Created
March 20, 2013 02:01
-
-
Save tomdalling/5201751 to your computer and use it in GitHub Desktop.
Some code from a state machine for Oddworld-style platform movement.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// Copyright 2012. All rights reserved. | |
// | |
static const int StandingHeight = 2; | |
static const int CrouchingHeight = 1; | |
class State { | |
public: | |
virtual void begin(PlayerController* p) {} | |
virtual void end(PlayerController* p) {} | |
virtual State* update(PlayerController* p, float secondsElapsed) { | |
return NULL; | |
} | |
protected: | |
bool isAirAt(PlayerController* p, int mapX, int mapY) const { | |
if(mapX < 0 || mapY < 0 || mapX >= (int)p->_map->width() || mapY >= (int)p->_map->height()) | |
return false; | |
return (p->_map->tileAt(mapX, mapY).type == TiledPlatformMap::Tile::Type_Air); | |
} | |
bool canMoveBy(PlayerController* p, int deltaX, unsigned height) const { | |
assert(height > 0); | |
Vec2<int> pos = p->_pos; | |
for(unsigned h = 0; h < height; ++h){ | |
if(!isAirAt(p, pos.x + deltaX, pos.y + h)){ | |
return false; | |
} | |
} | |
return true; | |
} | |
bool isAboveEdge(PlayerController* p) const { | |
if(p->_pos.y <= 0) | |
return false; | |
return (p->_map->tileAt(p->_pos.x, p->_pos.y - 1).type == TiledPlatformMap::Tile::Type_PlatformEdge); | |
} | |
bool isBelowEdge(PlayerController* p) const { | |
if(p->_pos.y >= (int)p->_map->height() - StandingHeight) | |
return false; | |
return (p->_map->tileAt(p->_pos.x, p->_pos.y + StandingHeight).type == TiledPlatformMap::Tile::Type_PlatformEdge); | |
} | |
bool doesEdgeRequireLeftFacing(PlayerController* p, int edgeDeltaY) const { | |
Vec2<int> edge = p->_pos + Vec2<int>(0, edgeDeltaY); | |
if(edge.x == 0) { | |
return false; | |
} else if(edge.x == p->_map->width() - 1) { | |
return true; | |
} else { | |
if(isAirAt(p, edge.x - 1, edge.y)){ | |
return false; | |
} else if(isAirAt(p, edge.x + 1, edge.y)) { | |
return true; | |
} else { | |
return true; //can face either direction | |
} | |
} | |
} | |
void fallPlayer(PlayerController* p) { | |
while(isAirAt(p, p->_pos.x, p->_pos.y - 1)){ | |
p->_pos.y -= 1; | |
} | |
} | |
bool controlIsPressed(PlayerController* p, Control c) { | |
return ((p->_pressedControls & c) == c); | |
} | |
}; | |
class StandingIdle : public State { | |
void begin(PlayerController* p) { | |
if(p->_facingLeft){ | |
p->_setAnim("anim:///anims/player-sil.anim.json"); | |
} else { | |
p->_setAnim("anim:///anims/player-sir.anim.json"); | |
} | |
} | |
State* update(PlayerController* p, float secondsElapsed) { | |
if(controlIsPressed(p, Control_Down)) | |
return &p->_s_StandToCrouch; | |
if(controlIsPressed(p, Control_Up) && isBelowEdge(p)){ | |
if(!doesEdgeRequireLeftFacing(p, StandingHeight) == !p->_facingLeft){ | |
return &p->_s_LedgeJumpUp; | |
} else { | |
return &p->_s_StandingTurn; | |
} | |
} | |
if((!p->_facingLeft && controlIsPressed(p, Control_Right) && canMoveBy(p, 1, StandingHeight)) || | |
(p->_facingLeft && controlIsPressed(p, Control_Left) && canMoveBy(p, -1, StandingHeight))) | |
{ | |
return &p->_s_StandingMove; | |
} | |
if((controlIsPressed(p, Control_Left) && !p->_facingLeft) || | |
(controlIsPressed(p, Control_Right) && p->_facingLeft)) | |
{ | |
return &p->_s_StandingTurn; | |
} | |
return NULL; | |
} | |
} _s_StandingIdle; | |
class CrouchingIdle : public State { | |
void begin(PlayerController* p) { | |
if(p->_facingLeft){ | |
p->_setAnim("anim:///anims/player-cil.anim.json"); | |
} else { | |
p->_setAnim("anim:///anims/player-cir.anim.json"); | |
} | |
} | |
State* update(PlayerController* p, float secondsElapsed) { | |
if(controlIsPressed(p, Control_Up) && canMoveBy(p, 0, StandingHeight)) | |
return &p->_s_CrouchToStand; | |
if(controlIsPressed(p, Control_Down) && isAboveEdge(p)){ | |
if(!doesEdgeRequireLeftFacing(p, -1) == !p->_facingLeft){ | |
return &p->_s_LedgeClimbDown; | |
} else { | |
return &p->_s_CrouchingTurn; | |
} | |
} | |
if((controlIsPressed(p, Control_Left) && !p->_facingLeft) || | |
(controlIsPressed(p, Control_Right) && p->_facingLeft)) | |
{ | |
return &p->_s_CrouchingTurn; | |
} | |
if((controlIsPressed(p, Control_Right) && canMoveBy(p, 1, CrouchingHeight)) || | |
(controlIsPressed(p, Control_Left) && canMoveBy(p, -1, CrouchingHeight))) | |
{ | |
return &p->_s_CrouchingMove; | |
} | |
return NULL; | |
} | |
} _s_CrouchingIdle; | |
class StandingMove : public State { | |
void begin(PlayerController* p) { | |
if(p->_facingLeft){ | |
p->_setAnim("anim:///anims/player-sml.anim.json"); | |
p->_pos.x -= 1; | |
} else { | |
p->_setAnim("anim:///anims/player-smr.anim.json"); | |
} | |
} | |
void end(PlayerController* p) { | |
if(!p->_facingLeft){ | |
p->_pos.x += 1; | |
} | |
fallPlayer(p); | |
} | |
State* update(PlayerController* p, float secondsElapsed) { | |
if(p->_anim.isFinished()){ | |
return &p->_s_StandingIdle; | |
} else { | |
return NULL; | |
} | |
} | |
} _s_StandingMove; | |
class CrouchingMove : public State { | |
void begin(PlayerController* p) { | |
if(p->_facingLeft){ | |
p->_setAnim("anim:///anims/player-cml.anim.json"); | |
p->_pos.x -= 1; | |
} else { | |
p->_setAnim("anim:///anims/player-cmr.anim.json"); | |
} | |
} | |
void end(PlayerController* p) { | |
if(!p->_facingLeft){ | |
p->_pos.x += 1; | |
} | |
fallPlayer(p); | |
} | |
State* update(PlayerController* p, float secondsElapsed) { | |
if(p->_anim.isFinished()){ | |
return &p->_s_CrouchingIdle; | |
} else { | |
return NULL; | |
} | |
} | |
} _s_CrouchingMove; | |
class CrouchingTurn : public State { | |
void begin(PlayerController* p) { | |
if(p->_facingLeft){ | |
p->_setAnim("anim:///anims/player-ctr.anim.json"); | |
} else { | |
p->_setAnim("anim:///anims/player-ctl.anim.json"); | |
} | |
} | |
void end(PlayerController* p) { | |
p->_facingLeft = !p->_facingLeft; | |
} | |
State* update(PlayerController* p, float secondsElapsed) { | |
if(p->_anim.isFinished()){ | |
return &p->_s_CrouchingIdle; | |
} else { | |
return NULL; | |
} | |
} | |
} _s_CrouchingTurn; | |
class StandingTurn : public State { | |
void begin(PlayerController* p) { | |
if(p->_facingLeft){ | |
p->_setAnim("anim:///anims/player-str.anim.json"); | |
} else { | |
p->_setAnim("anim:///anims/player-stl.anim.json"); | |
} | |
} | |
void end(PlayerController* p) { | |
p->_facingLeft = !p->_facingLeft; | |
} | |
State* update(PlayerController* p, float secondsElapsed) { | |
if(p->_anim.isFinished()){ | |
return &p->_s_StandingIdle; | |
} else { | |
return NULL; | |
} | |
} | |
} _s_StandingTurn; | |
class LedgeJumpUp : public State { | |
void begin(PlayerController* p) { | |
if(p->_facingLeft){ | |
p->_setAnim("anim:///anims/player-ljl.anim.json"); | |
} else { | |
p->_setAnim("anim:///anims/player-ljr.anim.json"); | |
} | |
} | |
State* update(PlayerController* p, float secondsElapsed) { | |
if(p->_anim.isFinished()){ | |
return &p->_s_LedgeIdle; | |
} else { | |
return NULL; | |
} | |
} | |
} _s_LedgeJumpUp; | |
class LedgeIdle : public State { | |
void begin(PlayerController* p) { | |
if(p->_facingLeft){ | |
p->_setAnim("anim:///anims/player-lil.anim.json"); | |
} else { | |
p->_setAnim("anim:///anims/player-lir.anim.json"); | |
} | |
} | |
State* update(PlayerController* p, float secondsElapsed) { | |
if(controlIsPressed(p, Control_Up)){ | |
return &p->_s_LedgeClimbUp; | |
} | |
if(controlIsPressed(p, Control_Down)){ | |
return &p->_s_LedgeJumpDown; | |
} | |
return NULL; | |
} | |
} _s_LedgeIdle; | |
class LedgeClimbUp : public State { | |
void begin(PlayerController* p) { | |
if(p->_facingLeft){ | |
p->_setAnim("anim:///anims/player-lcl.anim.json"); | |
} else { | |
p->_setAnim("anim:///anims/player-lcr.anim.json"); | |
} | |
} | |
void end(PlayerController* p) { | |
p->_pos.y += 3; | |
} | |
State* update(PlayerController* p, float secondsElapsed) { | |
if(p->_anim.isFinished()){ | |
return &p->_s_CrouchingIdle; | |
} else { | |
return NULL; | |
} | |
} | |
} _s_LedgeClimbUp; | |
class LedgeClimbDown : public State { | |
void begin(PlayerController* p) { | |
if(p->_facingLeft){ | |
p->_setAnim("anim:///anims/player-lll.anim.json"); | |
} else { | |
p->_setAnim("anim:///anims/player-llr.anim.json"); | |
} | |
p->_pos.y -= 3; | |
} | |
State* update(PlayerController* p, float secondsElapsed) { | |
if(p->_anim.isFinished()){ | |
return &p->_s_LedgeIdle; | |
} else { | |
return NULL; | |
} | |
} | |
} _s_LedgeClimbDown; | |
class LedgeJumpDown : public State { | |
void begin(PlayerController* p) { | |
if(p->_facingLeft){ | |
p->_setAnim("anim:///anims/player-ldl.anim.json"); | |
} else { | |
p->_setAnim("anim:///anims/player-ldr.anim.json"); | |
} | |
} | |
void end(PlayerController* p) { | |
fallPlayer(p); | |
} | |
State* update(PlayerController* p, float secondsElapsed) { | |
if(p->_anim.isFinished()){ | |
return &p->_s_StandingIdle; | |
} else { | |
return NULL; | |
} | |
} | |
} _s_LedgeJumpDown; | |
class StandToCrouch : public State { | |
void begin(PlayerController* p) { | |
if(p->_facingLeft){ | |
p->_setAnim("anim:///anims/player-s2cl.anim.json"); | |
} else { | |
p->_setAnim("anim:///anims/player-s2cr.anim.json"); | |
} | |
} | |
State* update(PlayerController* p, float secondsElapsed) { | |
if(p->_anim.isFinished()){ | |
return &p->_s_CrouchingIdle; | |
} else { | |
return NULL; | |
} | |
} | |
} _s_StandToCrouch; | |
class CrouchToStand : public State { | |
void begin(PlayerController* p) { | |
if(p->_facingLeft){ | |
p->_setAnim("anim:///anims/player-c2sl.anim.json"); | |
} else { | |
p->_setAnim("anim:///anims/player-c2sr.anim.json"); | |
} | |
} | |
State* update(PlayerController* p, float secondsElapsed) { | |
if(p->_anim.isFinished()){ | |
return &p->_s_StandingIdle; | |
} else { | |
return NULL; | |
} | |
} | |
} _s_CrouchToStand; | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment