/// <summary> /// Enter in ladder mode when user is in a ladder area and pressing up/down /// </summary> public override int WantsToUpdate(float delta) { bool onLadderState = character.IsOnState(States.Ladder); bool onLadderArea = character.IsOnArea(Areas.Ladder); // this means below my feet there is a ladder Ladder ladder = null; if (!onLadderArea && character.ladderBottom) { // deferred logic // if you EnableLadder now, you enter an area but there is no 'outisde-check' // so defer logic until also press down. onLadderArea = true; ladder = character.ladderBottom; } // in ladder state if (onLadderState) { return(priority); } bool enter = false; // enter ladder condition if (onLadderArea && !onLadderState && (ladder != null || character.ladder != null)) { float dir = input.GetAxisRawY(); // moving up, while inside a real LadderArea. if (dir > 0 && !(ladder ?? character.ladder).IsAtTop(character, character.feet)) { enter = true; } else if (dir < 0 && !(ladder ?? character.ladder).IsAtBottom(character, character.feet)) { // moving down: entering from the top if (ladder != null) { ladder.EnableLadder(character); // move the player inside the ladder. Vector3 pos = character.gameObject.transform.position; character.gameObject.transform.position = pos; enter = true; } else { // moving down: entering from the middle-bottom // check feet/bottom float bottomLadderY = character.ladder.GetBottom().y; float feetY = character.feet.y; // do not enter the ladder while on ground - pressing down if (feetY > bottomLadderY) { enter = true; } } } } if (enter) { return(priority); } return(0); }
/// <summary> /// Managed update called by UpdateManager /// Transform Input into platformer magic :) /// </summary> public virtual void PlatformerUpdate(float delta) { // before anything try to find if there is a ladder below // it's neccesary for ActionLadder&ActionCrounch RaycastHit2D hit = pc2d.DoFeetRay( pc2d.skinWidth * 2, Configuration.instance.laddersMask ); if (hit) { ladderBottom = hit.collider.gameObject.GetComponent <Ladder>(); if (ladderBottom == null) { Debug.LogWarning("Object with ladder mask but no Ladder Behaviour found", hit.collider.gameObject); } } else { ladderBottom = null; } // frozen -= delta; int prio = 0; int tmp; CharacterAction action = null; if (frozen < 0) { foreach (var i in actions) { tmp = i.WantsToUpdate(delta); if (tmp < 0) { i.PerformAction(Time.fixedDeltaTime); } else if (prio < tmp) { prio = tmp; action = i; } } } // reset / defaults pc2d.disableWorldCollisions = false; PostUpdateActions a = PostUpdateActions.WORLD_COLLISIONS | PostUpdateActions.APPLY_GRAVITY; if (action != null) { if (lastAction != action) { action.GainControl(delta); } action.PerformAction(Time.fixedDeltaTime); a = action.GetPostUpdateActions(); } if (Utils.biton((int)a, (int)PostUpdateActions.APPLY_GRAVITY)) { // TODO REVIEW x/y gravity... velocity.y += pc2d.gravity.y * delta; } if (!Utils.biton((int)a, (int)PostUpdateActions.WORLD_COLLISIONS)) { pc2d.disableWorldCollisions = true; } if (Mathf.Abs(velocity.x) < minVelocity) { velocity.x = 0.0f; } if (Mathf.Abs(velocity.y) < minVelocity) { velocity.y = 0.0f; } if (onBeforeMove != null) { onBeforeMove(this, delta); } movedLastFrame = pc2d.Move((velocity + worldVelocity) * delta, delta); if (onAfterMove != null) { onAfterMove(this, delta); } // this is meant to fix jump and falling hit something unexpected if (pc2d.collisions.above || pc2d.collisions.below) { velocity.y = 0; } if (pc2d.collisions.below) { fallingCD.Reset(); groundCD.Reset(); EnterStateGraceful(States.OnGround); } else { groundCD.Increment(); // give some margin if (groundCD.Ready()) { ExitStateGraceful(States.OnGround); } // falling but not wallsliding if (velocity.y < 0 && !IsOnState(States.WallSliding) && !IsOnState(States.Liquid) && !IsOnState(States.Rope)) { fallingCD.Increment(); if (fallingCD.Ready()) { EnterStateGraceful(States.Falling); } } } if (lastAction != null && lastAction != action) { lastAction.LoseControl(delta); } lastAction = action; }
public override void PerformAction(float delta) { // guard: something goes wrong! if (character.ladder == null) { character.ExitState(States.Ladder); return; } Ladder ladder = character.ladder; Vector2 in2d = input.GetAxisRaw(); if (character.IsOnArea(Areas.Ladder) && character.IsOnState(States.Ladder)) { // disable x movement character.velocity.x = 0; character.velocity.y = speed * in2d.y; } // TODO transition if (centering) { float ladderCenter = ladder.GetComponent <BoxCollider2D>().bounds.center.x; float characterX = character.GetCenter().x; if (Math.Abs(characterX - ladderCenter) < 0.05) { centering = false; character.velocity.x = 0; } else { // instant move to the center of the ladder! Mathf.SmoothDamp(characterX, ladderCenter, ref character.velocity.x, towardsTime, towardsSpeed, delta); } } if (ladder.topDismount && ladder.IsAtTop(character, character.feet) && in2d.y > 0) { // top dismount enabled and reached character.velocity = Vector2.zero; ladder.Dismount(character); } else if (ladder.bottomDismount && ladder.IsAtBottom(character, character.feet) && in2d.y < 0) { // bottom dismount enabled and reached character.velocity = Vector2.zero; ladder.Dismount(character); } else if (!ladder.topDismount && ladder.IsAboveTop(character, character.head) && in2d.y > 0) { // can't dismount (vine) don't let the head 'overflow' the ladder character.velocity = Vector2.zero; } else if (!ladder.bottomDismount && ladder.IsAtBottom(character, character.feet) && in2d.y < 0) { // can't dismount (vine) don't let the head 'overflow' the ladder // caveat: Vine cannot be near ground character.velocity = Vector2.zero; } character.SetFacing(in2d.x); // check for dismount conditions if (in2d.x != 0) { // do not allow to jump without telling the direction. // move up if you want it if (dismountJumping && input.IsActionHeld(actionJump.action)) { dismount.Reset(); character.ladder.Dismount(character); character.ladder = null; actionJump.Jump(new JumpConstant(character, jumpOff.Clone((int)character.faceDir) )); } else if (dismount.IncReady()) { character.velocity = Vector2.zero; character.ladder.Dismount(character); character.ladder = null; } } else { dismount.Reset(); } }
/// <summary> /// Managed update called by UpdateManager /// /// Call all actions ask them who 'WantsToUpdate'\n /// The highest priority action what want GainControl and PerformAction\n /// Given action give a list of things to do after using GetPostUpdateActions\n /// When all is done, fire events /// </summary> public virtual void PlatformerUpdate(float delta) { colBounds = bounds; // before anything try to find if there is a ladder below // it's neccesary for ActionLadder&ActionCrounch // this is not the right place... but where?! to be unique RaycastHit2D hit = FeetRay( skinWidth * 2, 1 << Configuration.instance.laddersMask ); if (hit) { ladderBottom = hit.collider.gameObject.GetComponent <Ladder>(); Assert.IsNotNull(ladderBottom, "GameObject at Ladders layer without Ladder MonoBehaviour at " + hit.collider.gameObject.GetFullName()); } else { ladderBottom = null; } // frozen -= delta; int prio = 0; int tmp; CharacterAction action = null; if (frozen < 0) { foreach (var i in actions) { tmp = i.WantsToUpdate(delta); if (tmp < 0) { i.PerformAction(Time.fixedDeltaTime); } else if (prio < tmp) { prio = tmp; action = i; } } } // reset / defaults disableWorldCollisions = false; PostUpdateActions a = PostUpdateActions.WORLD_COLLISIONS | PostUpdateActions.APPLY_GRAVITY; if (action != null) { if (lastAction != action) { action.GainControl(delta); } action.PerformAction(Time.fixedDeltaTime); a = action.GetPostUpdateActions(); } if (BitOn((int)a, (int)PostUpdateActions.APPLY_GRAVITY)) { // TODO REVIEW x/y gravity... velocity.y += gravity.y * delta; } if (!BitOn((int)a, (int)PostUpdateActions.WORLD_COLLISIONS)) { disableWorldCollisions = true; } if (Mathf.Abs(velocity.x) < minVelocity) { velocity.x = 0.0f; } if (Mathf.Abs(velocity.y) < minVelocity) { velocity.y = 0.0f; } if (onBeforeMove != null) { onBeforeMove(this, delta); } // check velocity don't exceed terminalVelocity // Limit X //velocity.x = Mathf.Min(velocity.x, terminalVelocity.x); //velocity.x = Mathf.Max(velocity.x, -terminalVelocity.x); // Limit Y but only freefall velocity.y = Mathf.Max(velocity.y, -terminalVelocity.y); movedLastFrame = Move((velocity + worldVelocity) * delta, delta); if (onAfterMove != null) { onAfterMove(this, delta); } // this is meant to fix jump and falling hit something unexpected if (collisions.above || collisions.below) { velocity.y = 0; } if (collisions.below) { fallingCD.Reset(); groundCD.Reset(); EnterStateGraceful(States.OnGround); } else { // give some margin if (groundCD.Ready()) { ExitStateGraceful(States.OnGround); } // falling but not wallsliding if (velocity.y < 0 && !IsOnState(States.WallSliding) && !IsOnState(States.Liquid) && !IsOnState(States.Rope)) { if (fallingCD.Ready()) { EnterStateGraceful(States.Falling); } } } if (lastAction != null && lastAction != action) { lastAction.LoseControl(delta); } lastAction = action; }