Was würdet ihr an meinem Programm verändern?
-
Hi,
Nachdem schon mehrere solcher Threads mit guten Tipps erschienen sind, habe ich mir gedacht auch mal so ein Programm zu veröffentlichen. Es ist vielleicht etwas größer, da es ein billiger Tetrisklon ist, den ich vor 2 Monaten geschrieben habe, aber vielleicht nimmt sich ja doch jemand die Zeit einen Blick drauf zu werfen, wäre nett.// ---------main.cpp--------------- #include <iostream> #include <cstdlib> #include <ctime> #include <boost/function.hpp> #include <boost/bind.hpp> #include "window.hpp" #include "playing_field.hpp" using namespace std; using namespace boost; int const window_width(800); int const window_height(640); int const game_speed(1); int main() { //Set the time as seed for random numbers srand(static_cast<int>(time(NULL))); //Setup the window and the playing field window win(window_width, window_height); playing_field field(bind(mem_fn(&window::close), &win), window_width, window_height); win.register_render_event_handler(bind(mem_fn(&playing_field::render), &field, _1)); win.register_new_timer_event_handler(bind(mem_fn(&playing_field::move_blocks_down), &field), game_speed); win.register_left_arrow_down_event_handler(bind(mem_fn(&playing_field::move_blocks_left), &field)); win.register_right_arrow_down_event_handler(bind(mem_fn(&playing_field::move_blocks_right), &field)); win.register_up_arrow_down_event_handler(bind(mem_fn(&playing_field::turn_blocks_right), &field)); win.register_down_arrow_real_time_down_event_handler(bind(mem_fn(&playing_field::move_blocks_down), &field)); //Run the mainloop win.main_loop(); } /*! * \file window.hpp * \brief Contains the windowclass * \author XXX */ #ifndef WINDOW_INCLUDED #define WINDOW_INCLUDED #include <list> #include <SFML/System.hpp> #include <SFML/Window.hpp> #include <boost/function.hpp> /*! * \brief Calls a function each X seconds * \details A functor which calls a registered callbackfunction, if a certain time was passed */ class timer_event { public: /*! * \brief Creates the object * \param[in] handler The function which should be called * \param[in] tick The time which has to pass so that the function is called */ timer_event(boost::function<void (timer_event&)> const& handler, int tick); /*! * \brief Checks if the time has passed and if it has passed calls the function */ void check(); /*! * \brief The same as check */ void operator()(); /*! * \brief Stops the timer, so that the function won't be called any more */ void stop(); private: boost::function<void (timer_event&)> m_event; sf::Clock m_timer; int m_tick; bool m_active; }; /*! * \brief Manages the window * \details Creates a window, calls Callbackfunctions to handle input and provides several functions to * deal with the window for example a function which returns the current FPS rate */ class window { public: /*! * \brief Creates and opens the window * \param[in] width The width of the window in pixels * \param[in] height The height of the window in pixels */ window(int width, int height); /*! * \brief Returns the current FPS rate * \return The current FPS rate */ int fps() const; /*! * \brief Calls the draw() function of the given object * \tparam T The type of the object which should be drawn * \param object The object which should be drawn */ template <typename T> void draw(T const& object) const; /*! * \brief The mainloop which keeps the program alive * \details Renders the scene, checks for input and than calls the appropriate eventhandlers */ void main_loop(); /*! * \brief Closes the window and finishes the mainloop */ void close(); /*! * \brief Registers a callbackfunction, which is called everytime when the window has to be redrawn * \param[in] The callbackfunction */ void register_render_event_handler(boost::function<void (window&)> const& render_event); /*! * \brief Registers a new timer * \param[in] timer_event The function which is called when the time has passed * \param[in] tick The time which has to pass */ void register_new_timer_event_handler(boost::function<void (timer_event&)> const& timer_event, int tick); /*! * \brief Registers a callbackfunction, which is called everytime when the left arrow key is pressed * \param[in] left_arrow_down_event The callbackfunction */ void register_left_arrow_down_event_handler(boost::function<void ()> const& left_arrow_down_event); /*! * \brief Registers a callbackfunction, which is called everytime when the right arrow key is pressed * \param[in] right_arrow_down_event The callbackfunction */ void register_right_arrow_down_event_handler(boost::function<void ()> const& right_arrow_down_event); /*! * \brief Registers a callbackfunction, which is called everytime when the up arrow key is pressed * \param[in] up_arrow_down_event The callbackfunction */ void register_up_arrow_down_event_handler(boost::function<void ()> const& up_arrow_down_event); /*! * \brief Registers a callbackfunction, which is called everytime when the down arrow key is pressed, but ignores the operatingsystem delay if you keep pressing the button * \param[in] down_arrow_down_event The callbackfunction */ void register_down_arrow_real_time_down_event_handler(boost::function<void ()> const& down_arrow_down_event); private: void render(); void handle_events(); sf::Window m_window; boost::function<void (window&)> m_render_event; boost::function<void ()> m_left_arrow_down_event; boost::function<void ()> m_right_arrow_down_event; boost::function<void ()> m_up_arrow_down_event; boost::function<void ()> m_down_arrow_real_time_down_event; std::list<timer_event> m_timer_events; }; #include "window.tmpl" #endif // ----------- window.cpp------------------ #include "window.hpp" #include <GL/gl.h> #include <GL/glu.h> using namespace std; using namespace sf; using namespace boost; int const bpp(32); double const bg_r(0.5), bg_g(0.5), bg_b(0.5), bg_a(0); char const * const caption("SFML Test"); window::window(int width, int height) : m_window(VideoMode(width, height, bpp), caption) { m_window.UseVerticalSync(true); //Set up OpenGL glClearColor(bg_r, bg_g, bg_b, bg_a); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluOrtho2D(0, width, height, 0); glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_COLOR_ARRAY); } int window::fps() const { return static_cast<int>(1./m_window.GetFrameTime()); } void window::main_loop() { while(m_window.IsOpened()) { handle_events(); for(list<timer_event>::iterator itr(m_timer_events.begin()), end(m_timer_events.end()); itr != end; itr++) itr->check(); render(); } } void window::close() { m_window.Close(); } void window::render() { glClear(GL_COLOR_BUFFER_BIT); m_render_event(*this); m_window.Display(); } void window::handle_events() { Event event; while(m_window.GetEvent(event)) { switch(event.Type) { case Event::Closed: m_window.Close(); break; case Event::KeyPressed: switch(event.Key.Code) { case Key::Left: if(m_left_arrow_down_event) m_left_arrow_down_event(); break; case Key::Right: if(m_right_arrow_down_event) m_right_arrow_down_event(); break; case Key::Up: if(m_up_arrow_down_event) m_up_arrow_down_event(); break; } break; } } if(m_window.GetInput().IsKeyDown(Key::Down) && m_down_arrow_real_time_down_event) m_down_arrow_real_time_down_event(); } void window::register_render_event_handler(function<void (window&)> const& handler) { m_render_event = handler; } void window::register_new_timer_event_handler(function<void (timer_event&)> const& handler, int tick) { m_timer_events.push_back(timer_event(handler, tick)); } void window::register_left_arrow_down_event_handler(function<void ()> const& left_arrow_down_event) { m_left_arrow_down_event = left_arrow_down_event; } void window::register_right_arrow_down_event_handler(function<void ()> const& right_arrow_down_event) { m_right_arrow_down_event = right_arrow_down_event; } void window::register_up_arrow_down_event_handler(function<void ()> const& up_arrow_down_event) { m_up_arrow_down_event = up_arrow_down_event; } void window::register_down_arrow_real_time_down_event_handler(function<void ()> const& down_arrow_down_event) { m_down_arrow_real_time_down_event = down_arrow_down_event; } timer_event::timer_event(function<void (timer_event&)> const& handler, int tick) : m_event(handler), m_tick(tick), m_active(true) { } void timer_event::check() { if(m_timer.GetElapsedTime() >= m_tick && m_active) { m_event(*this); m_timer.Reset(); } } void timer_event::stop() { m_active = false; } void timer_event::operator()() { check(); } //-----window.tmpl-------- template <typename T> void window::draw(T const& object) const { object.draw(); } /*! * \file util.hpp * \author XXX * \brief Contains usefull structures */ #ifndef UTIL_INCLUDED #define UTIL_INCLUDED #include <GL/gl.h> /*! * \brief Contains a color in form of three float values(r,g,b) */ struct color { GLfloat r, g, b; }; /*! * \brief Contains a position and a size */ struct rectangle { GLshort x, y, width, height; }; /*! * \brief compares two rectangles * \param[in] rect1 The first rectangle * \param[in] rect2 The second rectangle * \return If they are equal */ bool operator==(rectangle const& rect1, rectangle const& rect2); #endif // -------util.cpp--------- #include "util.hpp" bool operator==(rectangle const& rect1, rectangle const& rect2) { if(rect1.x == rect2.x && rect1.y == rect2.y && rect1.width == rect2.width && rect1.height == rect2.height) return true; return false; } /*! * \file playing_field.hpp * \author XXX * \brief Contains the playing field */ #ifndef PLAYING_FIELD_INCLUDED #define PLAYING_FIELD_INCLUDED #include <vector> #include <list> #include <boost/function.hpp> #include "window.hpp" #include "block_complex.hpp" /*! * \brief Manages the playing field which is the basic drawing area and contains the basic game code */ class playing_field { public: /*! * \brief Creates the playing field * \details Initializes all members and fills the vertex and indexarrays of OpenGL * \param[in] close_window_method A callback function which is called when the window should be closed * \param[in] window_width The width of the window in pixels * \param[in] window_height The height of the window in pixels * \param[in] width The number of columns * \param[in] height The number of rows */ playing_field( boost::function<void ()> const& close_window_method, int window_width, int window_height, int width = 14, int height = 20); /*! * \brief Redraws the whole game on the targetwindow * \param[in] target The targetwindow */ void render(window& target) const; /*! * \brief Draws only the playing field */ void draw() const; /*! * \brief Moves the current active blocks one row down * \details Moves the current active blockcomplex one row down, if there's no active blockcomplex it * creates one with a random shape, if it can't be created this function calls the * loosefunction. This function is also responsible for releasing the active block and * suspending full rows */ void move_blocks_down(); /*! * \brief Moves the current active blocks one column left */ void move_blocks_left(); /*! * \brief Moves the current active blocks one column right */ void move_blocks_right(); /*! * \brief Turns the current active blocks clockwise */ void turn_blocks_right(); private: void setup_ogl_arrays(); void update_row_information(); void loose(); void create_new_block(); std::vector<GLshort> m_vertices; std::vector<GLubyte> m_vertex_indices; std::vector<GLfloat> m_colors; std::list<block> m_blocks; std::vector<std::vector<bool> > m_rows; block_complex m_current_block_complex; int m_rows_suspended; boost::function<void ()> m_close_window; int const m_width; int const m_height; int const m_window_width; int const m_window_height; }; /*! * \relatesalso block_complex * \brief Checks if all blocks of a block complex can move in a specified direction * \param[in] begin An iterator to the first block * \param[in] end An iterator to the last block * \param[in] field Information about which fields are blocked and which are not * \param[in] down Describes how many fields it should move downwards * \param[in] right Describes how many field it should move in the right direction */ bool can_move( block_complex::const_iterator begin, block_complex::const_iterator end, std::vector<std::vector<bool> > const& field, int down, int right); /*! * \relatesalso playing_field * \brief Sets the information about which fields are blocked and which are not * \param[in] blocks The list of all blocks * \param[out] rows The information about the fields */ void refresh_rows( std::list<block> const& blocks, std::vector<std::vector<bool> >& rows); /*! * \relatesalso playing_field * \brief Checks if there is a full line and suspends it * \param[in] rows Informationa about the field * \param[out] blocks A list with all blocks * \return If a line was suspended */ bool suspend_next_full_line( std::vector<std::vector<bool> > const& rows, std::list<block>& blocks); /*! * \relatesalso playing_field * \brief Checks if a row is full * \param[in] row The row which should be checked * \return If the row is full */ bool row_full(std::vector<bool> const& row); #endif //---------------playing_field.cpp----------- #include "playing_field.hpp" #include <stack> #include <iostream> #include <cstdlib> #include "util.hpp" #include "block_complex.hpp" int const number_of_vertices(4); int const posvar_per_vertex(2); int const colorvar_per_vertex(3); int const number_of_indices(6); int const block_size(32); int const block_startup_x(5); int const block_startup_y(3); float const black(0.9); using namespace std; using namespace boost; playing_field::playing_field(function<void ()> const& close_window_method, int window_width, int window_height, int width, int height) : m_window_width(window_width), m_window_height(window_height), m_width(width), m_height(height), m_vertices(number_of_vertices * posvar_per_vertex), m_vertex_indices(number_of_indices), m_colors(number_of_vertices * colorvar_per_vertex), m_rows(height, std::vector<bool>(width)), m_rows_suspended(0), m_close_window(close_window_method) { setup_ogl_arrays(); } void playing_field::render(window& target) const { target.draw(*this); if(m_current_block_complex.is_valid()) target.draw(m_current_block_complex); for(list<block>::const_iterator itr(m_blocks.begin()), end(m_blocks.end()); itr != end; itr++) target.draw(*itr); } void playing_field::draw() const { glVertexPointer(posvar_per_vertex, GL_SHORT, posvar_per_vertex*sizeof(GLshort), &m_vertices[0]); glColorPointer(colorvar_per_vertex, GL_FLOAT, colorvar_per_vertex*sizeof(GLfloat), &m_colors[0]); glDrawElements(GL_TRIANGLES, number_of_indices, GL_UNSIGNED_BYTE, &m_vertex_indices[0]); } void playing_field::move_blocks_down() { if(m_current_block_complex.is_valid()) { if(can_move(m_current_block_complex.begin(), m_current_block_complex.end(), m_rows, 1, 0)) m_current_block_complex.move_down(); else { list<block> blocks(m_current_block_complex.disassemble()); m_blocks.insert(m_blocks.end(), blocks.begin(), blocks.end()); refresh_rows(m_blocks, m_rows); while(suspend_next_full_line(m_rows, m_blocks)) { m_rows_suspended++; refresh_rows(m_blocks, m_rows); } } } else { create_new_block(); if(!can_move(m_current_block_complex.begin(), m_current_block_complex.end(), m_rows, 0, 0)) loose(); } } void playing_field::create_new_block() { int type(rand() % 7); switch(type) { case 0: m_current_block_complex = create_long(block_size, block_size, block_startup_x*block_size, block_startup_y*block_size); break; case 1: m_current_block_complex = create_block(block_size, block_size, block_startup_x*block_size, block_startup_y*block_size); break; case 2: m_current_block_complex = create_rostrum(block_size, block_size, block_startup_x*block_size, block_startup_y*block_size); break; case 3: m_current_block_complex = create_reverse_L(block_size, block_size, block_startup_x*block_size, block_startup_y*block_size); break; case 4: m_current_block_complex = create_L(block_size, block_size, block_startup_x*block_size, block_startup_y*block_size); break; case 5: m_current_block_complex = create_stairs_up_is_right(block_size, block_size, block_startup_x*block_size, block_startup_y*block_size); break; case 6: m_current_block_complex = create_stairs_up_is_left(block_size, block_size, block_startup_x*block_size, block_startup_y*block_size); break; } } void playing_field::loose() { //as soon as I know how to print text with OpenGL, I will use an appropriate game over sequence cout << "You lost after suspending " << m_rows_suspended << " lines" << endl; if(m_close_window) m_close_window(); } void playing_field::move_blocks_left() { if(m_current_block_complex.is_valid()) { if(can_move(m_current_block_complex.begin(), m_current_block_complex.end(), m_rows, 0, -1)) m_current_block_complex.move_left(); } } void playing_field::move_blocks_right() { if(m_current_block_complex.is_valid()) { if(can_move(m_current_block_complex.begin(), m_current_block_complex.end(), m_rows, 0, 1)) m_current_block_complex.move_right(); } } void playing_field::turn_blocks_right() { if(m_current_block_complex.is_valid()) { m_current_block_complex.turn_right(); if(!can_move(m_current_block_complex.begin(), m_current_block_complex.end(), m_rows, 0, 0)) m_current_block_complex.turn_left(); } } void playing_field::setup_ogl_arrays() { int inner_width(m_width * block_size); int inner_height(m_height * block_size); int upper_space(m_window_height - inner_height); int right_space(m_window_width - inner_width); //0 the inner rectangle m_vertices[0] = 0; // X m_vertices[1] = upper_space; // Y //1 m_vertices[2] = inner_width; m_vertices[3] = upper_space; //2 m_vertices[4] = 0; m_vertices[5] = inner_height + upper_space; //3 m_vertices[6] = inner_width; m_vertices[7] = inner_height + upper_space; //color: inner rect for(int i(0); i < 12; i++) m_colors[i] = black; //indices: inner rect m_vertex_indices[0] = 0; m_vertex_indices[1] = 1; m_vertex_indices[2] = 2; m_vertex_indices[3] = 1; m_vertex_indices[4] = 2; m_vertex_indices[5] = 3; } bool can_move( block_complex::const_iterator begin, block_complex::const_iterator end, vector<vector<bool> > const& field, int down, int right) { bool result(true); for(block_complex::const_iterator itr(begin); itr != end; itr++) if(itr->position().y/itr->position().height + down >= field.size() || itr->position().x/itr->position().width + right >= field[0].size() || itr->position().x/itr->position().width + right < 0 || field[itr->position().y/itr->position().height + down] [itr->position().x/itr->position().width + right]) { result = false; break; } return result; } void refresh_rows( list<block> const& blocks, vector<vector<bool> >& rows) { rows = vector<vector<bool> >(rows.size(), vector<bool>(rows[0].size(), false)); for(list<block>::const_iterator itr(blocks.begin()), end(blocks.end()); itr != end; itr++) rows[itr->position().y/itr->position().height][itr->position().x/itr->position().width] = true; } bool row_full(vector<bool> const& row) { bool result(true); for(vector<bool>::const_iterator itr(row.begin()), end(row.end()); itr != end; itr++) if(!*itr) { result = false; break; } return result; } bool suspend_next_full_line( vector<vector<bool> > const& rows, list<block>& blocks) { int row(0); for(vector<vector<bool> >::const_iterator row_itr(rows.begin()), row_end(rows.end()); row_itr != row_end; row_itr++,row++) { stack<block> to_remove; if(row_full(*row_itr)) { for(list<block>::iterator block_itr(blocks.begin()), block_end(blocks.end()); block_itr != block_end; block_itr++) if(block_itr->position().y/block_itr->position().height == row) to_remove.push(*block_itr); else if(block_itr->position().y/block_itr->position().height < row) move_down(*block_itr); while(!to_remove.empty()) { blocks.erase(find(blocks.begin(), blocks.end(), to_remove.top())); to_remove.pop(); }; return true; } } return false; } /*! * \file block.hpp * \author XXX * \brief Contains code that manages a single block */ #ifndef BLOCK_INCLUDED #define BLOCK_INCLUDED #include <vector> #include <GL/gl.h> #include "util.hpp" /*! * \brief Manages a single block */ class block { public: /*! * \brief Creates the block * \details Initializes all members and sets up the vertexdata * \param[in] position The position on which the block should be created and its size in pixels * \param[in] block_color The color of the block */ block(rectangle const& position, color const& block_color); /*! * \brief Draws the block */ void draw() const; /*! * \brief Moves the block to a certain position * \param[in] x The new x coordinate in pixels * \param[in] y The new y coordinate in pixels */ void move(int x, int y); /*! * \brief Returns the position and size of the block * \return The position and size of the block */ rectangle position() const; private: void setup_arrays(color const& block_color); void setup_vertex_array(); rectangle m_position; std::vector<GLshort> m_vertices; std::vector<GLubyte> m_vertex_indices; std::vector<GLfloat> m_colors; }; /*! * \brief Compares 2 blocks * \param[in] blck1 The first block * \param[in] blck2 The second block * \return If they are equal */ bool operator==(block const& blck1, block const& blck2); /*! * \relates block * \brief moves a block one field down without checking if that is possible */ void move_down(block& blck); /*! * \relates block * \brief moves a block one field left without checking if that is possible */ void move_left(block& blck); /*! * \relates block * \brief moves a block one field right without checking if that is possible */ void move_right(block& blck); #endif // ---------Block.cpp----------- #include "block.hpp" int const number_of_vertices(4); int const posvar_per_vertex(2); int const colorvar_per_vertex(3); int const number_of_indices(6); using namespace std; block::block(rectangle const& position, color const& block_color) : m_position(position), m_vertices(number_of_vertices * posvar_per_vertex), m_vertex_indices(number_of_indices), m_colors(number_of_vertices * colorvar_per_vertex) { setup_arrays(block_color); } void block::setup_arrays(color const& block_color) { setup_vertex_array(); //Indices m_vertex_indices[0] = 0; m_vertex_indices[1] = 1; m_vertex_indices[2] = 2; m_vertex_indices[3] = 1; m_vertex_indices[4] = 2; m_vertex_indices[5] = 3; //Color for(vector<GLfloat>::iterator itr(m_colors.begin()), end(m_colors.end()); itr != end; itr++) { *itr = block_color.r; itr++; *itr = block_color.g; itr++; *itr = block_color.b; } } void block::setup_vertex_array() { //0 m_vertices[0] = m_position.x; m_vertices[1] = m_position.y; //1 m_vertices[2] = m_position.x + m_position.width; m_vertices[3] = m_position.y; //2 m_vertices[4] = m_position.x; m_vertices[5] = m_position.y + m_position.height; //3 m_vertices[6] = m_position.x + m_position.width; m_vertices[7] = m_position.y + m_position.height; } void block::draw() const { glVertexPointer(posvar_per_vertex, GL_SHORT, posvar_per_vertex*sizeof(GLshort), &m_vertices[0]); glColorPointer(colorvar_per_vertex, GL_FLOAT, colorvar_per_vertex*sizeof(GLfloat), &m_colors[0]); glDrawElements(GL_TRIANGLES, number_of_indices, GL_UNSIGNED_BYTE, &m_vertex_indices[0]); } rectangle block::position() const { return m_position; } void block::move(int x, int y) { m_position.x = x; m_position.y = y; setup_vertex_array(); } void move_down(block& blck) { rectangle pos(blck.position()); blck.move(pos.x, pos.y + pos.height); } void move_left(block& blck) { rectangle pos(blck.position()); blck.move(pos.x - pos.width, pos.y); } void move_right(block& blck) { rectangle pos(blck.position()); blck.move(pos.x + pos.width, pos.y); } bool operator==(block const& blck1, block const& blck2) { if(blck1.position() == blck2.position()) return true; return false; } /*! * \file block_complex.hpp * \author XXX * \brief Contains code which manages multiple blocks as a "block_complex" */ #ifndef BLOCK_COMPLEX_INCLUDED #define BLOCK_COMPLEX_INCLUDED #include <list> #include "block.hpp" #include "util.hpp" /*! * \brief Manages multiple blocks in a block_complex */ class block_complex { public: /*! * \brief Creates an invalid block_complex */ block_complex(); /*! * \brief Creates a valid block_complex * \details Creates all blocks by the parameters * \param[in] form The form of the block in a 4*4 field * \param[in] block_width The width of each block * \param[in] block_height The height of each block * \param[in] col The color of each block * \param[in] center_x The x coordinate of the centered field in the 4*4 field * \param[in] center_y The y coordniate of the centered field in the 4*4 field * \param[in] center_x_pos The x coordinate of the centered field in the playing field * \param[in] center_y_pos The y coordinate of the centered field in the playing field */ block_complex( bool form[4][4], int block_width, int block_height, color const& col, int center_x, int center_y, int center_x_pos, int center_y_pos); /*! * \brief Returns a constant iterator to the first block * \return The iterator */ std::list<block>::const_iterator begin() const; /*! * \brief Returns a constant iterator to the last block * \return The iterator */ std::list<block>::const_iterator end() const; /*! * \brief An iterator to a block */ typedef std::list<block>::const_iterator const_iterator; /*! * \brief Returns the blocks and makes the block_complex invalid * \return All blocks of the complex */ std::list<block> disassemble(); /*! * \brief Draws all blocks */ void draw() const; /*! * \brief Turns the block_complex clockwise */ void turn_right(); /*! * \brief Turns the block_complex counterclockwise */ void turn_left(); /*! * \brief Moves the block_complex one field downwards */ void move_down(); /*! * \brief Moves the block_complex one field in the left direction */ void move_left(); /*! * \brief Moves the block_complex one field right direction */ void move_right(); /*! * \brief Returns if the block_complex is valid * \return If the block_complex is valid */ bool is_valid() const; private: bool m_valid; int m_center_x_pos, m_center_y_pos; std::list<block> m_blocks; }; /* * ++++ */ /*! * \brief Creates a long block_complex * \param[in] block_width The width of each block * \param[in] block_height The height of each block * \param[in] center_x_pos The x coordinate of the block_complex * \param[in] center_y_pos The y coordinate of the block_complex * \return The new block_complex */ block_complex create_long(int block_width, int block_height, int center_x_pos, int center_y_pos); /* * ++ * ++ */ /*! * \brief Creates a blocklike block_complex * \param[in] block_width The width of each block * \param[in] block_height The height of each block * \param[in] center_x_pos The x coordinate of the block_complex * \param[in] center_y_pos The y coordinate of the block_complex * \return The new block_complex */ block_complex create_block(int block_width, int block_height, int center_x_pos, int center_y_pos); /* * + * +++ */ /*! * \brief Creates a rostrumlike block_complex * \param[in] block_width The width of each block * \param[in] block_height The height of each block * \param[in] center_x_pos The x coordinate of the block_complex * \param[in] center_y_pos The y coordinate of the block_complex * \return The new block_complex */ block_complex create_rostrum(int block_width, int block_height, int center_x_pos, int center_y_pos); /* * + * + * ++ */ /*! * \brief Creates a block_complex which looks like a reverse L * \param[in] block_width The width of each block * \param[in] block_height The height of each block * \param[in] center_x_pos The x coordinate of the block_complex * \param[in] center_y_pos The y coordinate of the block_complex * \return The new block_complex */ block_complex create_reverse_L(int block_width, int block_height, int center_x_pos, int center_y_pos); /* * + * + * ++ */ /*! * \brief Creates a block_complex which looks like a L * \param[in] block_width The width of each block * \param[in] block_height The height of each block * \param[in] center_x_pos The x coordinate of the block_complex * \param[in] center_y_pos The y coordinate of the block_complex * \return The new block_complex */ block_complex create_L(int block_width, int block_height, int center_x_pos, int center_y_pos); /* * ++ * ++ */ /*! * \brief Creates a stairslike block_complex * \param[in] block_width The width of each block * \param[in] block_height The height of each block * \param[in] center_x_pos The x coordinate of the block_complex * \param[in] center_y_pos The y coordinate of the block_complex * \return The new block_complex */ block_complex create_stairs_up_is_right(int block_width, int block_height, int center_x_pos, int center_y_pos); /* * ++ * ++ */ /*! * \brief Creates another stairslike block_complex * \param[in] block_width The width of each block * \param[in] block_height The height of each block * \param[in] center_x_pos The x coordinate of the block_complex * \param[in] center_y_pos The y coordinate of the block_complex * \return The new block_complex */ block_complex create_stairs_up_is_left(int block_width, int block_height, int center_x_pos, int center_y_pos); #endif //-----block_complex.cpp-------- #include "block_complex.hpp" #include <algorithm> using namespace std; block_complex::block_complex() : m_valid(false) {} block_complex::block_complex( bool form[4][4], int block_width, int block_height, color const& col, int center_x, int center_y, int center_x_pos, int center_y_pos) : m_center_x_pos(center_x_pos), m_center_y_pos(center_y_pos), m_valid(true) { for(int x(0); x < 4; x++) for(int y(0); y < 4; y++) if(form[y][x]) { rectangle pos = {center_x_pos - ((center_x - x) * block_width), center_y_pos - ((center_y - y) * block_height), block_width, block_height}; m_blocks.push_back(block(pos, col)); } } bool block_complex::is_valid() const { return m_valid; } void block_complex::draw() const { for(list<block>::const_iterator itr(m_blocks.begin()), end(m_blocks.end()); itr != end; itr++) itr->draw(); } void block_complex::turn_right() { for(list<block>::iterator itr(m_blocks.begin()), end(m_blocks.end()); itr != end; itr++) { itr->move(m_center_x_pos + itr->position().y - m_center_y_pos, m_center_y_pos - (itr->position().x - m_center_x_pos)); } } void block_complex::turn_left() { for(list<block>::iterator itr(m_blocks.begin()), end(m_blocks.end()); itr != end; itr++) { itr->move(m_center_x_pos - (itr->position().y - m_center_y_pos), m_center_y_pos + (itr->position().x - m_center_x_pos)); } } list<block>::const_iterator block_complex::begin() const { return m_blocks.begin(); } list<block>::const_iterator block_complex::end() const { return m_blocks.end(); } list<block> block_complex::disassemble() { m_valid = false; return m_blocks; } void block_complex::move_down() { for_each(m_blocks.begin(), m_blocks.end(), &::move_down); m_center_y_pos += m_blocks.begin()->position().height; } void block_complex::move_left() { for_each(m_blocks.begin(), m_blocks.end(), &::move_left); m_center_x_pos -= m_blocks.begin()->position().width; } void block_complex::move_right() { for_each(m_blocks.begin(), m_blocks.end(), &::move_right); m_center_x_pos += m_blocks.begin()->position().width; } block_complex create_long(int block_width, int block_height, int center_x_pos, int center_y_pos) { bool form[4][4] = { {0, 0, 1, 0}, {0, 0, 1, 0}, {0, 0, 1, 0}, {0, 0, 1, 0}}; color col = {0, 0, 1}; return block_complex(form, block_width, block_height, col, 2, 2, center_x_pos, center_y_pos); } block_complex create_block(int block_width, int block_height, int center_x_pos, int center_y_pos) { bool form[4][4] = { {0, 0, 0, 0}, {0, 1, 1, 0}, {0, 1, 1, 0}, {0, 0, 0, 0}}; color col = {0, 1, 1}; return block_complex(form, block_width, block_height, col, 2, 2, center_x_pos, center_y_pos); } block_complex create_rostrum(int block_width, int block_height, int center_x_pos, int center_y_pos) { bool form[4][4] = { {0, 0, 0, 0}, {0, 0, 1, 0}, {0, 1, 1, 1}, {0, 0, 0, 0}}; color col = {0, 0, 0.4}; return block_complex(form, block_width, block_height, col, 2, 2, center_x_pos, center_y_pos); } block_complex create_reverse_L(int block_width, int block_height, int center_x_pos, int center_y_pos) { bool form[4][4] = { {0, 0, 0, 0}, {0, 0, 1, 0}, {0, 0, 1, 0}, {0, 1, 1, 0}}; color col = {0, 1, 0}; return block_complex(form, block_width, block_height, col, 2, 3, center_x_pos, center_y_pos); } block_complex create_L(int block_width, int block_height, int center_x_pos, int center_y_pos) { bool form[4][4] = { {0, 0, 0, 0}, {0, 0, 1, 0}, {0, 0, 1, 0}, {0, 0, 1, 1}}; color col = {1, 0, 0}; return block_complex(form, block_width, block_height, col, 2, 3, center_x_pos, center_y_pos); } block_complex create_stairs_up_is_right(int block_width, int block_height, int center_x_pos, int center_y_pos) { bool form[4][4] = { {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 1, 1}, {0, 1, 1, 0}}; color col = {1, 1, 0}; return block_complex(form, block_width, block_height, col, 2, 3, center_x_pos, center_y_pos); } block_complex create_stairs_up_is_left(int block_width, int block_height, int center_x_pos, int center_y_pos) { bool form[4][4] = { {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 1, 1, 0}, {0, 0, 1, 1}}; color col = {0.5, 0.5, 0.4}; return block_complex(form, block_width, block_height, col, 2, 3, center_x_pos, center_y_pos); }