# HG changeset patch # User terom # Date 1228580225 0 # Node ID fbc5db6fce45c058ec2d93f4ef55be3b3da9812d # Parent 1c92222af6d3d6fb4b42095dd53ad33b0c7ea334 reorganize the weapons code and input handling code diff -r 1c92222af6d3 -r fbc5db6fce45 src/Graphics.cc --- a/src/Graphics.cc Sat Dec 06 14:36:37 2008 +0000 +++ b/src/Graphics.cc Sat Dec 06 16:17:05 2008 +0000 @@ -19,7 +19,7 @@ void Graphics::check_input (void) { LocalPlayer *player; - PlayerInput_Move input_move = 0; + PlayerInput input_mask = 0; // stop on escape if (keyboard.get_keycode(CL_KEY_ESCAPE)) { @@ -32,38 +32,19 @@ if ((player = state.getLocalPlayer()) == NULL) return; - // handle movement - if (keyboard.get_keycode(CL_KEY_LEFT)) - input_move |= INPUT_MOVE_LEFT; - - if (keyboard.get_keycode(CL_KEY_RIGHT)) - input_move |= INPUT_MOVE_RIGHT; - - if (keyboard.get_keycode(CL_KEY_UP)) - input_move |= INPUT_MOVE_UP; - - if (keyboard.get_keycode(CL_KEY_DOWN)) - input_move |= INPUT_MOVE_DOWN; - - if (keyboard.get_keycode(CL_KEY_RSHIFT)) - input_move |= INPUT_MOVE_JUMP; - + // dump debug info on stderr if (keyboard.get_keycode(CL_KEY_I)) - player->debugInfo(); + player->printDebugInfo(); - if (keyboard.get_keycode(CL_KEY_F)) { - input_move |= INPUT_SHOOT; + // check our keymap + for (InputKeymapEntry *e = getGlobalInputKeymap(); e->keycode && e->input; e++) { + if (keyboard.get_keycode(e->keycode)) + input_mask |= e->input; } - - if (keyboard.get_keycode(CL_KEY_D)) - input_move |= INPUT_CHANGE; - - if (keyboard.get_keycode(CL_KEY_M)) - input_move |= INPUT_MOVE_DIG; - - // apply movement if applicable - if (input_move) - player->handleMove(input_move); + + // apply input if applicable + if (input_mask) + player->handleInput(input_mask); } void Graphics::do_redraw (void) { diff -r 1c92222af6d3 -r fbc5db6fce45 src/Input.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Input.cc Sat Dec 06 16:17:05 2008 +0000 @@ -0,0 +1,20 @@ + +#define INPUT_CC + +#include "Input.hh" + +static InputKeymapEntry INPUT_KEYMAP[] = { + { CL_KEY_UP, INPUT_AIM_UP }, + { CL_KEY_DOWN, INPUT_AIM_DOWN }, + { CL_KEY_LEFT, INPUT_MOVE_LEFT }, + { CL_KEY_RIGHT, INPUT_MOVE_RIGHT }, + { CL_KEY_RSHIFT, INPUT_JUMP }, + { CL_KEY_M, INPUT_DIG }, + { CL_KEY_F, INPUT_SHOOT }, + { CL_KEY_D, INPUT_CHANGE }, + { 0, (_PlayerInput) 0 } +}; + +InputKeymapEntry* getGlobalInputKeymap (void) { + return INPUT_KEYMAP; +} diff -r 1c92222af6d3 -r fbc5db6fce45 src/Input.hh --- a/src/Input.hh Sat Dec 06 14:36:37 2008 +0000 +++ b/src/Input.hh Sat Dec 06 16:17:05 2008 +0000 @@ -1,22 +1,34 @@ #ifndef INPUT_HH #define INPUT_HH -const uint16_t INPUT_INTERVAL_MS = 20; +#include +#include -enum { - // XXX: aiming is not movement? - INPUT_MOVE_UP = 0x0001, - INPUT_MOVE_DOWN = 0x0002, +// const uint16_t INPUT_INTERVAL_MS = 20; + +enum _PlayerInput { + INPUT_AIM_UP = 0x0001, + INPUT_AIM_DOWN = 0x0002, INPUT_MOVE_LEFT = 0x0004, INPUT_MOVE_RIGHT = 0x0008, - INPUT_MOVE_JUMP = 0x0010, - INPUT_MOVE_DIG = 0x0020, + INPUT_JUMP = 0x0010, + INPUT_DIG = 0x0020, INPUT_SHOOT = 0x0040, INPUT_CHANGE = 0x0080, }; -typedef uint16_t PlayerInput_Move; +typedef uint16_t PlayerInput; + +struct InputKeymapEntry { + int keycode; + enum _PlayerInput input; +}; + +/* + * Get the global input keymap + */ +InputKeymapEntry* getGlobalInputKeymap (void); #endif diff -r 1c92222af6d3 -r fbc5db6fce45 src/Network/Client.cc --- a/src/Network/Client.cc Sat Dec 06 14:36:37 2008 +0000 +++ b/src/Network/Client.cc Sat Dec 06 16:17:05 2008 +0000 @@ -145,7 +145,7 @@ } -void NetworkClientLocalPlayer::handleMove (PlayerInput_Move input) { +void NetworkClientLocalPlayer::handleInput (PlayerInput input) { // always send move, in all cases NetworkPacket pkt; pkt.write_uint16(input); diff -r 1c92222af6d3 -r fbc5db6fce45 src/Network/Client.hh --- a/src/Network/Client.hh Sat Dec 06 14:36:37 2008 +0000 +++ b/src/Network/Client.hh Sat Dec 06 16:17:05 2008 +0000 @@ -59,7 +59,7 @@ public: NetworkClientLocalPlayer (NetworkClient &client, NetworkObject_Client *obj, Vector position); - virtual void handleMove (PlayerInput_Move input); + virtual void handleInput (PlayerInput input); }; class NetworkClientRemotePlayer : public NetworkClientPlayerHelper, public RemotePlayer { diff -r 1c92222af6d3 -r fbc5db6fce45 src/Network/Server.cc --- a/src/Network/Server.cc Sat Dec 06 14:36:37 2008 +0000 +++ b/src/Network/Server.cc Sat Dec 06 16:17:05 2008 +0000 @@ -111,12 +111,12 @@ return; } - PlayerInput_Move input = pkt.read_uint16(); + PlayerInput input = pkt.read_uint16(); Engine::log(INFO, "server_player.on_move") << "player=" << obj << ", old_pos=" << position << ", input=" << input; // apply input - handleMove(input); + handleInput(input); // send position update send_position_update(); diff -r 1c92222af6d3 -r fbc5db6fce45 src/PhysicsObject.cc --- a/src/PhysicsObject.cc Sat Dec 06 14:36:37 2008 +0000 +++ b/src/PhysicsObject.cc Sat Dec 06 16:17:05 2008 +0000 @@ -7,7 +7,7 @@ PhysicsObject::PhysicsObject (PhysicsWorld &world, float mass, Vector position, Vector velocity) : world(world), position(position), velocity(velocity), - mass(mass), inAir(true), aim(0), facingRight(true), reloadTimer(0) { + mass(mass), inAir(true), aim(0), facingRight(true) { // TODO: Is thir the right way to do this? //world.addPlayerObject(this); } @@ -64,7 +64,7 @@ float velocity = PLAYER_WALK_SPEED; float walkAmount = (velocity*dt)/1000; Vector reached = this->position; - while(walkAmount > 0 && !this->inAir) { + while (walkAmount > 0 && !this->inAir) { this->position = walk_one_step((1 < walkAmount ? 1 : walkAmount), right); walkAmount--; } @@ -112,12 +112,6 @@ * integration and collision detection. */ void PhysicsObject::updatePosition (TimeMS dt) { - - // Reloads weapon if not reloaded - reloadTimer -= dt; - if(reloadTimer < 0) - reloadTimer = 0; - // Add gravity to the force queue forceq.push(world.gravity); @@ -330,10 +324,6 @@ this->updatePosition(tick_length); } -bool PhysicsObject::canShoot() { - return this->reloadTimer <= 0; -} - void PhysicsObject::draw(CL_GraphicContext *gc) { CL_Quad player( (position+shape[0]).x, (position+shape[0]).y, diff -r 1c92222af6d3 -r fbc5db6fce45 src/PhysicsObject.hh --- a/src/PhysicsObject.hh Sat Dec 06 14:36:37 2008 +0000 +++ b/src/PhysicsObject.hh Sat Dec 06 16:17:05 2008 +0000 @@ -34,9 +34,6 @@ float aim; // Aim direction (half circle) bool facingRight; // Player facing - // - int reloadTimer; - PhysicsObject(PhysicsWorld &world, float mass, Vector position, Vector velocity); ~PhysicsObject() {} @@ -192,13 +189,7 @@ /** * Update object in physics simulation. */ - void tick(TimeMS tick_length); - - /** - * @return whether this PhysicsObject can shoot or not - * This is in PhysicsObject for larpa-like shots - */ - bool canShoot(); + virtual void tick (TimeMS tick_length); /** * Draw object diff -r 1c92222af6d3 -r fbc5db6fce45 src/Player.cc --- a/src/Player.cc Sat Dec 06 14:36:37 2008 +0000 +++ b/src/Player.cc Sat Dec 06 16:17:05 2008 +0000 @@ -22,7 +22,7 @@ // TODO: arsenal's size should be affected by some value // and weapons should be loaded from somewhere, not generated here for (int i = 0; i < 5; i++) { - arsenal.push_back(Weapon(10000, (5-i)*40+30, i*6+5, i*100+50, "asdf")); + arsenal.push_back(Weapon(state, 10000, (5 - i) * 40 + 30, i * 6 + 5, i * 100 + 50, "asdf")); } // build the player's shape @@ -52,100 +52,119 @@ } -void Player::debugInfo (void) { - Engine::log(DEBUG, "Player.debugInfo") << "In air: " << this->inAir; -} +void Player::handleShoot (Weapon &weapon) { + Vector unitVectorAim = (facingRight ? + Vector(std::cos(aim), -std::sin(aim)) : + Vector(-std::cos(aim), -std::sin(aim)) + ); + + // XXX: what does the PHYSICS_TICK_MS stuff mean? + float shotspeed = weapon.getVelocity() * PHYSICS_TICK_MS / 2; -/** - * shoots the selected weapon. - * TODO: selection and weapon information - */ -void LocalPlayer::shoot (void) { - // here should be somehow considered which projectile it is - if(!canShoot()) - return; - reloadTimer += getWeapon().reloadTime; - Vector unitVectorAim = facingRight ? Vector(std::cos(aim), -std::sin(aim)) : - Vector(-std::cos(aim), -std::sin(aim)); - float shotspeed = getWeapon().velocity*PHYSICS_TICK_MS/2; Vector shotRelativeVelocity = unitVectorAim * shotspeed; Vector shotVelocity = this->velocity + shotRelativeVelocity; - Vector shotPosition = this->position + unitVectorAim*10; - new Projectile(this->state, shotPosition, shotVelocity, true, getWeapon().explosionRadius); + Vector shotPosition = this->position + unitVectorAim * 10; + + weapon.shoot(shotPosition, shotVelocity); } -void LocalPlayer::handleMove (PlayerInput_Move input) { - float fx = 0; // Force in x-direction - float da = 0; // Crosshair angle - - // handle left/right - if ((input & INPUT_MOVE_LEFT) && (velocity.x > -PLAYER_MAX_SPEED)) - fx -= PLAYER_MOVE_FORCE; - - if ((input & INPUT_MOVE_RIGHT) && (velocity.x < PLAYER_MAX_SPEED)) - fx += PLAYER_MOVE_FORCE; +void Player::printDebugInfo (void) { + Engine::log(DEBUG, "layer.debug") << "In air: " << this->inAir; +} + +void Player::tick (TimeMS dt) { + // let PhysicsObject execute + PhysicsObject::tick(dt); + + // tick current weapon reload + getWeapon().tickReload(dt); +} - if (input & INPUT_MOVE_UP) - da += CROSSHAIR_ANGLE_SPEED; +void LocalPlayer::handleInput (PlayerInput input) { + // Movement force, vertical is always zero + Vector move_force = Vector(0, 0); - if (input & INPUT_MOVE_DOWN) - da -= CROSSHAIR_ANGLE_SPEED; + // Crosshair angle change + float aim_delta = 0; - if (input & INPUT_MOVE_JUMP) { - if ((input & INPUT_MOVE_LEFT)) + // handle movement left/right by applying a horizontal force, but limit the player's speed + if ((input & INPUT_MOVE_LEFT) && (velocity.x > -PLAYER_MAX_SPEED)) { + setFacing(false); + move_force.x -= PLAYER_MOVE_FORCE; + + } + + if ((input & INPUT_MOVE_RIGHT) && (velocity.x < PLAYER_MAX_SPEED)) { + setFacing(true); + move_force.x += PLAYER_MOVE_FORCE; + } + + // handle aim by creating a aim angle delta + if (input & INPUT_AIM_UP) + aim_delta += CROSSHAIR_ANGLE_SPEED; + + if (input & INPUT_AIM_DOWN) + aim_delta -= CROSSHAIR_ANGLE_SPEED; + + // handle jumping by invoking the jump method + // XXX: the direction should ideally be given using some other method + if (input & INPUT_JUMP) { + if (input & INPUT_MOVE_LEFT) jump(-1); - else if ((input & INPUT_MOVE_RIGHT)) + + else if (input & INPUT_MOVE_RIGHT) jump(1); + else jump(0); } + + // outsource digging to Player::handleDig, since this modifies the Terrain and Network needs to know + if (input & INPUT_DIG) { + handleDig(position, 15); - if (input & INPUT_MOVE_DIG) { // Should create Projectile which destroys ground, but also should be destroyed then, // but it doesn't. // But this now just segfaults // world.addObject(new Projectile(state, position, true)); - - handleDig(position, 15); } - + + // XXX: currently not network safe if (input & INPUT_CHANGE) { - if(changing) { + if (changing) { } else { changing = true; - selectedWeapon = (selectedWeapon+1)%arsenal.size(); + selectedWeapon = (selectedWeapon + 1) % arsenal.size(); Engine::log(DEBUG, "Player.cc:input ") << "changed weapon " << selectedWeapon; } } else { changing = false; } - - if (input & INPUT_SHOOT) { - this->shoot(); + + // validate shoot events, and then outsource to handleShoot so Network can intercept it + if (input & INPUT_SHOOT && getWeapon().canShoot()) { + this->handleShoot(getWeapon()); } - - + + // XXX: how should this be written? + if (move_force.x != 0) + animation_step = (animation_step + 1) % img_num_step; - // Player facing - if (fx < 0) setFacing(false); - else if (fx > 0) setFacing(true); - - if (fx != 0) animation_step = (animation_step+1)%img_num_step; + // apply aim delta + if (aim_delta) + changeAim(aim_delta); - - this->changeAim(da); // Move crosshair - - // Apply force - applyForce(Vector(fx, 0)); - + // apply force + if (!move_force.zero()) + applyForce(move_force); } Weapon& Player::getWeapon() { - return arsenal[selectedWeapon%arsenal.size()]; + return arsenal[selectedWeapon % arsenal.size()]; } -void Player::draw(CL_GraphicContext *gc) { +void Player::draw (CL_GraphicContext *gc) { int aim_img_idx = (int)((1 - (getAim()+KG_PI/2)/KG_PI)*img_num_aim); int step_img_idx = animation_step%img_num_step; @@ -154,7 +173,8 @@ skin_surface = CL_Surface(PLAYER_SKIN_PATH); skin_loaded = true; } - + + // XXX: this logic looks weird CL_Rectf destination(position.x - 4, position.y - 4, position.x + 5, position.y + 4); if (!getFacing()) { @@ -162,9 +182,14 @@ } skin_surface.draw_subpixel( - CL_Rectf(1+step_img_idx*img_width, aim_img_idx*img_height+1, 1+(1+step_img_idx)*img_width, (aim_img_idx+1)*img_height+1), - destination, - gc); + CL_Rectf( + 1 + step_img_idx * img_width, + aim_img_idx * img_height + 1, + 1 + (1 + step_img_idx) * img_width, + (aim_img_idx + 1) * img_height + 1 + ), + destination, gc + ); const uint16_t chlen = 10; uint16_t x = position.x; diff -r 1c92222af6d3 -r fbc5db6fce45 src/Player.hh --- a/src/Player.hh Sat Dec 06 14:36:37 2008 +0000 +++ b/src/Player.hh Sat Dec 06 16:17:05 2008 +0000 @@ -25,12 +25,25 @@ Player (void); Player (GameState &state, Vector position, bool visible); + // used by the network code to execute actions for players virtual void handleDig (Vector position, float radius); - + virtual void handleShoot (Weapon &weapon); + + /* + * + */ Weapon& getWeapon(); public: - void debugInfo (); + /* + * Prints random things via Engine::log + */ + void printDebugInfo (); + + /* + * Overrides PhysicsObject::tick to also advance game state + */ + virtual void tick (TimeMS dt); /* * Drawing requires the skin texture, which is loaded on-demand when draw is called @@ -42,8 +55,12 @@ class LocalPlayer : public virtual Player { public: - virtual void handleMove (PlayerInput_Move input); - void shoot (void); + /* + * Called to invoke some action on this player that we control, either by Graphics or NetworkServer. + * + * NetworkClientLocalPlayer overrides this to send the input to the server, which then handles it + */ + virtual void handleInput (PlayerInput input); }; class RemotePlayer : public virtual Player { diff -r 1c92222af6d3 -r fbc5db6fce45 src/Vector.hh --- a/src/Vector.hh Sat Dec 06 14:36:37 2008 +0000 +++ b/src/Vector.hh Sat Dec 06 16:17:05 2008 +0000 @@ -76,6 +76,12 @@ _Vector roundToInt() const { return _Vector((int)(x), (int)(y)); } + + // test Vectors as booleans + // XXX: comparing floats against zero... is a bad idea? + bool zero(void) const { + return x == 0 && y == 0; + } }; // Unary operators diff -r 1c92222af6d3 -r fbc5db6fce45 src/Weapon.cc --- a/src/Weapon.cc Sat Dec 06 14:36:37 2008 +0000 +++ b/src/Weapon.cc Sat Dec 06 16:17:05 2008 +0000 @@ -1,9 +1,40 @@ #include "Weapon.hh" -Weapon::Weapon(TickCount age, float velocity, float explosionRadius, int reloadTime, std::string name) - : age(age), velocity(velocity), explosionRadius(explosionRadius), reloadTime(reloadTime), name(name) { +Weapon::Weapon(GameState &st, TickCount age, float velocity, float explosionRadius, int reloadTime, std::string name) : + st(st), age(age), velocity(velocity), explosionRadius(explosionRadius), reloadTime(reloadTime), name(name), reloadTimer(0) +{ + } -Weapon::Weapon(const Weapon& orig) - : age(orig.age), velocity(orig.velocity), explosionRadius(orig.explosionRadius), reloadTime(orig.reloadTime), name(orig.name) { +Weapon::Weapon(const Weapon& orig) : + st(orig.st), age(orig.age), velocity(orig.velocity), explosionRadius(orig.explosionRadius), reloadTime(orig.reloadTime), name(orig.name) +{ + } + +Weapon& Weapon::operator= (const Weapon& orig) { + st = orig.st; + age = orig.age; + velocity = orig.velocity; + explosionRadius = orig.explosionRadius; + reloadTime = orig.reloadTime; + name = orig.name; +} + +void Weapon::tickReload (TimeMS dt) { + reloadTimer -= dt; + if (reloadTimer < 0) + reloadTimer = 0; +} + +bool Weapon::canShoot() { + return (reloadTimer == 0); +} + +Projectile* Weapon::shoot (Vector position, Vector velocity) { + // set the reload timer + reloadTimer = reloadTime; + + return new Projectile(st, position, velocity, true, explosionRadius); +} + diff -r 1c92222af6d3 -r fbc5db6fce45 src/Weapon.hh --- a/src/Weapon.hh Sat Dec 06 14:36:37 2008 +0000 +++ b/src/Weapon.hh Sat Dec 06 16:17:05 2008 +0000 @@ -1,35 +1,45 @@ #ifndef WEAPON_HH #define WEAPON_HH +// forward-declare +class Weapon; + +#include "GameState.hh" #include "Timer.hh" #include class Weapon { -public: -/* const TickCount age; - const float velocity; - const float explosionRadius; - const int reloadTime; //in ms - - const int clipSize; - const bool visible; - - const std::string name; -*/ - - TickCount age; +protected: + GameState &st; + std::string name; float velocity; float explosionRadius; int reloadTime; //in ms int clipSize; - bool visible; - std::string name; + bool visible; + TickCount age; + int reloadTimer; - Weapon(TickCount age, float velocity, float explosionRadius, int reloadTime, std::string name); +public: + Weapon (GameState &st, TickCount age, float velocity, float explosionRadius, int reloadTime, std::string name); + Weapon (const Weapon& orig); + Weapon& operator= (const Weapon& orig); + + // advance the reload timer + void tickReload (TimeMS dt); + + // can the weapon be fired (not reloading, have a clip, etc) + bool canShoot (void); + + // get the weapon projectile velocity + float getVelocity (void) { return velocity; } - Weapon(const Weapon& orig); + /* + * Fire the Weapon! Position and velocity are the initial position and velocity for the resulting projectile + */ + Projectile* shoot (Vector position, Vector velocity); }; #endif