a basic implementation of game messages, plus some weird GameStateEvent stuff
authorTero Marttila <terom@fixme.fi>
Tue, 13 Jan 2009 23:15:47 +0200
changeset 393 5dd4d782cf3a
parent 392 6c4dc68360eb
child 394 82def222fe7d
a basic implementation of game messages, plus some weird GameStateEvent stuff
src/Config.hh
src/GameMessageView.cc
src/GameMessageView.hh
src/GameState.cc
src/GameState.hh
src/Graphics.cc
src/Graphics.hh
src/Player.hh
src/Types.hh
--- a/src/Config.hh	Tue Jan 13 21:36:43 2009 +0200
+++ b/src/Config.hh	Tue Jan 13 23:15:47 2009 +0200
@@ -119,6 +119,10 @@
 const uint16_t GRAPHICS_UPDATE_INTERVAL_MS = 20;
 const bool GRAPHICS_FULLSCREEN = false;
 
+/**
+ * Number of pixels between lines
+ */
+const PixelDimension GRAPHICS_INFO_TEXT_LINE_OFFSET = 5;
 
 // Filesystem paths
 const std::string PLAYER_SKIN_PATH = (PROJECT_DATA_DIR "/skin.png");
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/GameMessageView.cc	Tue Jan 13 23:15:47 2009 +0200
@@ -0,0 +1,56 @@
+
+#include "GameMessageView.hh"
+#include "Graphics.hh"
+#include "Engine.hh"
+
+GameMessageView::GameMessageView (PixelArea area) :
+    area(area), messages()
+{
+    
+}
+
+void GameMessageView::add_message (CL_Color color, std::string message) {
+    GameMessage msg (color, message);
+
+    messages.push_back(msg);
+}
+
+void GameMessageView::draw (Graphics *g) {
+    // get font
+    CL_Font &font = g->getSimpleFont(); 
+
+    // remember color
+    CL_Color font_color = font.get_color();
+    
+    // maximum width
+    CL_Size max_size = CL_Size(area.right - area.left, 0);
+
+    // starting point for drawing
+    PixelDimension offset_prev = area.bottom;
+
+    // render messages, bottom up
+    for (std::vector<GameMessage>::reverse_iterator it = messages.rbegin(); it != messages.rend(); it++) {
+        // set message color
+        font.set_color(it->color);
+
+        // calculate height
+        PixelDimension height = font.get_height(it->message, max_size) + GRAPHICS_INFO_TEXT_LINE_OFFSET;
+       
+        // new draw_point
+        PixelDimension offset_this = offset_prev - height;
+
+        // break if it doesn't fit anymore
+        if (offset_this < area.top)
+            break;
+ 
+        // draw text
+        font.draw(CL_Rect(area.left, offset_this, area.right, offset_prev), it->message, g->get_gc());
+        
+        // advance offset
+        offset_prev = offset_this;
+    }
+
+    // restore font color
+    font.set_color(font_color);
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/GameMessageView.hh	Tue Jan 13 23:15:47 2009 +0200
@@ -0,0 +1,42 @@
+#ifndef GRAPHICS_INFO_TEXT_HH
+#define GRAPHICS_INFO_TEXT_HH
+
+#include "GraphicsPointer.hh"
+#include "Types.hh"
+
+#include <string>
+#include <vector>
+#include <ClanLib/display.h>
+
+struct GameMessage {
+    CL_Color color;
+    std::string message;
+
+    GameMessage (CL_Color color, std::string message) : color(color), message(message) { }
+    GameMessage (const GameMessage &copy) : color(copy.color), message(copy.message) { }
+    GameMessage &operator= (const GameMessage &copy) { color = copy.color; message = copy.message; return *this; }
+};
+
+class GameMessageView {
+    protected:
+        PixelArea area;
+        std::vector<GameMessage> messages;
+
+    public:
+        /**
+         * Define the area where messages are drawn
+         */
+        GameMessageView (PixelArea area);
+
+        /**
+         * Add a message to the list of messages displayed
+         */
+        void add_message (CL_Color color, std::string message);
+        
+        /**
+         * Draw as many messages as fits
+         */
+        void draw (Graphics *g);
+};
+
+#endif
--- a/src/GameState.cc	Tue Jan 13 21:36:43 2009 +0200
+++ b/src/GameState.cc	Tue Jan 13 23:15:47 2009 +0200
@@ -4,10 +4,17 @@
 #include "Config.hh"
 
 GameState::GameState (void) : 
-    world(Vector(0, MAP_GRAVITY), Vector(MAP_WIDTH, MAP_HEIGHT)), local_player(NULL)
+    world(Vector(0, MAP_GRAVITY), Vector(MAP_WIDTH, MAP_HEIGHT)), local_player(NULL), event_handler(NULL)
 { 
 
 }
+    
+void GameState::setEventHandler (GameStateEventHandler *handler) {
+    if (handler && event_handler != NULL)
+        throw Error("event_handler already set");
+
+    event_handler = handler;
+}
 
 void GameState::addProjectile (Projectile *projectile) {
     projectiles.push_back(projectile);
@@ -26,6 +33,9 @@
     
 void GameState::addPlayer (Player *player) {
     player_list.push_back(player);
+
+    if (event_handler)
+        event_handler->on_player_joined(player);
 }
 
 void GameState::removePlayer (Player *player) { 
@@ -33,6 +43,9 @@
         local_player = NULL;
 
     player_list.remove(player);
+    
+    if (event_handler)
+        event_handler->on_player_left(player);
 }
     
 void GameState::draw(Graphics *g, PixelCoordinate camera, bool displayWeapon) {
--- a/src/GameState.hh	Tue Jan 13 21:36:43 2009 +0200
+++ b/src/GameState.hh	Tue Jan 13 23:15:47 2009 +0200
@@ -15,6 +15,14 @@
 #include <stdexcept>
 #include <cmath>
 
+class GameStateEventHandler {
+    friend class GameState;
+
+    protected:
+        virtual void on_player_joined (Player *p) = 0;
+        virtual void on_player_left (Player *p) = 0;
+};
+
 class GameState {
 public:
     std::list<Player*> player_list;
@@ -26,12 +34,24 @@
      */
     LocalPlayer *local_player;
     
+protected:
+    /**
+     * Notify someone about events?
+     */
+    GameStateEventHandler *event_handler;
+
+public:    
     /**
      * ...
      * 
      * This should take some arguments
      */
     GameState (void);
+
+    /**
+     * Set event handler, only one can be set
+     */
+    void setEventHandler (GameStateEventHandler *handler);
     
     /**
      * Adds projectile to our list of projectiles to draw
--- a/src/Graphics.cc	Tue Jan 13 21:36:43 2009 +0200
+++ b/src/Graphics.cc	Tue Jan 13 23:15:47 2009 +0200
@@ -4,6 +4,18 @@
 #include <cmath>
 #include <sstream>
 
+/*
+ * XXX: until we figure out a better way to layout stuff
+ */
+static PixelArea getMessageViewArea (PixelCoordinate resolution) {
+    return PixelArea(
+            400,
+            resolution.y - 100,
+            resolution.x,
+            resolution.y
+    );
+}
+
 Graphics::Graphics (Engine &engine, GameState &state, PixelCoordinate resolution, bool fullscreen) :
     CL_DisplayWindow(GRAPHICS_WINDOW_TITLE, resolution.x, resolution.y, fullscreen),
     engine(engine), 
@@ -11,7 +23,8 @@
     resolution(resolution),
     update_timer(GRAPHICS_UPDATE_INTERVAL_MS),
     input(get_ic()->get_keyboard()),
-    simple_font("Font2", engine.getResourceManager()) 
+    simple_font("Font2", engine.getResourceManager()),
+    message_view(getMessageViewArea(resolution))
 {
 
     // connect timer signal
@@ -19,6 +32,12 @@
 
     // enable
     update_timer.start();
+
+    // push something to message_view
+    message_view.add_message(CL_Color::white, "Hello World"); 
+
+    // GameState events....
+    state.setEventHandler(this);
 }
 
 const std::vector<CL_DisplayMode> & Graphics::getDisplayModes (void) {
@@ -75,8 +94,11 @@
     }
 
     // dump player debug info on stderr
-    if ((flags & GUI_INPUT_DEBUG_PLAYER) && state.getLocalPlayer())
+    if ((flags & GUI_INPUT_DEBUG_PLAYER) && state.getLocalPlayer()) {
         state.getLocalPlayer()->printDebugInfo();
+        
+        message_view.add_message(CL_Color::green, "...");
+    }
     
     // toggle fullscreen?
     if (flags & GUI_INPUT_TOGGLE_FULLSCREEN) {
@@ -128,11 +150,14 @@
 
     // Draw the game
     state.draw(this, camera, flags & GUI_INPUT_DISPLAY_WEAPON);
-
+    
+    // draw player info box
     if (player != NULL) {
-        // draw player info box
         draw_player_info(gc, player);
     }
+    
+    // draw messages
+    message_view.draw(this);
 
     // Flip window buffer, sync
     flip(1);
@@ -261,5 +286,14 @@
         p->getCurrentWeapon()->getName(),
         get_gc()
     );
+
 }
 
+    
+void Graphics::on_player_joined (Player *p) {
+    message_view.add_message(CL_Color::white, " *** Player joined");
+}
+    
+void Graphics::on_player_left (Player *p) {
+    message_view.add_message(CL_Color::white, " *** Player left");
+}
--- a/src/Graphics.hh	Tue Jan 13 21:36:43 2009 +0200
+++ b/src/Graphics.hh	Tue Jan 13 23:15:47 2009 +0200
@@ -9,6 +9,8 @@
 #include "Engine.hh"
 #include "Config.hh"
 
+#include "GameMessageView.hh"
+
 #include <ClanLib/core.h>
 #include <ClanLib/gl.h>
 #include <ClanLib/display.h>
@@ -17,7 +19,7 @@
  * This handles drawing the GameState with an appropriate camera view each frame, loading fonts, and currently,
  * handling the input from Input to GameState.
  */
-class Graphics : public CL_DisplayWindow {
+class Graphics : public GameStateEventHandler, public CL_DisplayWindow {
 private:
     Engine &engine;
     GameState &state;
@@ -36,6 +38,9 @@
     // basic fonts
     CL_Font simple_font;
 
+    // view components
+    GameMessageView message_view;
+
 public:
     Graphics (Engine &engine, GameState &state, PixelCoordinate resolution, bool fullscreen);
     
@@ -73,6 +78,11 @@
     void on_update (TimeMS tick_length);
     
     void draw_player_info(CL_GraphicContext *gc, Player *p);
+        
+protected:
+    /* GameStateEventHandler */    
+    virtual void on_player_joined (Player *p);
+    virtual void on_player_left (Player *p);
 };
 
 #endif /* GRAPHICS_HH */
--- a/src/Player.hh	Tue Jan 13 21:36:43 2009 +0200
+++ b/src/Player.hh	Tue Jan 13 23:15:47 2009 +0200
@@ -45,7 +45,7 @@
     Timer respawn_timer;
     CL_Slot respawn_slot;
 
-    // XXX: hmm... updated where?
+    // XXX: updated where?
     int animation_step;
 
     //Player stats
--- a/src/Types.hh	Tue Jan 13 21:36:43 2009 +0200
+++ b/src/Types.hh	Tue Jan 13 23:15:47 2009 +0200
@@ -30,6 +30,17 @@
 typedef VectorType<PixelDimension> PixelCoordinate;
 
 /**
+ * A rectangular area of pixels
+ */
+struct PixelArea {
+    PixelDimension left, top, right, bottom;
+
+    PixelArea (PixelDimension left, PixelDimension top, PixelDimension right, PixelDimension bottom) :
+        left(left), top(top), right(right), bottom(bottom)
+    { }
+};
+
+/**
  * A time interval, measured in real milliseconds
  */
 typedef signed long TimeMS;