Merge from at r31:36 no-netsession
authorterom
Tue, 18 Nov 2008 22:58:50 +0000
branchno-netsession
changeset 35 e21cfda0edde
parent 34 1ea6554d703e
child 36 785d220fc6b7
Merge from at r31:36
build/mkcmake.sh
plan/diagram.dot
plan/test.ps
src/proto2/Application.cc
src/proto2/Dimension.cc
src/proto2/Dimension.hh
src/proto2/Engine.cc
src/proto2/Engine.hh
src/proto2/GameState.cc
src/proto2/GameState.hh
src/proto2/Graphics.cc
src/proto2/Graphics.hh
src/proto2/Input.hh
src/proto2/Network.cc
src/proto2/Network.hh
src/proto2/NetworkClient.cc
src/proto2/NetworkClient.hh
src/proto2/NetworkServer.cc
src/proto2/Physics.cc
src/proto2/Physics.hh
src/proto2/SinglePlayer.hh
src/proto2/Vector.hh
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/build/mkcmake.sh	Tue Nov 18 22:58:50 2008 +0000
@@ -0,0 +1,4 @@
+#!/bin/sh
+
+cmake ../ -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX=/tmp
+
--- a/plan/diagram.dot	Mon Nov 10 21:58:38 2008 +0000
+++ b/plan/diagram.dot	Tue Nov 18 22:58:50 2008 +0000
@@ -19,7 +19,7 @@
 
     subgraph cluster1 {
         label = "Game Engine";
-	{rank=min; gs; physics; }
+	{rank=min; gs; physics;}
 	gs;
 	physics;
 	color = black;
--- a/plan/test.ps	Mon Nov 10 21:58:38 2008 +0000
+++ b/plan/test.ps	Tue Nov 18 22:58:50 2008 +0000
@@ -410,3 +410,4 @@
 end
 restore
 %%EOF
+
--- a/src/proto2/Application.cc	Mon Nov 10 21:58:38 2008 +0000
+++ b/src/proto2/Application.cc	Tue Nov 18 22:58:50 2008 +0000
@@ -78,9 +78,9 @@
                 }
             }
             
-            // check for valid combinations of arugments
-            if (!(arg_server xor !arg_connect.empty()))
-                throw ArgumentError("must supply *exactly* one of --server/--client");
+            // check for invalid combinations of arugments
+            if (arg_server and !arg_connect.empty())
+                throw ArgumentError("cannot be both server and client");
         }
 
     public:
@@ -102,15 +102,16 @@
                 if (arg_graphics)
                     engine.setupGraphics();
 
-                // setup either network server or client
+                // setup either network server, client or singleplayer
                 if (arg_server) {
                     engine.setupNetworkServer(arg_port);
 
                 } else if (!arg_connect.empty()) {
                     engine.setupNetworkClient(arg_connect, arg_port);
                 
-                } else
-                    assert(false);
+                } else {
+                    engine.setupSinglePlayer();
+                }
 
                 // run the main loop
                 engine.run();
--- a/src/proto2/Dimension.cc	Mon Nov 10 21:58:38 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,14 +0,0 @@
-#include "Dimension.hh"
-
-std::ostream& operator<< (std::ostream &s, const Coordinate &c) {
-    s << "(" << c.x << ", " << c.y << ")";
-
-    return s;
-}
-
-std::ostream& operator<< (std::ostream &s, const PositionDelta &c) {
-    s << "(" << c.dx << ", " << c.dy << ")";
-
-    return s;
-}
-
--- a/src/proto2/Dimension.hh	Mon Nov 10 21:58:38 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,49 +0,0 @@
-#ifndef DIMENSION_HH
-#define DIMENSION_HH
-
-#include <iostream>
-
-class Dimension {
-    public:
-        uint32_t w;
-        uint32_t h;
-
-        Dimension (uint32_t w, uint32_t h) : w(w), h(h) { }
-};
-
-class PositionDelta {
-    public:
-        int32_t dx;
-        int32_t dy;
-
-        PositionDelta (int32_t dx, int32_t dy) : dx(dx), dy(dy) { }
-};
-
-class Coordinate {
-    public:
-        uint32_t x;
-        uint32_t y;
-
-        Coordinate (uint32_t x, uint32_t y) : x(x), y(y) { }
-
-        Coordinate &operator+= (const PositionDelta &d) {
-            this->x += d.dx;
-            this->y += d.dy;
-
-            return *this;
-        }
-
-        Coordinate operator+ (const PositionDelta &d) {
-            return Coordinate(x + d.dx, y + d.dy);
-        }
-
-        // Scale the coordinate so that it matches the pixel resolution
-        uint32_t scaledX() { return x; }
-
-        uint32_t scaledY() { return y; }
-};
-
-std::ostream& operator<< (std::ostream &s, const Coordinate &c);
-std::ostream& operator<< (std::ostream &s, const PositionDelta &c);
-
-#endif
--- a/src/proto2/Engine.cc	Mon Nov 10 21:58:38 2008 +0000
+++ b/src/proto2/Engine.cc	Tue Nov 18 22:58:50 2008 +0000
@@ -2,6 +2,7 @@
 #include "Engine.hh"
 #include "NetworkServer.hh"
 #include "NetworkClient.hh"
+#include "SinglePlayer.hh"
 
 #include <iostream>
 
@@ -27,6 +28,14 @@
     net_client = new NetworkClient(game_state, connect_addr);
 }
 
+void Engine::setupSinglePlayer (void) {
+    // create player directly
+ 	LocalPlayer* lp = new SinglePlayer(game_state);
+
+    // add to gamestate
+	game_state.newLocalPlayer(lp);
+}
+
 void Engine::stop (void) {
     is_running = false;
 }
@@ -39,7 +48,7 @@
         // if I can't find some better way to do this in ClanLib by next thursday, then it f*%!ing sucks
         // ideally, we should be able to have a main loop that does timed waits on I/O, fufilling some set of timers
         // but as far as I can tell, ClanLib doesn't have anything like that
-        CL_System::sleep(20);
+        CL_System::sleep(10);
     }
 }
 
--- a/src/proto2/Engine.hh	Mon Nov 10 21:58:38 2008 +0000
+++ b/src/proto2/Engine.hh	Tue Nov 18 22:58:50 2008 +0000
@@ -37,6 +37,7 @@
         // setting up both of these will lead to odd behaviour :)
         void setupNetworkServer (const std::string &listen_port);
         void setupNetworkClient (const std::string &connect_host, const std::string &connect_port);
+		void setupSinglePlayer (void);
         
         // run the main loop
         void run (void);
--- a/src/proto2/GameState.cc	Mon Nov 10 21:58:38 2008 +0000
+++ b/src/proto2/GameState.cc	Tue Nov 18 22:58:50 2008 +0000
@@ -1,18 +1,24 @@
 
 #include "GameState.hh"
 
-bool Player::updatePosition (Coordinate p) {
-    if (!state.isValidCoordinate(p)) {
-        // out-of-bounds
-        return false;
+void LocalPlayer::handleMove (PlayerInput_Move input) {
+    float fx = 0, fy = 0;
 
-    } else {
-        // valid
-        position = p;
+    // handle up/down/left/right
+    if (input & INPUT_MOVE_UP)
+            fy -= PLAYER_MOVE_FORCE;
+    
+    if (input & INPUT_MOVE_DOWN)
+            fy += PLAYER_MOVE_FORCE;
 
-        return true;
+    if (input & INPUT_MOVE_LEFT)
+            fx -= PLAYER_MOVE_FORCE;
+
+    if (input & INPUT_MOVE_RIGHT)
+            fx += PLAYER_MOVE_FORCE;
+    
+    if (fx || fy) {
+        // apply force
+        applyForce(Vector(fx, fy), INPUT_INTERVAL_MS);
     }
 }
-
-
-
--- a/src/proto2/GameState.hh	Mon Nov 10 21:58:38 2008 +0000
+++ b/src/proto2/GameState.hh	Tue Nov 18 22:58:50 2008 +0000
@@ -1,88 +1,60 @@
 #ifndef GAMESTATE_HH
 #define GAMESTATE_HH
 
-#include "Dimension.hh"
+#include "Physics.hh"
+#include "Input.hh"
 
 #include <list>
 #include <stdexcept>
 
-enum PlayerType {
-    PLAYER_LOCAL,
-    PLAYER_REMOTE
-};
-
-#define PLAYER_DIM_W 10
-#define PLAYER_DIM_H 10
-#define MAP_DIM_W 800
-#define MAP_DIM_H 640
+// in meters/kg
+const float MAP_WIDTH = 100.0;
+const float MAP_HEIGHT = 100.0;
+const float MAP_GRAVITY = 9.81;
+const float PLAYER_MASS = 10.0;
+const float PLAYER_MOVE_FORCE = 500.0;
+const float PLAYER_INITIAL_X = 50.0;
+const float PLAYER_INITIAL_Y = 40.0;
 
 // forward-declare GameState
 class GameState;
 
-class Player {
+class Player : public PhysicsObject {
     protected:
-        Coordinate position;
-
         GameState &state;
+        bool visible;
 
     public:
 
-        Player(GameState &state, Coordinate c, bool visible) : position(c), state(state), dimensions(PLAYER_DIM_W, PLAYER_DIM_H), visible(visible) {}
-
-        PlayerType type;
-        Dimension dimensions;
-        bool visible;
-
-        Coordinate getPosition (void) const {
-            return position;
-        }
-    
-    protected:
-        /*
-         * Update position to the given value.
-         *
-         * Returns true if valid move (not out of bounds), false otherwise (doesn't change position)
-         */
-        bool updatePosition (Coordinate p);
+        Player(GameState &state, Vector position, bool visible) : 
+            PhysicsObject((PhysicsWorld &) state, PLAYER_MASS, position, Vector(0, 0)), state(state), visible(visible) { }
 
 };
 
 class LocalPlayer : public Player {
     protected:
-        LocalPlayer (GameState &state, Coordinate c, bool visible) : Player(state, c, visible) { }
+        LocalPlayer (GameState &state, Vector pos, bool visible) : Player(state, pos, visible) { }
     
     public:
-        virtual bool move (PositionDelta d) {
-            return updatePosition(position + d);
-        }
+        virtual void handleMove (PlayerInput_Move input);
 };
 
 class RemotePlayer : public Player {
     protected:
-        RemotePlayer (GameState &state, Coordinate c, bool visible) : Player(state, c, visible) { }
-
+        RemotePlayer (GameState &state, Vector pos, bool visible) : Player(state, pos, visible) { }
 };
 
-class GameState {
+class GameState : public PhysicsWorld {
     public:
-        Dimension map_dimensions;
         std::list<Player*> player_list;
 
         // only one local player is supported
         LocalPlayer *local_player;
 
-        GameState (void) : map_dimensions(MAP_DIM_W, MAP_DIM_H), local_player(NULL) {
+        GameState (void) : PhysicsWorld(Vector(0, MAP_GRAVITY), Vector(MAP_WIDTH, MAP_HEIGHT)), local_player(NULL) {
 
         }
-
-        /*
-         * Check if the given coordinate is valid
-         */
-        bool isValidCoordinate (const Coordinate &p) {
-            // unsigned...
-            return !(p.x > map_dimensions.w || p.y > map_dimensions.h);
-        }
-        
+       
         /*
          * This will return NULL if we don't have a local player - yet
          */
--- a/src/proto2/Graphics.cc	Mon Nov 10 21:58:38 2008 +0000
+++ b/src/proto2/Graphics.cc	Tue Nov 18 22:58:50 2008 +0000
@@ -5,7 +5,7 @@
     engine(engine), 
     state(state), 
     update_timer(GRAPHICS_UPDATE_INTERVAL_MS),
-    win(GRAPHICS_WINDOW_TITLE, MAP_DIM_W, MAP_DIM_H), 
+    win(GRAPHICS_WINDOW_TITLE, GRAPHICS_RESOLUTION_WIDTH, GRAPHICS_RESOLUTION_HEIGHT),
     keyboard(win.get_ic()->get_keyboard()) {
     
     // connect timer signal
@@ -17,7 +17,7 @@
 
 void Graphics::check_input (void) {
     LocalPlayer *player;
-    int dx = 0, dy = 0;
+    PlayerInput_Move input_move = 0;
     
     // stop on escape
     if (keyboard.get_keycode(CL_KEY_ESCAPE)) {
@@ -32,20 +32,20 @@
     
     // handle up/down/left/right
     if (keyboard.get_keycode(CL_KEY_UP))
-            dy -= 3;
+            input_move |= INPUT_MOVE_UP;
 
     if (keyboard.get_keycode(CL_KEY_DOWN))
-            dy += 3;
+            input_move |= INPUT_MOVE_DOWN;
 
     if (keyboard.get_keycode(CL_KEY_LEFT))
-            dx -= 3;
+            input_move |= INPUT_MOVE_LEFT;
 
     if (keyboard.get_keycode(CL_KEY_RIGHT))
-            dx += 3;
+            input_move |= INPUT_MOVE_RIGHT;
     
     // apply movement if applicable
-    if (dx || dy)
-        player->move(PositionDelta(dx, dy));
+    if (input_move)
+        player->handleMove(input_move);
 }
 
 void Graphics::do_redraw (void) {
@@ -54,6 +54,9 @@
     // white background
     gc->clear(CL_Color::white);
 
+    const float factorX = GRAPHICS_RESOLUTION_WIDTH / MAP_WIDTH;
+    const float factorY = GRAPHICS_RESOLUTION_HEIGHT / MAP_HEIGHT;
+
     // draw players
     for (std::list<Player*>::iterator it = state.player_list.begin(); it != state.player_list.end(); it++) {
         Player *p = *it;
@@ -61,8 +64,8 @@
         // draw square
         gc->fill_rect(
             CL_Rect(
-                p->getPosition().x - 5, p->getPosition().y - 5,
-                p->getPosition().x + 5, p->getPosition().y + 5
+                p->getPosition().x * factorX - 5, p->getPosition().y * factorY - 5,
+                p->getPosition().x * factorX + 5, p->getPosition().y * factorY + 5
             ), CL_Color::black
         );
     }
--- a/src/proto2/Graphics.hh	Mon Nov 10 21:58:38 2008 +0000
+++ b/src/proto2/Graphics.hh	Tue Nov 18 22:58:50 2008 +0000
@@ -11,8 +11,10 @@
 #include <ClanLib/gl.h>
 #include <ClanLib/display.h>
 
-#define GRAPHICS_WINDOW_TITLE "Kisna Glista"
-#define GRAPHICS_UPDATE_INTERVAL_MS 100
+const std::string GRAPHICS_WINDOW_TITLE = "Kisna Glista";
+const uint32_t GRAPHICS_RESOLUTION_WIDTH = 800;
+const uint32_t GRAPHICS_RESOLUTION_HEIGHT = 600;
+const uint16_t GRAPHICS_UPDATE_INTERVAL_MS = 20;
 
 class Graphics {
     private:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/proto2/Input.hh	Tue Nov 18 22:58:50 2008 +0000
@@ -0,0 +1,15 @@
+#ifndef INPUT_HH
+#define INPUT_HH
+
+const uint16_t INPUT_INTERVAL_MS = 20;
+
+enum {
+    INPUT_MOVE_UP     = 0x01,
+    INPUT_MOVE_DOWN   = 0x02,
+    INPUT_MOVE_LEFT   = 0x04,
+    INPUT_MOVE_RIGHT  = 0x08,
+};
+
+typedef uint16_t PlayerInput_Move;
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/proto2/Network.cc	Tue Nov 18 22:58:50 2008 +0000
@@ -0,0 +1,41 @@
+
+#include "Network.hh"
+#include "Engine.hh"
+
+void writeVector (CL_NetPacket &pkt, const Vector &vec) {
+    pkt.output.write_float32(vec.x);
+    pkt.output.write_float32(vec.y);
+
+/*
+    int32_t x = vec.x * COORDINATE_MAX / MAP_WIDTH;
+    int32_t y = vec.y * COORDINATE_MAX / MAP_HEIGHT;
+    
+    Engine::log(DEBUG, "network.write_vector") 
+        << "vec=" << vec << " -> x=" << x << ", y=" << y;
+
+    pkt.output.write_int32(x);
+    pkt.output.write_int32(y);
+*/    
+}
+
+Vector readVector (CL_NetPacket &pkt) {
+    float fx = pkt.input.read_float32();
+    float fy = pkt.input.read_float32();
+
+    Vector vec(fx, fy);
+
+/*    
+    int32_t x = pkt.input.read_int32();
+    int32_t y = pkt.input.read_int32();
+
+    float fx = x * MAP_WIDTH / COORDINATE_MAX;
+    float fy = y * MAP_HEIGHT / COORDINATE_MAX;
+    
+    Vector vec(fx, fy);
+
+    Engine::log(DEBUG, "network.read_vector") << "x=" << x << ", y=" << y << " -> " << vec;
+*/    
+
+    return vec;
+}
+
--- a/src/proto2/Network.hh	Mon Nov 10 21:58:38 2008 +0000
+++ b/src/proto2/Network.hh	Tue Nov 18 22:58:50 2008 +0000
@@ -6,6 +6,8 @@
 
 #include <ClanLib/network.h>
 
+const int32_t COORDINATE_MAX = 1 << 30;
+
 class NetworkCore {
     protected:
         GameState &state;
@@ -14,24 +16,28 @@
 
         // constructor
         NetworkCore (GameState &state) : state(state) { }
+
+
 };
 
+// XXX: util methods
+void writeVector (CL_NetPacket &pkt, const Vector &vec);
+Vector readVector (CL_NetPacket &pkt);
+
 enum NetworkMessage {
     NETMSG_PACKET_INVALID   = 0x00,
 
     /*
      * You have joined the game:
      *
-     *  uint32_t x
-     *  uint32_t y
+     *  Vector      initial_position
      */
     NETMSG_SERVER_HELLO = 0x0100,
 
     /*
      * New client has connected to server:
-     *
-     *  uint32_t x
-     *  uint32_t y
+     *  
+     *  Vector      initial_position
      */
     NETMSG_PLAYER_JOIN  = 0x0101,
 
@@ -44,24 +50,23 @@
     /*
      * Client has moved
      *
-     *  int32_t dx
-     *  int32_t dy
+     *  Vector      impulse_force
+     *  uint16_t    impulse_ms
      */
     NETMSG_CLIENT_MOVE  = 0x0201,
     
     /*
      * Initial player info
      *
-     *  uint32_t x
-     *  uint32_t y
+     *  Vector      initial_position
      */
     NETMSG_PLAYER_INFO  = 0x0300,
 
     /*
      * Player position update
      *
-     *  uint32_t x
-     *  uint32_t y
+     * Vector   position
+     * Vector   velocity
      */
     NETMSG_PLAYER_POSITION  = 0x0301,
 };
--- a/src/proto2/NetworkClient.cc	Mon Nov 10 21:58:38 2008 +0000
+++ b/src/proto2/NetworkClient.cc	Tue Nov 18 22:58:50 2008 +0000
@@ -38,15 +38,12 @@
         
 void NetworkClient::on_server_hello (CL_NetObject_Client &obj, CL_NetPacket &pkt) {
     // read the packet
-    uint32_t x = pkt.input.read_uint32();
-    uint32_t y = pkt.input.read_uint32();
-
-    Coordinate initial_position(x, y);
+    Vector position = readVector(pkt);
     
-    Engine::log(INFO, "client.on_server_hello") << "obj=" << obj << ", pos=" << initial_position;
+    Engine::log(INFO, "client.on_server_hello") << "obj=" << obj << ", pos=" << position;
 
     // create the LocalPlayer object
-    NetworkClientLocalPlayer *player = new NetworkClientLocalPlayer(*this, obj, initial_position);
+    NetworkClientLocalPlayer *player = new NetworkClientLocalPlayer(*this, obj, position);
 
     // inform state
     state.newLocalPlayer(player);
@@ -54,15 +51,12 @@
         
 void NetworkClient::on_player_info (CL_NetObject_Client &obj, CL_NetPacket &pkt) {
     // read the packet
-    uint32_t x = pkt.input.read_uint32();
-    uint32_t y = pkt.input.read_uint32();
+    Vector position = readVector(pkt);
     
-    Coordinate initial_position(x, y);
-    
-    Engine::log(INFO, "client.on_player_info") << "obj=" << obj << ", pos=" << initial_position;
+    Engine::log(INFO, "client.on_player_info") << "obj=" << obj << ", pos=" << position;
 
     // create the LocalPlayer object
-    NetworkClientRemotePlayer *player = new NetworkClientRemotePlayer(*this, obj, initial_position);
+    NetworkClientRemotePlayer *player = new NetworkClientRemotePlayer(*this, obj, position);
 
     // inform state
     state.newRemotePlayer(player);
@@ -71,15 +65,12 @@
         
 void NetworkClient::on_player_join (CL_NetObject_Client &obj, CL_NetPacket &pkt) {
     // read the packet
-    uint32_t x = pkt.input.read_uint32();
-    uint32_t y = pkt.input.read_uint32();
+    Vector position = readVector(pkt);
     
-    Coordinate initial_position(x, y);
-    
-    Engine::log(INFO, "client.on_player_join") << "obj=" << obj << ", pos=" << initial_position;
+    Engine::log(INFO, "client.on_player_join") << "obj=" << obj << ", pos=" << position;
     
     // create the RemotePlayer object
-    NetworkClientRemotePlayer *player = new NetworkClientRemotePlayer(*this, obj, initial_position);
+    NetworkClientRemotePlayer *player = new NetworkClientRemotePlayer(*this, obj, position);
 
     // inform state
     state.newRemotePlayer(player);
@@ -94,38 +85,36 @@
     //  delete player;
 }
 
-NetworkClientLocalPlayer::NetworkClientLocalPlayer (NetworkClient &client, CL_NetObject_Client &obj, Coordinate initial_position) :
-    LocalPlayer(client.state, initial_position, true), client(client), obj(obj) {
+NetworkClientLocalPlayer::NetworkClientLocalPlayer (NetworkClient &client, CL_NetObject_Client &obj, Vector position) :
+    LocalPlayer(client.state, position, true), client(client), obj(obj) {
     
     // receive messages
     slots.connect(obj.sig_received_message(NETMSG_PLAYER_POSITION), this, &NetworkClientLocalPlayer::on_position);
 }
         
-bool NetworkClientLocalPlayer::move (PositionDelta d) {
+void NetworkClientLocalPlayer::applyForce (Vector force, uint16_t dt) {
     // always send move, in all cases
     CL_NetPacket pkt;
-    pkt.output.write_int32(d.dx);
-    pkt.output.write_int32(d.dy);
+    writeVector(pkt, force);
+    pkt.output.write_uint16(dt);
 
     obj.send(NETMSG_CLIENT_MOVE, pkt, false);
-
-    // return validity
-    return LocalPlayer::move(d);
+    
+    // do not handle locally
 }
         
 void NetworkClientLocalPlayer::on_position (CL_NetPacket &pkt) {
-    uint32_t x = pkt.input.read_uint32();
-    uint32_t y = pkt.input.read_uint32();
+    Vector position = readVector(pkt);
+    Vector velocity = readVector(pkt);
 
-    Coordinate pos (x, y);
-
-    Engine::log(INFO, "client_player.on_position") << "obj=" << obj << ", pos=" << pos;
+    Engine::log(INFO, "client_player.on_position") << "obj=" << obj << ", position=" << position << ", velocity=" << velocity;
     
-    assert(updatePosition(pos));
+    // just update... 
+    updatePhysics(position, velocity);
 }
         
-NetworkClientRemotePlayer::NetworkClientRemotePlayer (NetworkClient &client, CL_NetObject_Client &obj, Coordinate initial_position) :
-    RemotePlayer(client.state, initial_position, true), client(client), obj(obj) {
+NetworkClientRemotePlayer::NetworkClientRemotePlayer (NetworkClient &client, CL_NetObject_Client &obj, Vector position) :
+    RemotePlayer(client.state, position, true), client(client), obj(obj) {
     
     // receive messages
     slots.connect(obj.sig_received_message(NETMSG_PLAYER_POSITION), this, &NetworkClientRemotePlayer::on_position);
@@ -133,14 +122,13 @@
 }
 
 void NetworkClientRemotePlayer::on_position (CL_NetPacket &pkt) {
-    uint32_t x = pkt.input.read_uint32();
-    uint32_t y = pkt.input.read_uint32();
+    Vector position = readVector(pkt);
+    Vector velocity = readVector(pkt);
+
+    Engine::log(INFO, "client_player.on_position") << "obj=" << obj << ", position=" << position << ", velocity=" << velocity;
     
-    Coordinate pos (x, y);
-
-    Engine::log(INFO, "client_player.on_position") << "obj=" << obj << ", pos=" << pos;
-    
-    assert(updatePosition(pos));
+    // just update... 
+    updatePhysics(position, velocity);
 }
 
 void NetworkClientRemotePlayer::on_quit (CL_NetPacket &pkt) {
--- a/src/proto2/NetworkClient.hh	Mon Nov 10 21:58:38 2008 +0000
+++ b/src/proto2/NetworkClient.hh	Tue Nov 18 22:58:50 2008 +0000
@@ -38,9 +38,9 @@
         CL_NetObject_Client obj;
 
     public:
-        NetworkClientLocalPlayer (NetworkClient &client, CL_NetObject_Client &obj, Coordinate initial_position);
+        NetworkClientLocalPlayer (NetworkClient &client, CL_NetObject_Client &obj, Vector initial_position);
         
-        virtual bool move (PositionDelta d);
+        virtual void applyForce (Vector force, uint16_t dt);
     
     private:
         void on_position (CL_NetPacket &pkt);
@@ -55,7 +55,7 @@
         CL_NetObject_Client obj;
 
     public:
-        NetworkClientRemotePlayer (NetworkClient &client, CL_NetObject_Client &obj, Coordinate initial_position);
+        NetworkClientRemotePlayer (NetworkClient &client, CL_NetObject_Client &obj, Vector initial_position);
     
     private:
         void on_position (CL_NetPacket &pkt);
--- a/src/proto2/NetworkServer.cc	Mon Nov 10 21:58:38 2008 +0000
+++ b/src/proto2/NetworkServer.cc	Tue Nov 18 22:58:50 2008 +0000
@@ -48,7 +48,7 @@
 }
         
 NetworkServerPlayer::NetworkServerPlayer (NetworkServer &server, CL_NetComputer &computer, uint16_t pid) : 
-    RemotePlayer(server.state, Coordinate(100, 100), true), server(server), computer(computer), obj(&server.netobjs), pid(pid) {
+    RemotePlayer(server.state, Vector(PLAYER_INITIAL_X, PLAYER_INITIAL_Y), true), server(server), computer(computer), obj(&server.netobjs), pid(pid) {
     
     // log
     Engine::log(INFO, "server_player.connected") << "computer=" << computer << ", obj=" << obj;
@@ -58,8 +58,7 @@
 
     // the initial NETMSG_PLAYER_HELLO
     CL_NetPacket hello_pkt;
-    hello_pkt.output.write_uint32(position.x);
-    hello_pkt.output.write_uint32(position.y);
+    writeVector(hello_pkt, position);
 
     obj.send(computer, NETMSG_SERVER_HELLO, hello_pkt, true);
 
@@ -71,8 +70,7 @@
         // player is not in players list yet
         assert(player != this);
 
-        player_pkt.output.write_uint32(player->position.x);
-        player_pkt.output.write_uint32(player->position.y);
+        writeVector(player_pkt, player->position);
 
         player->obj.send(computer, NETMSG_PLAYER_INFO, player_pkt, true);
     }
@@ -95,17 +93,13 @@
     if (!(from == computer))
         return;
     
-    // read packet
-    int32_t dx = pkt.input.read_int32();
-    int32_t dy = pkt.input.read_int32();
+    Vector impulse_force = readVector(pkt);    
+    uint16_t impulse_ms = pkt.input.read_uint16();
 
-    // movement delta
-    PositionDelta delta(dx, dy);
-
-    Engine::log(INFO, "server_player.on_move") << "obj=" << obj << ", old_pos=" << position << ", delta=" << delta;
-
-    // apply movement
-    position += delta;
+    Engine::log(INFO, "server_player.on_move") << "obj=" << obj << ", old_pos=" << position << ", impulse=" << impulse_force << "@" << impulse_ms << "ms";
+    
+    // apply force
+    applyForce(impulse_force, impulse_ms);
 
     // send position update
     send_position_update();
@@ -113,10 +107,10 @@
         
 void NetworkServerPlayer::send_position_update (void) {
     CL_NetPacket pkt;
-    pkt.output.write_uint32(position.x);
-    pkt.output.write_uint32(position.y);
+    writeVector(pkt, position);
+    writeVector(pkt, velocity);
 
-    Engine::log(INFO, "server_player.send_position_update") << "obj=" << obj << " -> " << position;
+    Engine::log(INFO, "server_player.send_position_update") << "obj=" << obj << " -> " << position << "+" << velocity;
 
     obj.send(server.netsession.get_all(), NETMSG_PLAYER_POSITION, pkt, false);
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/proto2/Physics.cc	Tue Nov 18 22:58:50 2008 +0000
@@ -0,0 +1,114 @@
+
+#include "Physics.hh"
+#include "Engine.hh"
+
+#include <algorithm>
+#include <functional>
+
+PhysicsWorld::PhysicsWorld (Vector gravity, Vector dimensions)
+    : tick_timer(PHYSICS_TICK_MS), gravity(gravity), dimensions(dimensions) {
+
+    slots.connect(tick_timer.sig_timer(), this, &PhysicsWorld::tick);
+    tick_timer.enable();
+}
+
+void PhysicsWorld::addObject (PhysicsObject *object) {
+    objects.push_back(object);
+}
+
+void PhysicsWorld::tick () {
+//    Engine::log(DEBUG, "physics.apply_force") << "*tick*";
+
+	for (std::vector<PhysicsObject*>::iterator i = objects.begin(); i != objects.end(); i++) {
+       	(*i)->tick(); 
+  	}
+}
+
+PhysicsObject::PhysicsObject (PhysicsWorld &world, float mass, Vector position, Vector velocity)
+    : world(world), mass(mass), position(position), velocity(velocity) {
+
+    world.addObject(this);
+}
+    
+void PhysicsObject::updatePosition () {
+
+	// Check if the player is moving on the ground
+	/*if (this->velocity.y == 0 && (position.y >= world.dimensions.y - 3)) {
+    	position.x += 50 * velocity.x * (PHYSICS_TICK_MS / 1000.0);
+		velocity.x = 0;
+		return;
+	}*/
+
+	// If not moving on the ground, apply normal physics
+
+    // Calculate gravity's influence on the velocity vector
+    this->velocity += world.gravity * (PHYSICS_TICK_MS / 1000.0);
+        
+    Vector newPosition = position + velocity * (PHYSICS_TICK_MS / 1000.0);
+
+    //TODO Handle the object as a square or a polygon
+    
+//    Engine::log(DEBUG, "physics.update_position") << "position=" << newPosition << ", velocity=" << velocity;
+
+    bool collided = false;
+     
+    if (newPosition.x < 0 || (newPosition.x > world.dimensions.x)) {
+        // CRASH!
+        this->velocity.x *= -0.5;
+		
+		// If the velocity drops under some fixed constant we decide it is zero.
+		// This is to prevent the object from bouncing eternally.
+		if (abs(this->velocity.x) < 0.1)
+			this->velocity.x = 0;
+
+        collided = true;
+    } else {
+        this->position.x = newPosition.x;
+    }
+    
+    if (newPosition.y <= 0 || (newPosition.y >= world.dimensions.y)) {
+		this->velocity.y *= -0.3;
+
+		
+ 
+		if (abs(this->velocity.y) < 0.1) {
+			this->velocity.y = 0;
+			// Friction
+			this->velocity.x *= 0.95;
+		} else {
+        	// Bigger friction
+			this->velocity.x *= 0.75;
+		}
+
+        collided = true;
+	} else {
+        this->position.y = newPosition.y;
+	}
+    
+    if(!collided) {
+        this->position = newPosition;
+    }
+}
+
+void PhysicsObject::applyForce (Vector force, uint16_t dt) {
+    Vector oldVelocity = velocity;
+
+    this->velocity += force * dt / 1000 / mass;  // The last factor denotes the time.
+    // It should be scaled somehow.
+    
+//    Engine::log(DEBUG, "physics.apply_force") << "force=" << force << ", velocity " << oldVelocity << " -> " << velocity;
+}
+
+void PhysicsObject::updatePhysics (Vector position, Vector velocity) {
+    this->position = position;
+    this->velocity = velocity;
+}
+    
+Vector PhysicsObject::getPosition () {
+    return this->position;
+}
+
+void PhysicsObject::tick () {
+    this->updatePosition();
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/proto2/Physics.hh	Tue Nov 18 22:58:50 2008 +0000
@@ -0,0 +1,55 @@
+#ifndef PHYSICS_HH
+#define PHYSICS_HH
+
+#include "Vector.hh"
+
+#include <ClanLib/core.h>
+
+const uint16_t PHYSICS_TICK_MS = 10;
+
+// forward-declare
+class PhysicsObject;
+
+class PhysicsWorld {
+    friend class PhysicsObject;
+            
+    private:
+        CL_Timer tick_timer;
+
+    protected:
+        std::vector<PhysicsObject*> objects;
+        Vector gravity;
+        Vector dimensions;
+
+        CL_SlotContainer slots;
+        
+        PhysicsWorld (Vector gravity, Vector dimensions);
+
+    public:
+        void addObject (PhysicsObject *object);
+
+        void tick (void);
+};
+
+class PhysicsObject {
+    protected:
+        PhysicsWorld &world;
+        float mass;
+        Vector position;
+        Vector velocity;
+    
+        PhysicsObject (PhysicsWorld &world, float mass, Vector position, Vector velocity);
+
+        virtual void applyForce (Vector force, uint16_t dt);
+        void updatePhysics (Vector position, Vector velocity);
+    
+    private:
+        void updatePosition (void);
+
+    public:
+        Vector getPosition (void);
+
+        void tick (void);
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/proto2/SinglePlayer.hh	Tue Nov 18 22:58:50 2008 +0000
@@ -0,0 +1,11 @@
+#ifndef SINGLE_PLAYER_HH
+#define SINGLE_PLAYER_HH
+
+#include "GameState.hh"
+
+class SinglePlayer : public LocalPlayer {
+    public:
+        SinglePlayer (GameState &state) : LocalPlayer(state, Vector(PLAYER_INITIAL_X, PLAYER_INITIAL_Y), true) { }
+};
+
+#endif /* SINGLE_PLAYER_HH */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/proto2/Vector.hh	Tue Nov 18 22:58:50 2008 +0000
@@ -0,0 +1,76 @@
+#ifndef COOR_H
+#define COOR_H
+
+#include <iostream>
+
+/**
+ * 2D Vector class. Implements standard vector operations.
+ */
+template <typename T>
+class _Vector {
+public:
+    T x;
+    T y;
+    
+    _Vector() : x(0), y(0){}
+    /**
+     * @param x Initial x-coordinate.
+     * @param y Initial y-coordinate.
+     */
+    _Vector(T x, T y) : x(x), y(y) {}
+    /**
+     * @param v Other vector to be copied.
+     */
+    _Vector(const _Vector &v) : x(v.x), y(v.y) {}
+
+    void operator=(const _Vector &v) {
+        this->x = v.x;
+        this->y = v.y;
+    }
+    _Vector operator+(const _Vector &v) const {
+        return _Vector(this->x+v.x, this->y+v.y);
+    }
+    _Vector operator-(const _Vector &v) const {
+        return _Vector(this->x-v.x, this->y-v.y);
+    }
+    _Vector operator*(const T &d) const {
+        return _Vector(this->x*d, this->y*d);
+    }
+    _Vector operator/(const T &d) const {
+        return _Vector(this->x/d, this->y/d);
+    } 
+    void operator+=(const _Vector &v) {
+        this->x += v.x;
+        this->y += v.y;
+    }
+    void operator-=(const _Vector &v) {
+        this->x -= v.x;
+        this->y -= v.y;
+    }
+    void operator*=(const T &f) {
+        this->x *= f;
+        this->y *= f;
+    }
+    void operator/=(const T &d) {
+        this->x /= d;
+        this->y /= d;
+    }
+};
+
+template<typename T>
+bool operator==(const _Vector<T> &v1, const _Vector<T> &v2) {
+    return ((v1.x == v2.x) && (v1.y == v2.y));
+}
+template<typename T>
+bool operator!=(const _Vector<T> &v1, const _Vector<T> &v2) {
+    return !(v1 == v2);
+}
+
+template<typename T>
+std::ostream& operator<<(std::ostream &s, const _Vector<T> &v) {
+    return s<<"("<<v.x<<", "<<v.y<<")";
+}
+
+typedef _Vector<float> Vector;
+
+#endif