# HG changeset patch # User terom # Date 1227049130 0 # Node ID e21cfda0edde958740752ee56cc39375ef900db9 # Parent 1ea6554d703e9d5f2209d4420b6f7bcf5277d82b Merge from at r31:36 diff -r 1ea6554d703e -r e21cfda0edde build/mkcmake.sh --- /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 + diff -r 1ea6554d703e -r e21cfda0edde plan/diagram.dot --- 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; diff -r 1ea6554d703e -r e21cfda0edde plan/test.ps --- 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 + diff -r 1ea6554d703e -r e21cfda0edde src/proto2/Application.cc --- 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(); diff -r 1ea6554d703e -r e21cfda0edde src/proto2/Dimension.cc --- 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; -} - diff -r 1ea6554d703e -r e21cfda0edde src/proto2/Dimension.hh --- 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 - -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 diff -r 1ea6554d703e -r e21cfda0edde src/proto2/Engine.cc --- 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 @@ -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); } } diff -r 1ea6554d703e -r e21cfda0edde src/proto2/Engine.hh --- 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); diff -r 1ea6554d703e -r e21cfda0edde src/proto2/GameState.cc --- 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); } } - - - diff -r 1ea6554d703e -r e21cfda0edde src/proto2/GameState.hh --- 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 #include -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_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 */ diff -r 1ea6554d703e -r e21cfda0edde src/proto2/Graphics.cc --- 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::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 ); } diff -r 1ea6554d703e -r e21cfda0edde src/proto2/Graphics.hh --- 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 #include -#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: diff -r 1ea6554d703e -r e21cfda0edde src/proto2/Input.hh --- /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 diff -r 1ea6554d703e -r e21cfda0edde src/proto2/Network.cc --- /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; +} + diff -r 1ea6554d703e -r e21cfda0edde src/proto2/Network.hh --- 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 +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, }; diff -r 1ea6554d703e -r e21cfda0edde src/proto2/NetworkClient.cc --- 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) { diff -r 1ea6554d703e -r e21cfda0edde src/proto2/NetworkClient.hh --- 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); diff -r 1ea6554d703e -r e21cfda0edde src/proto2/NetworkServer.cc --- 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); } diff -r 1ea6554d703e -r e21cfda0edde src/proto2/Physics.cc --- /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 +#include + +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::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(); +} + diff -r 1ea6554d703e -r e21cfda0edde src/proto2/Physics.hh --- /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 + +const uint16_t PHYSICS_TICK_MS = 10; + +// forward-declare +class PhysicsObject; + +class PhysicsWorld { + friend class PhysicsObject; + + private: + CL_Timer tick_timer; + + protected: + std::vector 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 diff -r 1ea6554d703e -r e21cfda0edde src/proto2/SinglePlayer.hh --- /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 */ diff -r 1ea6554d703e -r e21cfda0edde src/proto2/Vector.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 + +/** + * 2D Vector class. Implements standard vector operations. + */ +template +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 +bool operator==(const _Vector &v1, const _Vector &v2) { + return ((v1.x == v2.x) && (v1.y == v2.y)); +} +template +bool operator!=(const _Vector &v1, const _Vector &v2) { + return !(v1 == v2); +} + +template +std::ostream& operator<<(std::ostream &s, const _Vector &v) { + return s<<"("< Vector; + +#endif