reorganize the weapons code and input handling code
authorterom
Sat, 06 Dec 2008 16:17:05 +0000
changeset 221 fbc5db6fce45
parent 220 1c92222af6d3
child 222 293ddf4c067d
reorganize the weapons code and input handling code
src/Graphics.cc
src/Input.cc
src/Input.hh
src/Network/Client.cc
src/Network/Client.hh
src/Network/Server.cc
src/PhysicsObject.cc
src/PhysicsObject.hh
src/Player.cc
src/Player.hh
src/Vector.hh
src/Weapon.cc
src/Weapon.hh
--- 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) {
--- /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;
+}
--- 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 <stdint.h>
+#include <ClanLib/Display/keys.h>
 
-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
--- 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);
--- 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 {
--- 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();
--- 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,
--- 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
--- 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;
--- 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 {
--- 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
--- 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);
+}
+
--- 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 <string>
 
 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