This commit is contained in:
end 2016-09-28 07:16:24 +02:00
commit 8b1c94cebb
19 changed files with 500 additions and 113 deletions

View file

@ -12,6 +12,7 @@ set(GAME_SRC
game_window.cpp game_window.cpp
renderer_simple.cpp renderer_simple.cpp
renderer_shader.cpp renderer_shader.cpp
session.hpp
util.cpp util.cpp
game.cpp game.cpp
@ -38,7 +39,8 @@ include_directories(${CMAKE_CURRENT_BINARY_DIR})
include_directories(${CMAKE_CURRENT_SOURCE_DIR}) include_directories(${CMAKE_CURRENT_SOURCE_DIR})
include_directories(${OPENGL_INCLUDE_DIR}) include_directories(${OPENGL_INCLUDE_DIR})
include_directories(${CMAKE_SOURCE_DIR}/libs/glm/) include_directories(${CMAKE_SOURCE_DIR}/libs/glm/)
include_directories(${CMAKE_SOURCE_DIR}/libs/asio/asio/include/)
add_executable(game ${GAME_SRC} ${GAME_HEADERS}) add_executable(game ${GAME_SRC} ${GAME_HEADERS})
setup_target(game) setup_target(game)
target_link_libraries(game X11 epoxy) target_link_libraries(game X11 epoxy pthread)

View file

@ -6,39 +6,56 @@
#include <cmath> #include <cmath>
Game::Game() { Game::Game()
// advance simulation with 100 Hz {
m_time_step = 1.0 / 100.0; // advance simulation in fixed steps with 100 Hz
m_time_step = 1.0 / 100.0;
m_time_for_next_step = 0.0; m_time_for_next_step = 0.0;
m_state = new game::State(); m_state = new game::State();
m_state->init(); m_state->init();
m_state->addPlayer(0);
m_state->addPlayer(1);
m_state->addPlayer(2);
m_state->addPlayer(3);
// m_state->addPlayer(2);
} }
bool Game::cycle(float dt) { bool Game::cycle(float dt)
{
#if 0
// XXX the following is just testing code to do things
static float total = 0.0;
static float acc = 0.0; static float acc = 0.0;
acc += dt;
//if (total == 0.0) {
// float speed = 0.005;
// m_state->players[0]->addCommand(new game::SetSpeedCommand(speed));
// for (int i=0; i<100; i++) {
// float a = 2.0 * M_PI * util::randf_0_1();
// m_state->players[0]->addCommand(new game::ShootCommand(a));
// }
//}
m_state->addPlayer();
acc += dt;
total += dt;
float spawnInterval = 0.1; float spawnInterval = 0.1;
while (acc > spawnInterval) { while (acc > spawnInterval) {
acc -= spawnInterval; acc -= spawnInterval;
float a = 2.0 * M_PI * util::randf_0_1(); float angle = 2.0 * M_PI * util::randf_0_1();
float speed = 0.005; float speed = 0.005;
m_state->players[0]->addCommand(new game::ShootCommand(a, speed));
}
#if 1 m_state->players[0]->addCommand(new game::SetSpeedCommand(speed));
if (dt >= 10.0) { m_state->players[0]->addCommand(new game::ShootCommand(angle));
// std::cout<<"time to big: " << dt << std::endl;
dt = m_time_step; //static bool done = false;
//if (total >= 10.0 && !done) {
// done = true;
// m_state->players[0]->addCommand(new game::ClearTracesCommand());
//}
} }
#endif
// std::cout<<"adding dt: " << dt << std::endl; // std::cout<<"adding dt: " << dt << std::endl;
m_time_for_next_step += dt; m_time_for_next_step += dt;
@ -56,11 +73,4 @@ bool Game::cycle(float dt) {
// steps taken." << std::endl; // steps taken." << std::endl;
return true; return true;
#else
(void)dt;
m_state->advance(dt);
return true;
#endif
} }

View file

@ -11,7 +11,7 @@ class Game {
bool cycle(float dt); bool cycle(float dt);
// for rendering // for rendering
const game::State *state() const { return m_state; } game::State *state() const { return m_state; }
private: private:
game::State *m_state; game::State *m_state;

View file

@ -25,12 +25,12 @@ class GameWindow : public endofthejedi::GLWindow {
// if (!once) { // if (!once) {
// once = true; // once = true;
// for (int i=0; i<1000; i++) { // for (int i=0; i<1000; i++) {
// m_game.cycle(time); // m_game->cycle(time);
// } // }
//} //}
if (!m_game.cycle(static_cast<float>(time / 1000000000.0))) { if (!m_game->cycle(static_cast<float>(time/1000000000.0))) {
std::cout << "stopping the game..." << std::endl; std::cout<<"stopping the game..." << std::endl;
stop(); stop();
} }

View file

@ -1,17 +1,23 @@
#include "opengl.hpp"
#include <iostream> #include <iostream>
#include <getopt.h> #include <getopt.h>
#include <asio.hpp>
#include <cstdlib>
#include "opengl.hpp"
#include "game_window.hpp" #include "game_window.hpp"
#include "server.hpp"
#include "options.hpp" #include "options.hpp"
uint64_t optionsFlags; uint64_t optionsFlags;
using asio::ip::tcp;
using namespace std; using namespace std;
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
char port[]="3490";
char c; char c;
static struct option long_options[] = static struct option long_options[] =
@ -24,7 +30,7 @@ int main(int argc, char *argv[]) {
// {"add", no_argument, 0, 'a'}, // {"add", no_argument, 0, 'a'},
// {"append", no_argument, 0, 'b'}, // {"append", no_argument, 0, 'b'},
// {"delete", required_argument, 0, 'd'}, // {"delete", required_argument, 0, 'd'},
// {"create", required_argument, 0, 'c'}, {"port", required_argument, 0, 'p'},
{"fps", no_argument, 0, 'f'}, {"fps", no_argument, 0, 'f'},
{0, 0, 0, 0} {0, 0, 0, 0}
}; };
@ -32,7 +38,7 @@ int main(int argc, char *argv[]) {
int option_index = 0; int option_index = 0;
while(1){ while(1){
c = getopt_long (argc, argv, "abc:d:f", c = getopt_long (argc, argv, "p:f",
long_options, &option_index); long_options, &option_index);
if (c == -1) if (c == -1)
break; break;
@ -42,10 +48,10 @@ int main(int argc, char *argv[]) {
case 'f': case 'f':
SET_FLAG(SHOW_FPS,true); SET_FLAG(SHOW_FPS,true);
break; break;
/*case 'c': case 'p':
cvalue = optarg; strcpy(port,optarg);
break; break;
*/
case '?': case '?':
/* getopt_long already printed an error message. */ /* getopt_long already printed an error message. */
@ -56,8 +62,18 @@ int main(int argc, char *argv[]) {
} }
} }
GameWindow window(500, 500); Game game;
asio::io_service io_service;
Server s(io_service, game.state(), atoi(port) );
GameWindow window(500, 500, &game);
window.set_maxfps(60.0); window.set_maxfps(60.0);
window.loop();
window.stop(); while(window.running()){
window.poll();
io_service.poll();
}
return 0;
} }

View file

@ -102,44 +102,26 @@ void endofthejedi::GLWindow::handle(XEvent event) {
void endofthejedi::GLWindow::swap() { glXSwapBuffers(m_display, m_window); } void endofthejedi::GLWindow::swap() { glXSwapBuffers(m_display, m_window); }
void endofthejedi::GLWindow::loop() { void endofthejedi::GLWindow::poll() {
m_running = true;
timespec prev;
timespec current;
clock_gettime(CLOCK_MONOTONIC_RAW, &prev); clock_gettime(CLOCK_MONOTONIC_RAW, &prev);
clock_gettime(CLOCK_MONOTONIC_RAW, &current); clock_gettime(CLOCK_MONOTONIC_RAW, &current);
double delta = 0.0; handleevents();
double sleeptime = 0.0; render(delta);
swap();
while (m_running) { if (m_maxfps > 0) {
handleevents(); sleeptime = ((1000000000.0/m_maxfps) - delta) + sleeptime;
render(delta); if (sleeptime > 0.0) {
swap(); usleep((unsigned int)(sleeptime/1000.0));
sleeptime = sleeptime - (unsigned int)(sleeptime/1000.0);
if (m_maxfps > 0) { }
sleeptime = ((1000000000.0 / m_maxfps) - delta) + sleeptime;
if (sleeptime > 0.0) {
usleep((unsigned int)(sleeptime / 1000.0));
sleeptime = sleeptime - (unsigned int)(sleeptime / 1000.0);
}
}
clock_gettime(CLOCK_MONOTONIC_RAW, &current);
delta = diff(prev, current).tv_nsec;
prev = current;
if (delta > 0.0) {
m_fps = (1000000000.0 / delta);
if (ISSET_FLAG(SHOW_FPS)) {
std::cout << m_fps << "\n";
}
}
} }
} }
void endofthejedi::GLWindow::stop() { m_running = false; } void endofthejedi::GLWindow::stop() { m_running = false; }
bool endofthejedi::GLWindow::running() { return m_running; }
void endofthejedi::GLWindow::init() {} void endofthejedi::GLWindow::init() { m_running = true; }
void endofthejedi::GLWindow::render(double time) { UNUSED(time) } void endofthejedi::GLWindow::render(double time) { UNUSED(time) }
void endofthejedi::GLWindow::resize() {} void endofthejedi::GLWindow::resize() {}

View file

@ -9,11 +9,11 @@
namespace endofthejedi { namespace endofthejedi {
class GLWindow { class GLWindow {
private: private:
//X-related stuff //X-related stuff
Display* m_display; Display* m_display;
Window m_rootwnd; Window m_rootwnd;
GLint m_attributes[23] = GLint m_attributes[23] =
{ {
GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT, GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
GLX_RENDER_TYPE, GLX_RGBA_BIT, GLX_RENDER_TYPE, GLX_RGBA_BIT,
@ -28,17 +28,21 @@ class GLWindow {
None None
}; };
XVisualInfo* m_visualinfo; XVisualInfo* m_visualinfo;
Colormap m_colormap; Colormap m_colormap;
XSetWindowAttributes m_swa; XSetWindowAttributes m_swa;
Window m_window; Window m_window;
GLXContext m_glcontext; GLXContext m_glcontext;
XWindowAttributes m_gwa; XWindowAttributes m_gwa;
Atom m_atomWmDeleteWindow; Atom m_atomWmDeleteWindow;
//End of X related stuff //End of X related stuff
unsigned int m_width; unsigned int m_width;
unsigned int m_height; unsigned int m_height;
double delta = 0.0;
double sleeptime = 0.0;
timespec prev;
timespec current;
//mainloop condition //mainloop condition
bool m_running = false; bool m_running = false;
@ -47,9 +51,7 @@ class GLWindow {
//if maxfps = 0 there's no fps limit //if maxfps = 0 there's no fps limit
double m_maxfps; double m_maxfps;
void handleevents(); protected:
protected:
//ancestors shall override these methods //ancestors shall override these methods
virtual void init(); virtual void init();
//called by mainloop periodically //called by mainloop periodically
@ -61,16 +63,19 @@ class GLWindow {
//as it handles the close calls & resizing //as it handles the close calls & resizing
virtual void handle(XEvent event); virtual void handle(XEvent event);
virtual void handleevents();
public: public:
//initializes the X Window & creates an OpenGL context //initializes the X Window & creates an OpenGL context
GLWindow(unsigned int width, unsigned int height); GLWindow(unsigned int width, unsigned int height);
~GLWindow(); ~GLWindow();
//mainloop does event handling & calls render/swap //mainloop does event handling & calls render/swap
void loop(); void poll();
void swap(); void swap();
//stops the mainloop by setting m_running false //stops the mainloop by setting m_running false
void stop(); void stop();
bool running();
//getters //getters
unsigned int getheight() const { unsigned int getheight() const {

38
game/server.hpp Normal file
View file

@ -0,0 +1,38 @@
#pragma once
#include <asio.hpp>
#include "session.hpp"
using asio::ip::tcp;
class Server
{
public:
Server(asio::io_service& io_service,game::State* s, short port)
: acceptor_(io_service, tcp::endpoint(tcp::v4(), port)),
socket_(io_service)
{
state=s;
do_accept();
}
private:
void do_accept()
{
acceptor_.async_accept(socket_,
[this](std::error_code ec)
{
if (!ec)
{
std::make_shared<Session>(std::move(socket_),state)->start();
}
do_accept();
});
}
tcp::acceptor acceptor_;
tcp::socket socket_;
game::State* state;
};

35
game/session.hpp Normal file
View file

@ -0,0 +1,35 @@
#pragma once
#include <iostream>
#include <memory>
#include <utility>
#include <string>
#include <asio.hpp>
#include "game.hpp"
using asio::ip::tcp;
class Session
: public std::enable_shared_from_this<Session>
{
public:
Session(tcp::socket socket, game::State* state)
: m_socket(std::move(socket))
{
m_state = state;
}
void start();
private:
void do_read();
void do_write(char m_snd_data[], std::size_t length);
bool parse(std::string);
tcp::socket m_socket;
enum { max_length = 1024 };
char m_rcv_data[max_length];
game::State* m_state;
bool m_started = false;
int m_pid;
};

View file

@ -2,6 +2,8 @@
#include "trace.hpp" #include "trace.hpp"
#include <iostream>
namespace game { namespace game {
void ShootCommand::apply(Player *player, State *state) const void ShootCommand::apply(Player *player, State *state) const
{ {
@ -10,23 +12,72 @@ namespace game {
// TODO: idea // TODO: idea
// shoot multiple rockets at once or from different positions after // shoot multiple rockets at once or from different positions after
// level up / upgrade ... // level up / upgrade ...
Missile *missile = new Missile(player, player->ship->position, m_angle, m_speed); Missile *missile = new Missile(player, player->ship->position, m_angle, player->speed);
Trace *trace = new Trace(missile); Trace *trace = new Trace(missile);
missile->trace = trace; missile->trace = trace;
player->energy -= m_speed; player->energy -= player->speed;
player->missiles.push_back(missile); player->missiles.push_back(missile);
state->addTrace(trace); state->addTrace(trace);
} }
bool ShootCommand::allowed(const Player *player, const State *state) const bool ShootCommand::ready(const Player *player, const State *state) const
{ {
(void) state; (void) state;
// TODO // TODO
return player->alive && player->energy >= m_speed; return player->alive && player->energy >= player->speed;
//return player->alive; //return player->alive;
} }
void ChangeNameCommand::apply(Player *player, State *state) const
{
// discard if not unique
for (const Player *other : state->players) {
if (m_name == other->name) {
std::cout << "name '" << m_name << "' already given to player #" << other->id << std::endl;
return;
}
}
player->name = m_name;
}
void SetSpeedCommand::apply(Player *player, State *state) const
{
(void) state;
player->speed = m_speed;
}
void ClearTracesCommand::apply(Player *player, State *state) const
{
std::cout<<"clearing traces!!!" << std::endl;
size_t i = 0;
while(i < state->traces.size()) {
Trace *trace = state->traces[i];
if (trace->missile == nullptr && trace->player == player) {
state->deleteTrace(i);
} else {
i++;
}
}
}
#if 0
bool TakeOverPlayerCommand::ready(const Player *player, const State *state) const
{
(void) state;
return state->havePlayerGrantFor(player->id, m_otherPlayerId);
}
void TakeOverPlayerCommand::apply(Player *player, State *state) const
{
if (
state->playerGrant(player->id, m_otherPlayerId);
}
#endif
} }

View file

@ -9,6 +9,10 @@
#include <iostream> #include <iostream>
namespace game { namespace game {
/**
* Base class for commands.
* must derive from this.
*/
class Command { class Command {
public: public:
Command() Command()
@ -19,7 +23,11 @@ namespace game {
{ {
} }
virtual bool allowed(const Player *player, const State *state) const // check whether the command is ready to execute.
// if not, wait.
// note: stuff like for admin should be done in execute() to discard the
// command and not block the queue.
virtual bool ready(const Player *player, const State *state) const
{ {
(void) player; (void) player;
(void) state; (void) state;
@ -38,19 +46,95 @@ namespace game {
virtual std::string name() const { return "<unnamed>"; } virtual std::string name() const { return "<unnamed>"; }
}; };
/**********************************************************************/
/* Implemented commands */
/**********************************************************************/
/*
* Shoot at angle and optional speed.
* TODO
*/
class ShootCommand : public Command { class ShootCommand : public Command {
public: public:
ShootCommand(float angle, float speed) : m_angle(angle), m_speed(speed) ShootCommand(float angle) : m_angle(angle)
{ {
} }
std::string name() const { return "<shoot>"; } std::string name() const { return "<shoot>"; }
void apply( Player *player, State *state) const; void apply( Player *player, State *state) const;
bool allowed(const Player *player, const State *state) const; bool ready(const Player *player, const State *state) const;
private: private:
float m_angle; float m_angle;
};
/**
* Change the name of the player if it will be uniuqe.
*/
class ChangeNameCommand : public Command {
public:
ChangeNameCommand(const std::string &name) : m_name(name)
{
}
std::string name() const { return "<change name>"; }
void apply(Player *player, State *state) const;
private:
std::string m_name;
};
/**
* clear all traces of this player that are done
*/
class ClearTracesCommand : public Command {
public:
ClearTracesCommand()
{
}
std::string name() const { return "<clear traces>"; }
void apply(Player *player, State *state) const;
};
/**
* Set default speed of next shots for this player.
*/
class SetSpeedCommand : public Command {
public:
SetSpeedCommand(float speed) : m_speed(speed)
{
}
std::string name() const { return "<set speed>"; }
void apply(Player *player, State *state) const;
private:
float m_speed; float m_speed;
}; };
#if 0
/**
* Take over a session for a player that left.
* An admin must confirm this command.
*/
class TakeOverPlayerCommand : public Command {
public:
TakeOverPlayerCommand(int otherPlayerId) : m_otherPlayerId(otherPlayerId)
{
}
std::string name() const { return "<take over player>"; }
void apply( Player *player, State *state) const;
bool ready(const Player *player, const State *state) const;
private:
int m_otherPlayerId;
};
#endif
} }

View file

@ -49,7 +49,7 @@ namespace game {
if (dist <= planet->radius) { if (dist <= planet->radius) {
// TODO: collect all hits and return the first one only // TODO: collect all hits and return the first one only
// TODO: find exact hit position! // TODO: find exact hit position!
return Missile::Event(position, Hit::Planet); return Missile::Event(position, planet->id);
} }
dist *= 20.0; dist *= 20.0;

View file

@ -22,7 +22,8 @@ namespace game {
// stops existing afterwards. // stops existing afterwards.
class Event { class Event {
public: public:
Event(const glm::vec2 &pos) : Event(pos, Hit::Nothing) Event(const glm::vec2 &pos)
: Event(pos, Hit::Nothing)
{ {
} }
@ -31,6 +32,11 @@ namespace game {
{ {
} }
Event(const glm::vec2 &pos, int planetId) : Event(pos, Hit::Planet)
{
this->planetId = planetId;
}
Event(const glm::vec2 &pos, int playerIdKiller, int playerIdVictim) Event(const glm::vec2 &pos, int playerIdKiller, int playerIdVictim)
: Event(pos, Hit::Ship) : Event(pos, Hit::Ship)
{ {
@ -41,8 +47,12 @@ namespace game {
Hit hit; Hit hit;
glm::vec2 position; glm::vec2 position;
// if a player was hit, these are valid.
int playerIdKiller; int playerIdKiller;
int playerIdVictim; int playerIdVictim;
// if a planet was hit, this is valid
int planetId;
}; };
Missile(Player *player, const glm::vec2 &pos, float angle, float speed); Missile(Player *player, const glm::vec2 &pos, float angle, float speed);

View file

@ -2,11 +2,39 @@
#include "object.hpp" #include "object.hpp"
#include <cstdlib>
namespace game { namespace game {
class Planet : public Object { class Planet : public Object {
public: public:
Planet(const glm::vec2 &pos, float r) : Object(pos, r) /**
* Planets are build out of one material.
* TODO: support mixture or multiple material per planet.
*/
enum class Material {
Rock,
Metal,
Sand,
Gas,
Ice,
Water,
Sun
};
Planet(const glm::vec2 &pos, int id, float r) : Planet(pos, id, r, Material::Rock)
{ {
} }
Planet(const glm::vec2 &pos, int id, float r, Material mat)
: Object(pos, r)
, id(id)
, material(mat)
, seed(rand())
{
}
int id;
Material material; // for rendering and physics (can fly through sun and outer gas planets)
int seed; // just for rendering variation
}; };
} }

View file

@ -1,5 +1,6 @@
#pragma once #pragma once
#include <string>
#include <deque> #include <deque>
#include <vector> #include <vector>
@ -15,12 +16,14 @@ namespace game {
public: public:
int id; int id;
bool alive; bool alive;
float speed;
float energy; float energy;
float deadTimeCounter; float deadTimeCounter;
Ship *ship; Ship *ship;
std::string name;
std::vector<Missile*> missiles; std::vector<Missile*> missiles;
Player(int id) : id(id), alive(true), energy(0.0), ship(nullptr) Player(int id) : id(id), alive(true), speed(0.01), energy(0.0), ship(nullptr), name("<unnamed>")
{ {
} }

View file

@ -18,6 +18,8 @@
#include "util.hpp" #include "util.hpp"
using namespace std;
namespace game { namespace game {
void State::init() void State::init()
{ {
@ -25,6 +27,7 @@ namespace game {
m_maxMissileDistance = 2.0; m_maxMissileDistance = 2.0;
m_playerRespawnTime = 2.0; m_playerRespawnTime = 2.0;
m_defaultEnergy = 10.0; m_defaultEnergy = 10.0;
m_maxNumTraces = 10;
bool planetsOnCircle = false; bool planetsOnCircle = false;
@ -45,7 +48,7 @@ namespace game {
} }
} while(glm::length(pos) < 0.2 && tries++ < 1000); } while(glm::length(pos) < 0.2 && tries++ < 1000);
planets.push_back(new Planet(pos, 0.03 + 0.07*util::randf_0_1())); planets.push_back(new Planet(pos, i, 0.03 + 0.07*util::randf_0_1()));
} }
} }
@ -64,15 +67,41 @@ namespace game {
return true; return true;
} }
void State::addPlayer(int playerId) int State::addPlayer()
{ {
int playerId = m_nextId++;
Player *player = new Player(playerId); Player *player = new Player(playerId);
players.push_back(player); players.push_back(player);
return playerId;
} }
void State::playerLeft(int playerId) void State::quitPlayer(int playerId)
{ {
(void) playerId; (void) playerId;
cout << playerId << " quit" << endl;
}
void State::clear(int playerId)
{
cout << playerId << " clear" << endl;
}
void State::setName(int playerId, std::string name)
{
// discard if not unique
for (const Player *other : players) {
if (name == other->name) {
std::cout << "name '" << name << "' already given to player #" << other->id << std::endl;
return;
}
}
playerForId(playerId)->name = name;
}
void State::setSpeed(int playerId, double speed)
{
playerForId(playerId)->speed = speed;
} }
void State::advancePlayerShipSpawns(float dt) void State::advancePlayerShipSpawns(float dt)
@ -108,7 +137,7 @@ namespace game {
// try to execute as much queued commands as possible. // try to execute as much queued commands as possible.
while (player->hasCommandInQueue()) { while (player->hasCommandInQueue()) {
Command *command = player->peekCommand(); Command *command = player->peekCommand();
if (!command->allowed(player, this)) { if (!command->ready(player, this)) {
break; break;
} }
@ -145,12 +174,9 @@ namespace game {
// TODO // TODO
// add points // add points
//
// TODO // TODO
// message // message
//
// TODO
// respawn timer
} }
void State::advancePlayerMissiles(float dt) void State::advancePlayerMissiles(float dt)
@ -166,7 +192,9 @@ namespace game {
const bool isHit = (evt.hit != Hit::Nothing); const bool isHit = (evt.hit != Hit::Nothing);
missile->trace->addPointFromMissile(isHit); // force point if missile gets destroyed a if (missile->trace != nullptr) {
missile->trace->addPointFromMissile(isHit); // force point if missile gets destroyed a
}
if (!isHit) { if (!isHit) {
i++; i++;
@ -192,6 +220,10 @@ namespace game {
addExplosionFromHit(&evt); addExplosionFromHit(&evt);
if (missile->trace != nullptr) {
missile->trace->finish();
}
player->missiles.erase(player->missiles.begin() + i); player->missiles.erase(player->missiles.begin() + i);
delete(missile); delete(missile);
//std::cout<<std::endl; //std::cout<<std::endl;
@ -287,9 +319,50 @@ namespace game {
void State::addTrace(Trace *trace) void State::addTrace(Trace *trace)
{ {
//int count = 0;
//for (Trace *old : traces) {
// if (old->playerId == trace->playerId) {
// count++;
// }
//}
//if (count > m_maxNumTraces) {
//}
traces.push_back(trace); traces.push_back(trace);
} }
void State::deleteTrace(size_t index)
{
if (index >= traces.size()) {
std::cerr << "can't find trace with invalid index " << index << std::endl;
return;
}
Trace *trace = traces[index];
//std::cout<<"removing a trace" << std::endl;
if (trace->missile != nullptr) {
// delete backlink.
// XXX: there's a missile without a trace now.
trace->missile->trace = nullptr;
}
traces.erase(traces.begin() + index);
delete(trace);
}
void State::deleteTrace(Trace *trace)
{
size_t i = 0;
while(i < traces.size()) {
if (traces[i] == trace) {
deleteTrace(i);
break;
}
}
}
void State::addExplosionFromHit(const Missile::Event *evt) void State::addExplosionFromHit(const Missile::Event *evt)
{ {
if (evt->hit == Hit::Nothing || evt->hit == Hit::BorderOfUniverse) { if (evt->hit == Hit::Nothing || evt->hit == Hit::BorderOfUniverse) {

View file

@ -2,6 +2,7 @@
#include <vector> #include <vector>
#include <queue> #include <queue>
#include <string>
#include <iostream> #include <iostream>
@ -9,6 +10,18 @@
#include "missile.hpp" #include "missile.hpp"
// TODO:
// give points for equipment / better weapons / more energy when:
// - player discovers the universe
//
// - the shot which made a kill was much longer than the direkt line between
// player and his target
//
// - add wormholes
// - add blackholes
// - shoot through suns which add a fire mantle to the rocket to make it more
// thick and dangerous but it gets destroyed after some time.
namespace game { namespace game {
// forward declarations // forward declarations
class Command; class Command;
@ -38,8 +51,11 @@ namespace game {
// The upper layer (network/renderer) calling these three functions // The upper layer (network/renderer) calling these three functions
// should keep id's unique and give one (network) input an id. // should keep id's unique and give one (network) input an id.
void addPlayer(int playerId); int addPlayer();
void playerLeft(int playerId); void clear(int playerId);
void setName(int playerId, std::string name);
void setSpeed(int playerId, double speed);
void quitPlayer(int playerId);
void commandForPlayer(int playerId, Command *cmd); void commandForPlayer(int playerId, Command *cmd);
// lookup. return nullptr on invalid playerId // lookup. return nullptr on invalid playerId
@ -57,6 +73,10 @@ namespace game {
// add a trace to the list of traces. // add a trace to the list of traces.
void addTrace(Trace *trace); void addTrace(Trace *trace);
// delete traces with this command
void deleteTrace(Trace *trace); // using a pointer
void deleteTrace(size_t index); // using an index
/*************************************************************************/ /*************************************************************************/
/* Rendering */ /* Rendering */
/*************************************************************************/ /*************************************************************************/
@ -95,5 +115,7 @@ namespace game {
float m_playerRespawnTime; float m_playerRespawnTime;
float m_shipRadius; float m_shipRadius;
float m_defaultEnergy; float m_defaultEnergy;
int m_nextId=0;
int m_maxNumTraces;
}; };
}; };

View file

@ -4,6 +4,8 @@
#include "missile.hpp" #include "missile.hpp"
#include <iostream>
namespace game { namespace game {
Trace::TracePoint::TracePoint(const Missile *missile) Trace::TracePoint::TracePoint(const Missile *missile)
: position(missile->position) : position(missile->position)
@ -11,7 +13,16 @@ namespace game {
{ {
} }
Trace::Trace(const Missile *missile) : missile(missile), fidelityCounter(0) Trace::~Trace()
{
//std::cout<<"~Trace()" << std::endl;
}
Trace::Trace(Missile *missile)
: missile(missile)
, player(missile->player)
, fidelityCounter(0)
, age(0.0)
{ {
points.push_back(TracePoint(missile)); points.push_back(TracePoint(missile));
} }
@ -24,4 +35,10 @@ namespace game {
points.push_back(TracePoint(missile)); points.push_back(TracePoint(missile));
} }
} }
void Trace::finish()
{
//std::cout<<"trace finished now!" << std::endl;
missile = nullptr;
}
} }

View file

@ -5,6 +5,7 @@
namespace game { namespace game {
class Missile; class Missile;
class Player;
/* /*
* Trace of a missile through the space. * Trace of a missile through the space.
@ -12,7 +13,8 @@ namespace game {
*/ */
class Trace { class Trace {
public: public:
Trace(const Missile *missile); Trace(Missile *missile);
~Trace();
// Add the current position of the missile as a new point on the // Add the current position of the missile as a new point on the
// trace. // trace.
@ -21,6 +23,10 @@ namespace game {
// the missile) in case the fidelityCounter would skip the current position. // the missile) in case the fidelityCounter would skip the current position.
void addPointFromMissile(bool forceAdd=false); void addPointFromMissile(bool forceAdd=false);
// call this to mark the trace as finish and disconnect it from the
// missile.
void finish();
// TODO: add extendLastPointToPosition() method for saving points / // TODO: add extendLastPointToPosition() method for saving points /
// optimization later on // optimization later on
@ -35,11 +41,16 @@ namespace game {
}; };
std::vector<TracePoint> points; std::vector<TracePoint> points;
const Missile *missile; // missile which creates this path. Missile *missile; // missile which creates this path.
Player *player;
// counter which is incremented each time addPointFromMissile() is called. // counter which is incremented each time addPointFromMissile() is called.
// when reaching a certain value the point is saved for // when reaching a certain value the point is saved for
// optimization. // optimization.
int fidelityCounter; int fidelityCounter;
// age of the trace. if too old, it can be removed to save
// space/power
float age;
}; };
} }