рдЖрдЬ, рдЬреИрд╕рд╛ рдХрд┐ рдореИрдВрдиреЗ рд╡рд╛рджрд╛ рдХрд┐рдпрд╛ рдерд╛, рд╣рдо рдЕрдкрдиреЗ
рдЖрд░реНрдХрд╛рдиреЙрдпрдб рдЬреАрд╡рди рдореЗрдВ рд╕рд╛рдВрд╕ рд▓реЗрдВрдЧреЗред рддреЛрдбрд╝рддреЗ рд╕рдордп рдИрдВрдЯреЛрдВ рдФрд░ рдИрдВрдЯреЛрдВ рд╕реЗ рдЯрдХрд░рд╛рддреЗ рд╣реБрдП рдЧреЗрдВрдж рдХреЛ рдЪрд▓рдиреЗ рджреЗрдВред рд╕рд┐рджреНрдзрд╛рдВрдд рд░реВрдк рдореЗрдВ, arcanoid рдореЗрдВ рдЦреЗрд▓ рднреМрддрд┐рдХреА рдЕрдкрдиреЗ рдЖрдк рдореЗрдВ рдмрд╣реБрдд рдЬрдЯрд┐рд▓ рдФрд░ рдХрд╛рдлреА рд╕рдВрднрд╡ рдирд╣реАрдВ рд╣реИред рдЗрд╕рдореЗрдВ рдПрдХрдорд╛рддреНрд░ рдЧреИрд░-рддреБрдЪреНрдЫ рдХреНрд╖рдг рдЯрдХрд░рд╛рд╡ рдЯреНрд░реИрдХрд┐рдВрдЧ рд╣реИред рд▓реЗрдХрд┐рди рдпрд╣ рд╡рд╣реА рд╣реИ рдЬреЛ "рд╡рдпрд╕реНрдХ" рднреМрддрд┐рдХ рдЗрдВрдЬрди рд╕рдмрд╕реЗ рдЕрдЪреНрдЫрд╛ рдХрд░ рд╕рдХрддрд╛ рд╣реИ!
рддреЛ рдХреНрдпреЛрдВ рдирд╣реАрдВ рдЙрдирдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВ? рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, рдЕрдЧрд░ рд╣рдо Box2D рдХреЛ рдПрдХ
рдореБрд░рдмреНрдмрд╛ рдореЙрдбреНрдпреВрд▓ рдХреЗ рд░реВрдк рдореЗрдВ рдбрд┐рдЬрд╝рд╛рдЗрди рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рдмрд╛рдж рдореЗрдВ, рд╣рдо рдЗрд╕реЗ рдЕрдиреНрдп рдЕрдиреБрдкреНрд░рдпреЛрдЧреЛрдВ рдореЗрдВ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рдЬрд┐рд╕рдХреЗ рд▓рд┐рдП рдЕрдзрд┐рдХ рдкрд░рд┐рд╖реНрдХреГрдд "рднреМрддрд┐рдХреА" рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛ рд╕рдХрддреА рд╣реИред рдЪрд▓реЛ рдХрд░рддреЗ рд╣реИрдВред
Box2D рдХреЛ рдПрдХ рдЙрдкрдкреНрд░реЛрдЬреЗрдХреНрдЯ рдХреЗ рд░реВрдк рдореЗрдВ рдбрд┐рдЬрд╛рдЗрди рдХрд░рдиреЗ рдХреА рддрдХрдиреАрдХ рдкреВрд░реА рддрд░рд╣ рд╕реЗ рдЙрд╕реА рдХреЗ рд╕рдорд╛рди рд╣реИ рдЬрд┐рд╕реЗ рд╣рдордиреЗ рдкрд┐рдЫрд▓реЗ
рд▓реЗрдЦ рдореЗрдВ LibYAML рдХреЗ рд╕рд╛рде рдкреНрд░рдпреЛрдЧ рдХрд┐рдпрд╛ рдерд╛ред рдЕрдВрддрд░ рдХреЗрд╡рд▓ рдЗрддрдирд╛ рд╣реИ рдХрд┐ Box2D рдореЗрдВ рдмрд╣реБрдд рдЕрдзрд┐рдХ рд╕реНрд░реЛрдд рдлрд╛рдЗрд▓реЗрдВ рд╣реИрдВред рдЗрд╕рд▓рд┐рдП, рдЕрдЧрд░ рдореЗрд░реЗ рджреНрд╡рд╛рд░рд╛ рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдХрд┐рдП рдЧрдП mkf рдлрд╝рд╛рдЗрд▓ рдореЗрдВ рдЙрдирдХреЗ рдирд╛рдореЛрдВ рдХреА рдирд┐рдпрдорд┐рдд рдкреБрдирд░реНрд▓реЗрдЦрди рдХреЛ рджреЛрд╣рд░рд╛рдиреЗ рдХреА рдХреЛрдИ рдЗрдЪреНрдЫрд╛ рдирд╣реАрдВ рд╣реИ, рддреЛ рдЖрдк рддреИрдпрд╛рд░ рдореЙрдбреНрдпреВрд▓ рдХреЛ рд╕реАрдзреЗ
GitHub рд╕реЗ рд▓реЗ рд╕рдХрддреЗ рд╣реИрдВред Box2D рд╡рд┐рддрд░рдг
рдпрд╣рд╛рдБ рд╕реЗ рд▓рд┐рдпрд╛
рдЧрдпрд╛ ред
рддреЛ, рд╣рдо рдЕрдкрдиреЗ рдкреНрд░реЛрдЬреЗрдХреНрдЯ рдореЗрдВ Box2D рдЬреЛрдбрд╝рддреЗ рд╣реИрдВ:
arcanoid.mkb#!/usr/bin/env mkb options { module_path="../yaml" + module_path="../box2d" } subprojects { iwgl yaml + box2d } includepath { ./source/Main ./source/Model } files { [Main] (source/Main) Main.cpp Main.h Quads.cpp Quads.h Desktop.cpp Desktop.h IO.cpp IO.h [Model] (source/Model) Bricks.cpp Bricks.h Ball.cpp Ball.h Board.cpp Board.h } assets { (data) level.json }
... рдФрд░ рд╣рдо рдЗрд╕ рд╕рдм рдХреЛ рд╕рдВрдХрд▓рд┐рдд рдХрд░рдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХрд░ рд░рд╣реЗ рд╣реИрдВ, рд╕рд╛рде рд╣реА '' рдЪрд▓реЛ рдХрдВрдкрд╛рдЗрд▓рд░ рдХреЛ рдЦреБрд╢ рдХрд░рддреЗ рд╣реИрдВ '' 'рд╢реНрд░реЗрдгреА рдореЗрдВ рдХреЙрд╕реНрдореЗрдЯрд┐рдХ рд╕реБрдзрд╛рд░реЛрдВ рдХреЛ рд╢реБрд░реВ рдХрд░рддреЗ рд╣реБрдП:
рдЯрдХрд░рд╛рд╡ \ b2BroadPhase.h - for (int32 i = 0; i < m_moveCount; ++i) + for (int32 j = 0; j < m_moveCount; ++j) { - m_queryProxyId = m_moveBuffer[i]; + m_queryProxyId = m_moveBuffer[j]; ... } ... while (i < m_pairCount) { ... }
рдЖрдо \ b2Math.h /// A 2D column vector. struct b2Vec2 { /// Default constructor does nothing (for performance). - b2Vec2() {} + b2Vec2(): x(0.0f), y(0.0f) {} /// Construct using coordinates. b2Vec2(float32 x, float32 y) : x(x), y(y) {} ... float32 x, y; };
рдпрджрд┐ рдЙрд╕рдХреЗ рдмрд╛рдж рднреА рдЖрдкрдХреЛ рдХреЛрдИ рддреНрд░реБрдЯрд┐ рдорд┐рд▓рддреА рд╣реИ:

... рддреЛ рдпрд╣ рд╕рдмрд╕реЗ рдЕрдзрд┐рдХ рд╕рдВрднрд╛рд╡рдирд╛ рд╣реИ рдХрд┐ рдЖрдк, рдореЗрд░реА рддрд░рд╣, MSVS 2003 рдХреА рддрд░рд╣ред рдЬреАрд╕реАрд╕реА, рдПрдХ рд╣реА рд╕рдордп рдореЗрдВ, рддреНрд░реБрдЯрд┐рдпреЛрдВ рдХреЗ рдмрд┐рдирд╛ рдкрд░рд┐рдпреЛрдЬрдирд╛ рдПрдХрддреНрд░ рдХрд░рддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рд╣рдо рдирд┐рд╢реНрдЪрд┐рдд рд░реВрдк рд╕реЗ, рдЗрд╕реЗ рдбрд┐рдмрдЧрд░ рдХреЗ рддрд╣рдд рднреА рдЪрд▓рд╛рдиреЗ рдореЗрдВ рд╕рдХреНрд╖рдо рд╣реЛрдирд╛ рдЪрд╛рд╣реЗрдВрдЧреЗред рдЬреИрд╕рд╛ рдХрд┐ рдпрд╣ рд╣реЛ рд╕рдХрддрд╛ рд╣реИ, MSVS 2003 рдХреЛ рдЫреЛрдбрд╝рдирд╛ рд╣реЛрдЧрд╛ред рд╕рд┐рджреНрдзрд╛рдВрдд рд░реВрдк рдореЗрдВ, рдпрд╣ MSVS 2005 рдкрд░ рд╕реНрд╡рд┐рдЪ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдкрд░реНрдпрд╛рдкреНрдд рд╣реИ, рд▓реЗрдХрд┐рди рдореИрдВрдиреЗ рддреБрд░рдВрдд MSVS 2010 рд╕реНрдерд╛рдкрд┐рдд рдХрд┐рдпрд╛, рдХреНрдпреЛрдВрдХрд┐ рдпрд╣ рд╣рд╛рде рдореЗрдВ рдерд╛ред рдЦреБрдж рдХреЛ рд╕реНрд╡рд┐рдЪ рдХрд░рдирд╛, рдореБрд░рдмреНрдмрд╛ рд╡рд┐рдиреНрдпрд╛рд╕ рдЙрдкрдпреЛрдЧрд┐рддрд╛ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред

рддреЛ рдареАрдХ рд╣реИ, рдпрд╣ рд╡реНрдпрд╛рдкрд╛рд░ рдХреЗ рд▓рд┐рдП рдиреАрдЪреЗ рдЙрддрд░рдиреЗ рдХрд╛ рд╕рдордп рд╣реИред рдпрджрд┐ рдкрд╣рд▓реЗ рд▓реЗрдЦ рдореЗрдВ рд╣рдо "рднреНрд░рдо рдХреА рджреБрдирд┐рдпрд╛" рд╕реЗ рдирд┐рдкрдЯрддреЗ рд╣реИрдВ, рддреЛ рджреВрд╕рд░реЗ рдореЗрдВ "рд╡рд┐рдЪрд╛рд░реЛрдВ рдХреА рджреБрдирд┐рдпрд╛" рдХреЗ рд╕рд╛рде, рдЕрдм рдпрд╣ "рд╡рд╛рд╕реНрддрд╡рд┐рдХ рджреБрдирд┐рдпрд╛" рдмрдирд╛рдиреЗ рдХрд╛ рд╕рдордп рд╣реИ, рдЬрд┐рд╕рдХреЗ рд▓рд┐рдП рд╣рдо рд╡рд╕реНрддреБрдУрдВ рдХреА рднреМрддрд┐рдХ рдмрд╛рддрдЪреАрдд рдХреЗ рд▓рд┐рдП рдЬрд┐рдореНрдореЗрджрд╛рд░ рд╣реЛрдВрдЧреЗред рдкреНрд░реЛрдЬреЗрдХреНрдЯ рдореЗрдВ рдирдИ рдлрд╛рдЗрд▓реЗрдВ рдЬреЛрдбрд╝реЗрдВ:
arcanoid.mkb #!/usr/bin/env mkb options { module_path="../yaml" module_path="../box2d" } subprojects { iwgl yaml box2d } includepath { ./source/Main ./source/Model } files { [Main] (source/Main) Main.cpp Main.h Quads.cpp Quads.h Desktop.cpp Desktop.h IO.cpp IO.h + World.cpp + World.h [Model] (source/Model) Bricks.cpp Bricks.h Ball.cpp Ball.h Board.cpp Board.h + IBox2DItem.h } assets { (data) level.json }
IBox2DItem рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рд╣рдорд╛рд░реЗ рдбреЗрдЯрд╛ рдореЙрдбрд▓ рдХреЗ рд▓рд┐рдП Box2D рд╕реЗ рдШрдЯрдирд╛рдУрдВ рдХреЛ рдкрд╛рд░рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЬрд┐рдореНрдореЗрджрд╛рд░ рд╣реЛрдЧрд╛ред рд╣рдорд╛рд░реЗ рдЙрджреНрджреЗрд╢реНрдпреЛрдВ рдХреЗ рд▓рд┐рдП, рдЬрдмрдХрд┐ рдХреЗрд╡рд▓ рджреЛ рд╡рд┐рдзрд┐рдпрд╛рдБ рдкрд░реНрдпрд╛рдкреНрдд рд╣реИрдВ:
IBox2DItem.h #ifndef _I_BOX2D_ITEM_H_ #define _I_BOX2D_ITEM_H_ #include <Box2D.h> class IBox2DItem { public: virtual void setXY(int X, int Y) {} virtual bool impact(b2Body* b) {return false;} }; #endif // _I_BOX2D_ITEM_H_
рд╣рд╛рдВ, рдореБрдЭреЗ рдкрддрд╛ рд╣реИ рдХрд┐ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдореЗрдВ рдХреЗрд╡рд▓ рд╕рд╛рд░ рд╡рд┐рдзрд┐рдпрд╛рдВ рд╣реЛрдиреА рдЪрд╛рд╣рд┐рдП (рд╢реБрд░реБрдЖрдд рдореЗрдВ рдпрд╣ рдереА), рд▓реЗрдХрд┐рди рдлрд┐рд░ рдпрд╣ рдХреБрдЫ рдбрд┐рдлрд╝реЙрд▓реНрдЯ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдХреЗ рд▓рд┐рдП рдЕрдзрд┐рдХ рд╕реБрд╡рд┐рдзрд╛рдЬрдирдХ рдирд┐рдХрд▓рд╛, рдФрд░ рд╡рд░реНрдЧ рдХрд╛ рдирд╛рдо рдмрджрд▓рдиреЗ рдХреЗ рд▓рд┐рдП рдмрд╣реБрдд рдЖрд▓рд╕реА рдерд╛ред рдХрд┐рд╕реА рднреА рдорд╛рдорд▓реЗ рдореЗрдВ, рд╣рдорд╛рд░реЗ рд▓реЗрдЦ рдХреЗ рд╕рдВрджрд░реНрдн рдореЗрдВ рдпрд╣ рдореБрджреНрджрд╛ рдорд╛рдпрдиреЗ рдирд╣реАрдВ рд░рдЦрддрд╛ рд╣реИред
рд╕реЗрдЯрдПрдХреНрд╕рд╡рд╛рдИ рд╡рд┐рдзрд┐ рд╣рдореЗрдВ рдЪрд▓рддреА рд╡рд╕реНрддреБрдУрдВ рдХреЗ рдирд┐рд░реНрджреЗрд╢рд╛рдВрдХ рдореЗрдВ рдкрд░рд┐рд╡рд░реНрддрди рдкреНрд░рд╕рд╛рд░рд┐рдд рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрдЧрд╛ (рддрд╛рдХрд┐ рдЗрди рдкрд░рд┐рд╡рд░реНрддрдиреЛрдВ рдХреЛ рд╕реНрдХреНрд░реАрди рдкрд░ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХреЗ), рдФрд░ рдкреНрд░рднрд╛рд╡ рд╡рд┐рдзрд┐ рд╣рдореЗрдВ рдереЛрдбрд╝реА рджреЗрд░ рдмрд╛рдж рд╡рд╕реНрддреБрдУрдВ рдХреЗ рдЯрдХрд░рд╛рд╡ рдХреЛ рдЯреНрд░реИрдХ рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрдЧрд╛ред
World.h #ifndef _WORLD_H_ #define _WORLD_H_ #include <vector> #include <Box2D.h> #include "Desktop.h" #include "IBox2DItem.h" const int HALF_MARGIN = 10; const int V_ITERATIONS = 10; const int P_ITERATIONS = 10; const float FRICTION = 0.0f; const float RESTITUTION = 1.0f; const float DYN_DENSITY = 0.0f; const float R_INVIS = 0.0f; const float EPS = 1.0f; const float SPEED_SQ = 10.0f; using namespace std; class World { private: bool isStarted; int HandleX, HandleH, HandleW; uint64 timestamp; int width, height; b2World* wp; b2Body* ground; b2Body* ball; b2Body* handle; b2Body* createBox(int x, int y, int hw, int hh, IBox2DItem* userData = NULL); float32 getTimeStep(); void start(); public: World(): width(0), height(0), wp(NULL) {} void init(); void release(); void update(); void refresh(); b2Body* addBrick(int x, int y, int hw, int hh, IBox2DItem* userData) {return createBox(x, y, hw, hh, userData);} b2Body* addBall(int x, int y, int r, IBox2DItem* userData); b2Body* addHandle(int x, int y, int hw, int hh, IBox2DItem* userData); void moveHandle(int x, int y); typedef vector<b2Body*>::iterator BIter; }; extern World world; #endif // _WORLD_H_
рдЗрд╕ рдореЙрдбреНрдпреВрд▓ рдХреЗ рд▓рд┐рдП, рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдкрд░ рдЕрдзрд┐рдХ рд╡рд┐рд╕реНрддрд╛рд░ рд╕реЗ рд╡рд┐рдЪрд╛рд░ рдХрд░реЗрдВ:
World.cpp #include "s3e.h" #include "World.h" #include "Ball.h" World world; void World::init() { isStarted = false; width = desktop.getWidth(); height = desktop.getHeight(); b2Vec2 gravity(0.0f, 0.0f); wp = new b2World(gravity); ground = createBox(width/2, -HALF_MARGIN, width/2, HALF_MARGIN); createBox(-HALF_MARGIN, height/2, HALF_MARGIN, height/2); createBox(width/2, height + HALF_MARGIN, width/2, HALF_MARGIN); createBox(width + HALF_MARGIN, height/2, HALF_MARGIN, height/2); ball = NULL; handle = NULL; } void World::release() { if (wp != NULL) { delete wp; wp = NULL; ball = NULL; handle = NULL; } } ...
"рджреБрдирд┐рдпрд╛" рдХреА рдореБрдЦреНрдп рд╡рд╕реНрддреБрдУрдВ рдХреЗ рд╕рд╣реА рдирд┐рд░реНрдорд╛рдг рдФрд░ рд╡рд┐рдирд╛рд╢ рдореЗрдВ рдЗрдирд┐рдЯ рдФрд░ рд░рд┐рд▓реАрдЬ рдХреЗ рддрд░реАрдХреЗ рд╢рд╛рдорд┐рд▓ рд╣реИрдВред рдореИрдВ рдЗрд╕ рддрдереНрдп рдкрд░ рдЖрдкрдХрд╛ рдзреНрдпрд╛рди рдЖрдХрд░реНрд╖рд┐рдд рдХрд░рддрд╛ рд╣реВрдВ рдХрд┐ рд╣рдо 0 рдкрд░ рдЧреБрд░реБрддреНрд╡рд╛рдХрд░реНрд╖рдг рд╕реЗрдЯ рдХрд░рддреЗ рд╣реИрдВ (рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рд╢реВрдиреНрдп рдЧреБрд░реБрддреНрд╡рд╛рдХрд░реНрд╖рдг рд╣реЛрдЧрд╛), рдФрд░ рдЪрд╛рд░ "рджреАрд╡рд╛рд░реЛрдВ" рдХреЗ рд╕рд╛рде рдЦреЗрд▓ рдХреЗ рдореИрджрд╛рди рдХреЛ рдШреЗрд░ рд▓реЗрдВ (рдЙрдирдореЗрдВ рд╕реЗ рдПрдХ рдХреЛ рдлрд┐рд░ рдЖрд╕рд╛рдиреА рд╕реЗ рд╣рдЯрд╛рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ)ред
рдЗрд╕рдХреЗ рдмрд╛рдж, рд╣рдо рдЧреЗрдо рдСрдмреНрдЬреЗрдХреНрдЯ рдмрдирд╛рдиреЗ рдХреЗ рддрд░реАрдХреЛрдВ рдХреЛ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд░рддреЗ рд╣реИрдВ:
World.cpp ... b2Body* World::createBox(int x, int y, int hw, int hh, IBox2DItem* userData) { b2BodyDef def; def.type = b2_staticBody; def.position.Set(x, y); b2Body* r = wp->CreateBody(&def); b2PolygonShape box; box.SetAsBox(hw, hh); b2FixtureDef fd; fd.shape = &box; fd.density = 0; fd.friction = FRICTION; fd.restitution = RESTITUTION; r->CreateFixture(&fd); r->SetUserData(userData); return r; } b2Body* World::addBall(int x, int y, int r, IBox2DItem* userData) { if (ball != NULL) { wp->DestroyBody(ball); } b2BodyDef def; def.type = b2_dynamicBody; def.linearDamping = 0.0f; def.angularDamping = 0.0f; def.position.Set(x, y); ball = wp->CreateBody(&def); b2CircleShape shape; shape.m_p.SetZero(); shape.m_radius = r + R_INVIS; b2FixtureDef fd; fd.shape = &shape; fd.density = DYN_DENSITY; fd.friction = FRICTION; fd.restitution = RESTITUTION; ball->CreateFixture(&fd); ball->SetBullet(true); ball->SetUserData(userData); return ball; } ...
рдпрд╣рд╛рдВ рд╣рдо рдПрдХ рдЖрдпрддрд╛рдХрд╛рд░ рд╡рд╕реНрддреБ (рджреАрд╡рд╛рд░ рдпрд╛ рдИрдВрдЯ) рдФрд░ рдПрдХ рдЧреЗрдВрдж рдмрдирд╛рддреЗ рд╣реИрдВред рдлрд╛рд░реНрдо рдХреЗ рдЕрд▓рд╛рд╡рд╛, рд╡реЗ рдкреНрд░рдХрд╛рд░ рдореЗрдВ рднрд┐рдиреНрди рд╣реЛрддреЗ рд╣реИрдВред рдИрдВрдЯ рд╕реНрдерд┐рд░ (рд╕реНрдерд┐рд░) рд╡рд╕реНрддреБрдПрдВ рд╣реИрдВ, рдФрд░ рдЧреЗрдВрдж рдЧрддрд┐рд╢реАрд▓ рд╣реИред Box2D рдХреЛ рдкреНрд░рджрд░реНрд╢рди рдХрд╛рд░рдгреЛрдВ рд╕реЗ рдЧреЗрдо рдСрдмреНрдЬреЗрдХреНрдЯреНрд╕ рдХреЛ рдЗрди рджреЛ рдкреНрд░рдХрд╛рд░реЛрдВ рдореЗрдВ рдЕрд▓рдЧ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИред рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, рд╣рдо рдЗрд╕ рддрд░рд╣ рдХреЗ рднреМрддрд┐рдХ рдЧреБрдгреЛрдВ рдХреЛ рд▓реЛрдЪ, рдШрд░реНрд╖рдг рдХреЗ рдЧреБрдгрд╛рдВрдХ, рдЖрджрд┐ рдХреЗ рд░реВрдк рдореЗрдВ рд╕реЗрдЯ рдХрд░рддреЗ рд╣реИрдВред рд╕реБрд╡рд┐рдзрд╛ рдХреЗ рд▓рд┐рдП, рдЙрдиреНрд╣реЗрдВ рдПрдЪ-рдлрд╛рдЗрд▓ рдореЗрдВ рд╕реНрдерд┐рд░рд╛рдВрдХ рджреНрд╡рд╛рд░рд╛ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИред
рд╣рдорд╛рд░реЗ рдорд╛рдорд▓реЗ рдореЗрдВ, рдШрд░реНрд╖рдг рдХреА рдЕрдиреБрдкрд╕реНрдерд┐рддрд┐ рдореЗрдВ, рдмрд┐рд▓реНрдХреБрд▓ рд▓реЛрдЪрджрд╛рд░ рдЯрдХрд░рд╛рд╡ рд╕рд┐рдореНрдпреБрд▓реЗрдЯреЗрдб (RESTITUTION = 1) рд╣реЛрддрд╛ рд╣реИред рд╣рдордиреЗ рдорд╛рдкрджрдВрдбреЛрдВ рдХреЛ рд░реИрдЦрд┐рдХ рдбрдВрдкрд┐рдВрдЧ рдФрд░ рдПрдВрдЧреБрд▓рд░рдбреИрдореНрдкрд┐рдВрдЧ рдХреЛ рд╢реВрдиреНрдп рдкрд░ рднреА рд╕реЗрдЯ рдХрд┐рдпрд╛ рд╣реИ, рдЬреЛ "рдкрд░реНрдпрд╛рд╡рд░рдг" рдХреЗ рд╕рд╛рде рдЪрд▓рддреА рд╡рд╕реНрддреБ рдХреЛ рдмреНрд░реЗрдХ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЬрд┐рдореНрдореЗрджрд╛рд░ рд╣реИрдВред рдкреНрд░рд╛рд░рдВрдн рдореЗрдВ, рдЧреИрд░-рд╢реВрдиреНрдп рдкрд░ FRICTION рдорд╛рди рд╕реЗрдЯ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рд╡рд┐рдЪрд╛рд░ рдерд╛, рддрд╛рдХрд┐ рдПрдХ рд░реИрдХреЗрдЯ рдХреЗ рд╕рд╛рде рдЧреЗрдВрдж рдХреЛ "рдореЛрдбрд╝" рдХрд░рдирд╛ рд╕рдВрднрд╡ рдерд╛, рд▓реЗрдХрд┐рди рдЗрд╕реЗ рдЫреЛрдбрд╝рдирд╛ рдкрдбрд╝рд╛ред рдЬрдм FRICTION рдХреЛ рдХрд┐рд╕реА рднреА рдЧреИрд░-рдЕрдХреНрд╖реАрдп рдорд╛рди рдкрд░ рд╕реЗрдЯ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рддреЛ рдЧреЗрдВрдж рдХреА рдЧрддрд┐ рдмрд╣реБрдд рддреЗрдЬрд╝реА рд╕реЗ рд▓рдВрдмрд╡рдд рдпрд╛ рдХреНрд╖реИрддрд┐рдЬ рд░реВрдк рд╕реЗ рд╢реБрджреНрдз рдЖрдВрджреЛрд▓рди рдореЗрдВ рдмрджрд▓ рдЬрд╛рддреА рд╣реИред
рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛рдбрд╛рдЯрд╛ рдореЗрдВ рд╢рд░реАрд░ рдФрд░ рд╕реНрдерд┐рд░рддрд╛ рдХреЗ рд▓рд┐рдП, рдЖрдк рдХрд┐рд╕реА рднреА рдкреЙрдЗрдВрдЯрд░ рдХреЛ рд╕реНрдЯреЛрд░ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рд╣рдо рдЕрдкрдиреЗ рдореЙрдбрд▓ рдореЗрдВ рд╕рдВрдмрдВрдзрд┐рдд рд╡рд╕реНрддреБрдУрдВ рдХреЗ IBox2DItem рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдХреЗ рд▓рд┐рдП рдПрдХ рдкреЙрдЗрдВрдЯрд░ рдХреЛ рд╕реНрдЯреЛрд░ рдХрд░реЗрдВрдЧреЗред
World.cpp ... float32 World::getTimeStep() { uint64 t = s3eTimerGetMs(); int r = (int)(t - timestamp); timestamp = t; return (float32)r / 1000.0f; } void World::start() { if (ball != NULL) { ball->ApplyLinearImpulse(ball->GetWorldVector(b2Vec2(-10.0f, -10.0f)), ball->GetWorldPoint(b2Vec2(0.0f, 0.0f))); } } void World::update() { if (!isStarted) { isStarted = true; start(); timestamp = s3eTimerGetMs(); srand((unsigned int)timestamp); } else { float32 timeStep = getTimeStep(); wp->Step(timeStep, V_ITERATIONS, P_ITERATIONS); } } void World::refresh() { if (ball != NULL) { b2Vec2 pos = ball->GetPosition(); Ball* b = (Ball*)ball->GetUserData(); if (b != NULL) { b->setXY(pos.x, pos.y); } } }
рдЕрдкрдбреЗрдЯ рд╡рд┐рдзрд┐ рдореЗрдВ, рд╣рдо "рджреБрдирд┐рдпрд╛" рдХреЗ рдЕрд╕реНрддрд┐рддреНрд╡ рдХреА рдЕрдЧрд▓реА рдкреБрдирд░рд╛рд╡реГрддреНрддрд┐ рдХреА рдЧрдгрдирд╛ рд╕реНрдЯреЗрдк рд╡рд┐рдзрд┐ рджреНрд╡рд╛рд░рд╛ рдХрд░рддреЗ рд╣реИрдВ, рдЬрд┐рд╕рдореЗрдВ рддреАрди рддрд░реНрдХ рдкрд╛рд░рд┐рдд рдХрд┐рдП рдЬрд╛рддреЗ рд╣реИрдВред рдкрд╣рд▓рд╛ рддрд░реНрдХ рд╕рдордп рдЕрдВрддрд░рд╛рд▓ рд╣реИ рдЬрд┐рд╕рдХреЗ рд▓рд┐рдП рдЧрдгрдирд╛ рдХреА рдЬрд╛рддреА рд╣реИред
Box2D рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдЧрд╛рдЗрдб ~ 1/60 рд╕реЗрдХрдВрдб рдХреЗ рдЕрдВрддрд░рд╛рд▓ рдХреА рд╕рд┐рдлрд╛рд░рд┐рд╢ рдХрд░рддрд╛ рд╣реИред рдпрд╣ рднреА рдЕрддреНрдпрдзрд┐рдХ рдЕрдиреБрд╢рдВрд╕рд┐рдд рд╣реИ рдХрд┐ рдпрд╣ рд╕реНрдерд┐рд░ рд╣реЛред рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рджреЛ рдкреИрд░рд╛рдореАрдЯрд░ рдЧрдгрдирд╛ рдХрд░рддреЗ рд╕рдордп рдкреБрдирд░рд╛рд╡реГрддреНрддрд┐рдпреЛрдВ рдХреА рд╕рдВрдЦреНрдпрд╛ рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХрд░рддреЗ рд╣реИрдВ рдФрд░ рд╕реАрдзреЗ рд╕рд┐рдореБрд▓реЗрд╢рди рдХреА рдЧреБрдгрд╡рддреНрддрд╛ рдХреЛ рдкреНрд░рднрд╛рд╡рд┐рдд рдХрд░рддреЗ рд╣реИрдВред рдореИрдВ рджреЛрдиреЛрдВ рдорд╛рдкрджрдВрдбреЛрдВ рдХреЗ рд▓рд┐рдП 10 рдХрд╛ рдорд╛рди рдкрд╛рд╕ рдХрд░рддрд╛ рд╣реВрдВред
рдкрд╣рд▓реА рдмрд╛рд░ рдЕрдкрдбреЗрдЯ рд╡рд┐рдзрд┐ рдХрд╣рд╛ рдЬрд╛рддрд╛ рд╣реИ, рд╣рдо рдЧреЗрдВрдж рдХреЛ рдкреНрд░рд╛рд░рдВрднрд┐рдХ рдЧрддрд┐ рджреЗрддреЗ рд╣реИрдВред рдЪреВрдВрдХрд┐ рд╕рднреА рдЯрдХрд░рд╛рд╡ рдкреВрд░реА рддрд░рд╣ рд╕реЗ рд▓реЛрдЪрджрд╛рд░ рд╣реИрдВ, рдЯрдХреНрдХрд░реЛрдВ рдХреЗ рдмрд╛рдж рдЧреЗрдВрдж рдХрд╛ рд╡реЗрдЧ рдХрдо рдирд╣реАрдВ рд╣реЛрддрд╛ рд╣реИ, рдФрд░ рдкреНрд░рд╛рд░рдВрднрд┐рдХ рд╡реЗрдЧ рдХреА рдПрдХ рднреА рд╕реЗрдЯрд┐рдВрдЧ рд╣рдорд╛рд░реЗ рд▓рд┐рдП рдХрд╛рдлреА рдкрд░реНрдпрд╛рдкреНрдд рд╣реИред рдпрджрд┐ рдЖрд╡рд╢реНрдпрдХ рд╣реЛ, рддреЛ рд╣рдо рдХреЙрд▓ рд╡рд┐рдзрд┐ рдХреЗ рдмреАрдЪ рдХреА рдЧрддрд┐ рдХреЛ рдЕрдкрдбреЗрдЯ рд╡рд┐рдзрд┐ рдореЗрдВ рд╕рдорд╛рдпреЛрдЬрд┐рдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ (рдХрд┐рд╕реА рднреА рд╕реНрдерд┐рддрд┐ рдореЗрдВ рдЖрдкрдХреЛ b2World.Step рдХреЙрд▓ рдХреЗ рд╕рдВрджрд░реНрдн рдореЗрдВ рд╡рд╕реНрддреБрдУрдВ рдХреЗ рд╕рд╛рде рдХреЛрдИ рд╣реЗрд░рдлреЗрд░ рдирд╣реАрдВ рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдП, рдпрд╣ рд╕рдВрднрд╡рддрдГ рд╕реНрдореГрддрд┐ рднреНрд░рд╖реНрдЯрд╛рдЪрд╛рд░ рдХреЛ рдЬрдиреНрдо рджреЗрдЧрд╛)ред
рддрд╛рдЬрд╝рд╛ рд╡рд┐рдзрд┐ рдХрд╛ рдХрд╛рд░реНрдп рдЧреЗрдВрдж рдХреЗ рдкрд░рд┐рд╡рд░реНрддрд┐рдд рдирд┐рд░реНрджреЗрд╢рд╛рдВрдХ (рдЕрдЧрд▓реЗ рдЧрдгрдирд╛ рдЪрд░рдг рдХреЗ рдмрд╛рдж) рдкреНрд░рд╛рдкреНрдд рдХрд░рдирд╛ рд╣реИ рдФрд░ рдкрд░рд┐рд╡рд░реНрддрд┐рдд рдирд┐рд░реНрджреЗрд╢рд╛рдВрдХ рдХреЛ IBox2DItem рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдореЗрдВ рд╕реНрдерд╛рдирд╛рдВрддрд░рд┐рдд рдХрд░рдирд╛ рд╣реИред
рдореЙрдбрд▓ рдореЗрдВ рдЖрд╡рд╢реНрдпрдХ рдкрд░рд┐рд╡рд░реНрддрди рдХрд░реЗрдВ:
Bricks.h #ifndef _BRICKS_H_ #define _BRICKS_H_ #include "IwGL.h" #include "s3e.h" #include "Desktop.h" +#include "World.h" +#include "IBox2DItem.h" #define BRICK_COLOR_1 0xffffff00 #define BRICK_COLOR_2 0xff50ff00 #define BRICK_HALF_WIDTH 20 #define BRICK_HALF_HEIGHT 10 #include <vector> using namespace std; -class Bricks { +class Bricks: public IBox2DItem { private: struct SBrick { SBrick(int x, int y): x(x), y(y), + body(NULL), + isBroken(false), hw(BRICK_HALF_WIDTH), hh(BRICK_HALF_HEIGHT), ic(BRICK_COLOR_1), oc(BRICK_COLOR_2) {} SBrick(const SBrick& p): x(px), y(py), + body(p.body), + isBroken(p.isBroken), hw(p.hw), hh(p.hh), ic(p.ic), oc(p.oc) {} int x, y, hw, hh, ic, oc; + int isBroken; + b2Body* body; }; vector<SBrick> bricks; public: Bricks(): bricks() {} + void init() {} + void release() {} void refresh(); void clear(){bricks.clear();} void add(SBrick& b); typedef vector<SBrick>::iterator BIter; friend class Board; }; #endif // _BRICKS_H_
Bricks.cpp #include "Bricks.h" #include "Quads.h" void Bricks::refresh() { for (BIter p = bricks.begin(); p != bricks.end(); ++p) { + if (p->isBroken) continue; CIwGLPoint point(p->x, p->y); point = IwGLTransform(point); int16* quadPoints = quads.getQuadPoints(); uint32* quadCols = quads.getQuadCols(); if ((quadPoints == NULL) || (quadCols == NULL)) break; *quadPoints++ = point.x - p->hw; *quadPoints++ = point.y + p->hh; *quadCols++ = p->ic; *quadPoints++ = point.x + p->hw; *quadPoints++ = point.y + p->hh; *quadCols++ = p->oc; *quadPoints++ = point.x + p->hw; *quadPoints++ = point.y - p->hh; *quadCols++ = p->ic; *quadPoints++ = point.x - p->hw; *quadPoints++ = point.y - p->hh; *quadCols++ = p->oc; } } void Bricks::add(SBrick& b) { + b.body = world.addBrick(bx, by, b.hw, b.hh, (IBox2DItem*)this); bricks.push_back(b); }
Ball.h #ifndef _BALL_H_ #define _BALL_H_ #include <vector> #include "IwGL.h" #include "s3e.h" #include "Desktop.h" +#include "World.h" +#include "IBox2DItem.h" #define MAX_SEGMENTS 7 #define BALL_COLOR_1 0x00000000 #define BALL_COLOR_2 0xffffffff #define BALL_RADIUS 15 using namespace std; -class Ball { +class Ball: public IBox2DItem { private: struct Offset { Offset(int dx, int dy): dx(dx), dy(dy) {} Offset(const Offset& p): dx(p.dx), dy(p.dy) {} int dx, dy; }; vector<Offset> offsets; int x; int y; + b2Body* body; public: void init(); void release() {} void refresh(); virtual void setXY(int X, int Y); typedef vector<Offset>::iterator OIter; }; #endif // _BALL_H_
Ball.cpp #include "Ball.h" #include "Quads.h" #include "Desktop.h" #include <math.h> #define PI 3.14159265f void Ball::init(){ x = desktop.getWidth() / 2; y = desktop.getHeight()/ 2; float delta = PI / (float)MAX_SEGMENTS; float angle = delta / 2.0f; float r = (float)desktop.toRSize(BALL_RADIUS); for (int i = 0; i < MAX_SEGMENTS; i++) { offsets.push_back(Offset((int16)(cos(angle) * r), (int16)(sin(angle) * r))); angle = angle + delta; offsets.push_back(Offset((int16)(cos(angle) * r), (int16)(sin(angle) * r))); angle = angle + delta; offsets.push_back(Offset((int16)(cos(angle) * r), (int16)(sin(angle) * r))); } + body = world.addBall(x, y, (int)r, (IBox2DItem*)this); } void Ball::setXY(int X, int Y) { x = X; y = Y; } void Ball::refresh() { CIwGLPoint point(x, y); point = IwGLTransform(point); OIter o = offsets.begin(); int r = desktop.toRSize(BALL_RADIUS); for (int i = 0; i < MAX_SEGMENTS; i++) { int16* quadPoints = quads.getQuadPoints(); uint32* quadCols = quads.getQuadCols(); if ((quadPoints == NULL) || (quadCols == NULL)) break; *quadPoints++ = point.x + (r / 4); *quadPoints++ = point.y + (r / 4); *quadCols++ = BALL_COLOR_2; *quadPoints++ = point.x + o->dx; *quadPoints++ = point.y + o->dy; *quadCols++ = BALL_COLOR_1; o++; *quadPoints++ = point.x + o->dx; *quadPoints++ = point.y + o->dy; *quadCols++ = BALL_COLOR_1; o++; *quadPoints++ = point.x + o->dx; *quadPoints++ = point.y + o->dy; *quadCols++ = BALL_COLOR_1; o++; } }
рдпрд╣рд╛рдВ, рд╕рднреА рдкрд░рд┐рд╡рд░реНрддрди рд╕реНрдкрд╖реНрдЯ рд╣реИрдВред рдЕрдЧрд▓рд╛, рдореБрдЦреНрдп рдореЗрдВ рдкрд░рд┐рд╡рд░реНрддрди рдХрд░реЗрдВ:
main.cpp #include "Main.h" #include "s3e.h" #include "IwGL.h" #include "Desktop.h" +#include "World.h" #include "IO.h" #include "Quads.h" #include "Board.h" Board board; void init() { desktop.init(); io.init(); quads.init(); + world.init(); board.init(); } void release() { + world.release(); io.release(); desktop.release(); } int main() { init(); { while (!s3eDeviceCheckQuitRequest()) { io.update(); if (io.isKeyDown(s3eKeyAbsBSK) || io.isKeyDown(s3eKeyBack)) break; + world.update(); quads.update(); desktop.update(); board.update(); board.refresh(); + world.refresh(); quads.refresh(); io.refresh(); desktop.refresh(); } } release(); return 0; }
рдЕрдм рдХрд╛рд░реНрдпрдХреНрд░рдо рд▓реЙрдиреНрдЪ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред рд╣рдо рдХреНрдпрд╛ рджреЗрдЦрддреЗ рд╣реИрдВ? рдЧреЗрдВрдж рдЪрд▓рддреА рд╣реИ, рд▓реЗрдХрд┐рди рдХрд┐рд╕реА рддрд░рд╣ рдмрд╣реБрдд рдзреАрд░реЗ-рдзреАрд░реЗред рдЯрдХрд░рд╛рд╡ рдХреЗ рдмрд╛рдж рдХреЛрдИ рдкреНрд░рддрд┐рдХреНрд╖реЗрдк рдирд╣реАрдВ рджреЗрдЦрд╛ рдЬрд╛рддрд╛ рд╣реИред рдкреНрд░рд╛рд░рдВрднрд┐рдХ рд╡реЗрдЧ рдХреЗ рд╕рд╛рде рдЬреЛрдбрд╝рддреЛрдбрд╝ рдЧреЗрдВрдж рдХреЗ рд╕реНрдкрд╖реНрдЯ рд╡реЗрдЧ рдХреЛ рдирд╣реАрдВ рдмрджрд▓рддреЗ рд╣реИрдВред рдпрд╣ рд╕рдм рдмрддрд╛рддрд╛ рд╣реИ рдХрд┐ рд╣рдо рдХреБрдЫ рдЧрд▓рдд рдХрд░ рд░рд╣реЗ рд╣реИрдВред
рдЖрдЗрдП рд╡рд┐рдЪрд╛рд░ рдХрд░реЗрдВ рдХрд┐ рдпрд╣ рдХреНрдпрд╛ рд╣реЛ рд╕рдХрддрд╛ рд╣реИ? рд╣рдо рд╕реНрдХреНрд░реАрди рдирд┐рд░реНрджреЗрд╢рд╛рдВрдХ рдХреЗ рдкреИрдорд╛рдиреЗ рдореЗрдВ рд╕рднреА рдЖрдХрд╛рд░реЛрдВ рдХреЛ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд░рддреЗ рд╣реИрдВред рдЕрдкрдиреЗ рд▓рд┐рдП, рдореИрдВ рдЖрдорддреМрд░ рдкрд░ рдмреЙрдХреНрд╕ 2 рдбреА рдореЗрдВ рдорд╛рдк рдХреА рдЗрдХрд╛рдИ рдХреЛ 1 рдореАрдЯрд░ рдорд╛рдирддрд╛ рд╣реВрдВред рдпрд╣рд╛рдВ рддрдХ тАЛтАЛрдХрд┐ 320x480 рдХреЗ рд╕реНрдХреНрд░реАрди рд░рд┐рдЬрд╝реЙрд▓реНрдпреВрд╢рди рдХреЗ рд╕рд╛рде, рдпрд╣ рдкрддрд╛ рдЪрд▓рддрд╛ рд╣реИ рдХрд┐ рд╣рдо рдХреБрдЫ рдкреВрд░реА рддрд░рд╣ рд╕реЗ рдЕрдХрд▓реНрдкрдиреАрдп рдорд╣рд╛рдХрд╛рд╡реНрдп рдЖрдХрд╛рд░реЛрдВ рдХреЗ рдПрдХ рдЖрд░реНрдХрд╛рдиреЙрдЗрдб рдХрд╛ рдЕрдиреБрдХрд░рдг рдХрд░рдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХрд░ рд░рд╣реЗ рд╣реИрдВ (рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, рд╕рд┐рдореНрдпреБрд▓реЗрдЯреЗрдб рднреМрддрд┐рдХреА рдбрд┐рд╡рд╛рдЗрд╕ рдХреА рд╕реНрдХреНрд░реАрди рдХреЗ рдЖрдХрд╛рд░ рдкрд░ рдирд┐рд░реНрднрд░ рдХрд░реЗрдЧреА, рдФрд░ рдпрд╣ рдкреВрд░реА рддрд░рд╣ рд╕реЗ рдмреЗрдХрд╛рд░ рд╣реИ)ред рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, Box2D рдЗрд╕ рдЖрдХрд╛рд░ рдХреА рд╡рд╕реНрддреБрдУрдВ рдХреА рдЧрдгрдирд╛ рдХрд░рдиреЗ рдореЗрдВ рдмрд╣реБрдд рдЕрдЪреНрдЫрд╛ рдирд╣реАрдВ рд╣реИред рдЖрдорддреМрд░ рдкрд░, рджреБрдирд┐рдпрд╛ рдХрд╛ рдЕрдиреБрд╢рдВрд╕рд┐рдд рдЖрдХрд╛рд░ рджрд╕рд┐рдпреЛрдВ рдореАрдЯрд░ рд╕реЗ рдЕрдзрд┐рдХ рдирд╣реАрдВ рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдПред рд╕реБрдзрд╛рд░ рдХрд░реЗрдВ:
World.h #ifndef _WORLD_H_ #define _WORLD_H_ #include <vector> #include <Box2D.h> #include "Desktop.h" #include "IBox2DItem.h" +const float W_WIDTH = 10.0f; const int HALF_MARGIN = 10; const int V_ITERATIONS = 10; const int P_ITERATIONS = 10; const float FRICTION = 0.0f; const float RESTITUTION = 1.0f; const float DYN_DENSITY = 0.0f; const float R_INVIS = 0.0f; const float EPS = 1.0f; const float SPEED_SQ = 10.0f; using namespace std; class World { private: bool isStarted; int HandleX, HandleH, HandleW; uint64 timestamp; int width, height; b2World* wp; b2Body* ground; b2Body* ball; b2Body* handle; b2Body* createBox(int x, int y, int hw, int hh, IBox2DItem* userData = NULL); float32 getTimeStep(); void start(); + float toWorld(int x); + int fromWorld(float x); public: World(): width(0), height(0), wp(NULL) {} void init(); void release(); void update(); void refresh(); b2Body* addBrick(int x, int y, int hw, int hh, IBox2DItem* userData) {return createBox(x, y, hw, hh, userData);} b2Body* addBall(int x, int y, int r, IBox2DItem* userData); typedef vector<b2Body*>::iterator BIter; }; extern World world; #endif // _WORLD_H_
World.cpp #include "s3e.h" #include "World.h" #include "Ball.h" World world; void World::init() { isStarted = false; width = desktop.getWidth(); height = desktop.getHeight(); b2Vec2 gravity(0.0f, 0.0f); wp = new b2World(gravity); ground = createBox(width/2, -HALF_MARGIN, width/2, HALF_MARGIN); createBox(-HALF_MARGIN, height/2, HALF_MARGIN, height/2); createBox(width/2, height + HALF_MARGIN, width/2, HALF_MARGIN); createBox(width + HALF_MARGIN, height/2, HALF_MARGIN, height/2); ball = NULL; handle = NULL; } void World::release() { if (wp != NULL) { delete wp; wp = NULL; ball = NULL; handle = NULL; } } +float World::toWorld(int x) { + return ((float)x * W_WIDTH) / (float)desktop.getWidth(); +} +int World::fromWorld(float x) { + return (int)((x * (float)desktop.getWidth()) / W_WIDTH); +} b2Body* World::createBox(int x, int y, int hw, int hh, IBox2DItem* userData) { b2BodyDef def; def.type = b2_staticBody; - def.position.Set(x, y); + def.position.Set(toWorld(x), toWorld(y)); b2Body* r = wp->CreateBody(&def); b2PolygonShape box; - box.SetAsBox(hw, hh); + box.SetAsBox(toWorld(hw), toWorld(hh)); b2FixtureDef fd; fd.shape = &box; fd.density = 0; fd.friction = FRICTION; fd.restitution = RESTITUTION; r->CreateFixture(&fd); r->SetUserData(userData); return r; } b2Body* World::addBall(int x, int y, int r, IBox2DItem* userData) { if (ball != NULL) { wp->DestroyBody(ball); } b2BodyDef def; def.type = b2_dynamicBody; def.linearDamping = 0.0f; def.angularDamping = 0.0f; - def.position.Set(x, y); + def.position.Set(toWorld(x), toWorld(y)); ball = wp->CreateBody(&def); b2CircleShape shape; shape.m_p.SetZero(); - shape.m_radius = r + R_INVIS; + shape.m_radius = toWorld(r) + R_INVIS; b2FixtureDef fd; fd.shape = &shape; fd.density = DYN_DENSITY; fd.friction = FRICTION; fd.restitution = RESTITUTION; ball->CreateFixture(&fd); ball->SetBullet(true); ball->SetUserData(userData); return ball; } float32 World::getTimeStep() { uint64 t = s3eTimerGetMs(); int r = (int)(t - timestamp); timestamp = t; return (float32)r / 1000.0f; } void World::start() { if (ball != NULL) { ball->ApplyLinearImpulse(ball->GetWorldVector(b2Vec2(-10.0f, -10.0f)), ball->GetWorldPoint(b2Vec2(0.0f, 0.0f))); } } void World::update() { if (!isStarted) { isStarted = true; start(); timestamp = s3eTimerGetMs(); srand((unsigned int)timestamp); } else { float32 timeStep = getTimeStep(); wp->Step(timeStep, V_ITERATIONS, P_ITERATIONS); } } void World::refresh() { if (ball != NULL) { b2Vec2 pos = ball->GetPosition(); Ball* b = (Ball*)ball->GetUserData(); if (b != NULL) { - b->setXY(pos.x, pos.y); + b->setXY(fromWorld(pos.x), fromWorld(pos.y)); } } }
рдЕрдм, рд╕реНрдХреНрд░реАрди рдХреЗ рдЖрдХрд╛рд░ рдХреА рдкрд░рд╡рд╛рд╣ рдХрд┐рдП рдмрд┐рдирд╛, рд╣рдорд╛рд░реА рджреБрдирд┐рдпрд╛ рдХреА "рдЪреМрдбрд╝рд╛рдИ" 10 (рдореАрдЯрд░) рд╣реЛрдЧреАред рд╣рдо рд╢реБрд░реВ рдХрд░рддреЗ рд╣реИрдВ рдФрд░ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░рддреЗ рд╣реИрдВ рдХрд┐ рдЧреЗрдВрдж рд╕рд╛рдорд╛рдиреНрдп рдЧрддрд┐ рд╕реЗ рдЙрдбрд╝рдиреЗ рд▓рдЧреА рдФрд░ рджреАрд╡рд╛рд░реЛрдВ рд╕реЗ рдЙрдЫрд▓ рдЧрдИред рдЕрдм, рд╣рдо рдпрд╣ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░реЗрдВрдЧреЗ рдХрд┐ "рдИрдВрдЯреЗрдВ" рдПрдХ рдЧреЗрдВрдж рд╕реЗ рдЯрдХрд░рд╛рдиреЗ рдХреЗ рдмрд╛рдж рдЧрд╛рдпрдм рд╣реЛ рдЬрд╛рдПрдВред
Bricks.h #ifndef _BRICKS_H_ #define _BRICKS_H_ #include "IwGL.h" #include "s3e.h" #include "Desktop.h" #include "World.h" #include "IBox2DItem.h" #define BRICK_COLOR_1 0xffffff00 #define BRICK_COLOR_2 0xff50ff00 #define BRICK_HALF_WIDTH 20 #define BRICK_HALF_HEIGHT 10 #include <vector> using namespace std; class Bricks: public IBox2DItem { private: struct SBrick { SBrick(int x, int y): x(x), y(y), body(NULL), isBroken(false), hw(BRICK_HALF_WIDTH), hh(BRICK_HALF_HEIGHT), ic(BRICK_COLOR_1), oc(BRICK_COLOR_2) {} SBrick(const SBrick& p): x(px), y(py), body(p.body), isBroken(p.isBroken), hw(p.hw), hh(p.hh), ic(p.ic), oc(p.oc) {} int x, y, hw, hh, ic, oc; int isBroken; b2Body* body; }; vector<SBrick> bricks; + virtual bool impact(b2Body* b); public: Bricks(): bricks() {} void init() {} void release() {} void refresh(); void clear(){bricks.clear();} void add(SBrick& b); typedef vector<SBrick>::iterator BIter; friend class Board; }; #endif // _BRICKS_H_
Bricks.cpp #include "Bricks.h" #include "Quads.h" void Bricks::refresh() { for (BIter p = bricks.begin(); p != bricks.end(); ++p) { if (p->isBroken) continue; CIwGLPoint point(p->x, p->y); point = IwGLTransform(point); int16* quadPoints = quads.getQuadPoints(); uint32* quadCols = quads.getQuadCols(); if ((quadPoints == NULL) || (quadCols == NULL)) break; *quadPoints++ = point.x - p->hw; *quadPoints++ = point.y + p->hh; *quadCols++ = p->ic; *quadPoints++ = point.x + p->hw; *quadPoints++ = point.y + p->hh; *quadCols++ = p->oc; *quadPoints++ = point.x + p->hw; *quadPoints++ = point.y - p->hh; *quadCols++ = p->ic; *quadPoints++ = point.x - p->hw; *quadPoints++ = point.y - p->hh; *quadCols++ = p->oc; } } +bool Bricks::impact(b2Body* b) { + for (BIter p = bricks.begin(); p != bricks.end(); ++p) { + if (p->body == b) { + p->isBroken = true; + return true; + } + } + return false; +} void Bricks::add(SBrick& b) { b.body = world.addBrick(bx, by, b.hw, b.hh, (IBox2DItem*)this); bricks.push_back(b); }
World.h #ifndef _WORLD_H_ #define _WORLD_H_ #include <vector> #include <Box2D.h> #include "Desktop.h" #include "IBox2DItem.h" const float W_WIDTH = 10.0f; const int HALF_MARGIN = 10; const int V_ITERATIONS = 10; const int P_ITERATIONS = 10; const float FRICTION = 0.0f; const float RESTITUTION = 1.0f; const float DYN_DENSITY = 0.0f; const float R_INVIS = 0.0f; const float EPS = 1.0f; const float SPEED_SQ = 10.0f; using namespace std; -class World { +class World: public b2ContactListener { private: bool isStarted; int HandleX, HandleH, HandleW; uint64 timestamp; int width, height; b2World* wp; b2Body* ground; b2Body* ball; b2Body* handle; b2Body* createBox(int x, int y, int hw, int hh, IBox2DItem* userData = NULL); float32 getTimeStep(); + vector<b2Body*>* broken; void start(); + void impact(b2Body* b); + virtual void PostSolve(b2Contact* contact, const b2ContactImpulse* impulse); float toWorld(int x); int fromWorld(float x); public: World(): broken(), width(0), height(0), wp(NULL) {} void init(); void release(); void update(); void refresh(); b2Body* addBrick(int x, int y, int hw, int hh, IBox2DItem* userData) { return createBox(x, y, hw, hh, userData); } b2Body* addBall(int x, int y, int r, IBox2DItem* userData); + typedef vector<b2Body*>::iterator BIter; }; extern World world; #endif // _WORLD_H_
World.cpp #include "s3e.h" #include "World.h" #include "Ball.h" World world; void World::init() { + broken = new vector<b2Body*>(); isStarted = false; width = desktop.getWidth(); height = desktop.getHeight(); b2Vec2 gravity(0.0f, 0.0f); wp = new b2World(gravity); + wp->SetContactListener(this); ground = createBox(width/2, -HALF_MARGIN, width/2, HALF_MARGIN); createBox(-HALF_MARGIN, height/2, HALF_MARGIN, height/2); createBox(width/2, height + HALF_MARGIN, width/2, HALF_MARGIN); createBox(width + HALF_MARGIN, height/2, HALF_MARGIN, height/2); ball = NULL; handle = NULL; } void World::release() { if (wp != NULL) { delete wp; wp = NULL; ball = NULL; handle = NULL; } + delete broken; } float World::toWorld(int x) { return ((float)x * W_WIDTH) / (float)desktop.getWidth(); } int World::fromWorld(float x) { return (int)((x * (float)desktop.getWidth()) / W_WIDTH); } b2Body* World::createBox(int x, int y, int hw, int hh, IBox2DItem* userData) { b2BodyDef def; def.type = b2_staticBody; def.position.Set(toWorld(x), toWorld(y)); b2Body* r = wp->CreateBody(&def); b2PolygonShape box; box.SetAsBox(toWorld(hw), toWorld(hh)); b2FixtureDef fd; fd.shape = &box; fd.density = 0; fd.friction = FRICTION; fd.restitution = RESTITUTION; r->CreateFixture(&fd); r->SetUserData(userData); return r; } b2Body* World::addBall(int x, int y, int r, IBox2DItem* userData) { if (ball != NULL) { wp->DestroyBody(ball); } b2BodyDef def; def.type = b2_dynamicBody; def.linearDamping = 0.0f; def.angularDamping = 0.0f; def.position.Set(toWorld(x), toWorld(y)); ball = wp->CreateBody(&def); b2CircleShape shape; shape.m_p.SetZero(); shape.m_radius = toWorld(r) + R_INVIS; b2FixtureDef fd; fd.shape = &shape; fd.density = DYN_DENSITY; fd.friction = FRICTION; fd.restitution = RESTITUTION; ball->CreateFixture(&fd); ball->SetBullet(true); ball->SetUserData(userData); return ball; } float32 World::getTimeStep() { uint64 t = s3eTimerGetMs(); int r = (int)(t - timestamp); timestamp = t; return (float32)r / 1000.0f; } void World::start() { if (ball != NULL) { ball->ApplyLinearImpulse(ball->GetWorldVector(b2Vec2(-10.0f, -10.0f)), ball->GetWorldPoint(b2Vec2(0.0f, 0.0f))); } } +void World::impact(b2Body* b) { + IBox2DItem* it = (IBox2DItem*)b->GetUserData(); + if (it != NULL) { + if (it->impact(b)) { + for (BIter p = broken->begin(); p != broken->end(); ++p) { + if (*p == b) return; + } + broken->push_back(b); + } + } +} +void World::PostSolve(b2Contact* contact, const b2ContactImpulse* impulse) { + impact(contact->GetFixtureA()->GetBody()); + impact(contact->GetFixtureB()->GetBody()); +} void World::update() { if (!isStarted) { isStarted = true; start(); timestamp = s3eTimerGetMs(); srand((unsigned int)timestamp); } else { float32 timeStep = getTimeStep(); wp->Step(timeStep, V_ITERATIONS, P_ITERATIONS); } } void World::refresh() { + for (BIter p = broken->begin(); p != broken->end(); ++p) { + wp->DestroyBody(*p); + } + broken->clear(); if (ball != NULL) { b2Vec2 pos = ball->GetPosition(); Ball* b = (Ball*)ball->GetUserData(); if (b != NULL) { b->setXY(fromWorld(pos.x), fromWorld(pos.y)); } } }
рдпрд╣рд╛рдБ, рдЬреИрд╕рд╛ рдХрд┐ рдореИрдВрдиреЗ рдКрдкрд░ рдХрд╣рд╛, рдпрд╣ рдорд╣рддреНрд╡рдкреВрд░реНрдг рд╣реИ рдХрд┐ b2World.Step рдХреЗ рдЕрдЧрд▓реЗ рдкреБрдирд░рд╛рд╡реГрддреНрддрд┐ рдХреА рдЧрдгрдирд╛ рдХрд░рддреЗ рд╕рдордп рдСрдмреНрдЬреЗрдХреНрдЯ рдХреЛ рд╣рдЯрд╛рдиреЗ рдХрд╛ рдкреНрд░рдпрд╛рд╕ рди рдХрд░реЗрдВ (рдпрджрд┐ рдЖрдк рд╕реАрдзреЗ PostSolve рдореЗрдВ рдСрдмреНрдЬреЗрдХреНрдЯ рдХреЛ рд╣рдЯрд╛рдиреЗ рдХрд╛ рдкреНрд░рдпрд╛рд╕ рдХрд░рддреЗ рд╣реИрдВ рддреЛ рдпрд╣реА рд╣реЛрдЧрд╛)ред рд╕рд╛рде рд╣реА, рдЖрдкрдХреЛ PostSolve рдХреЛ рдПрдХ рдмрд╛рд░ рдХреЙрд▓ рдХрд░рдиреЗ рдХреА рдЕрдкреЗрдХреНрд╖рд╛ рдирд╣реАрдВ рдХрд░рдиреА рдЪрд╛рд╣рд┐рдПред рдпрд╣ рдХрд╛рдлреА рд╕рдВрднрд╡ рд╣реИ рдХрд┐ рдпрд╣ рдХрд╛рдо рдХрд░реЗрдЧрд╛, рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдПрдХ "рдИрдВрдЯ" рдХреЗ рд▓рд┐рдП рджреЛ рдмрд╛рд░ред рдпрджрд┐ рд╣рдо рдкрд╣рд▓реА рдЬрд╛рдБрдЪ рдХреЗ рдмрд┐рдирд╛ рдЯреВрдЯреА рд╣реБрдИ рд╡рд╕реНрддреБ рдбрд╛рд▓реЗрдВ, рддреЛ рд╣рдо рдЗрд╕реЗ рджреЛ рдмрд╛рд░ рдирд╖реНрдЯ рдХрд░рдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХрд░реЗрдВрдЧреЗ, рдЬрд┐рд╕рд╕реЗ рдЕрдирд┐рд╡рд╛рд░реНрдп рд░реВрдк рд╕реЗ рд╕реНрдореГрддрд┐ рд╡рд┐рдирд╛рд╢ рд╣реЛ рдЬрд╛рдПрдЧрд╛ред рдЪреВрдВрдХрд┐ рдмрдбрд╝реА рд╕рдВрдЦреНрдпрд╛ рдореЗрдВ рдСрдмреНрдЬреЗрдХреНрдЯреНрд╕ рдЯреВрдЯреА рд╣реБрдИ рдирд╣реАрдВ рдЬрдорд╛ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рд╡реЗрдХреНрдЯрд░ рдореЗрдВ рдСрдмреНрдЬреЗрдХреНрдЯ рдХреЗ рд▓рд┐рдП рдПрдХ рд░реЗрдЦреАрдп рдЦреЛрдЬ рдкреНрд░рджрд░реНрд╢рди рдХреЗ рдорд╛рдорд▓реЗ рдореЗрдВ рдХрд╛рдлреА рд╕рдВрддреЛрд╖рдЬрдирдХ рд╣реИред
рдмрд╣реБрдд рдХрдо рдмрдЪрд╛ рд╣реИред рдПрдХ рд░реИрдХреЗрдЯ рдЬреЛрдбрд╝реЗрдВред рдкреНрд░рд╛рд░рдВрдн рдореЗрдВ, рдореИрдВ рд░реИрд╕реНрдХреЗрдЯ рдХреЛ рдПрдХ рдЧрддрд┐рд╢реАрд▓ рд╡рд╕реНрддреБ рдмрдирд╛рдирд╛ рдЪрд╛рд╣рддрд╛ рдерд╛, рдЬреЛ рдкреНрд░рд┐рдЬреНрдореАрдпрдЬреЙрдЗрдВрдЯ рдХреЗ рд╕рд╛рде рдЕрдкрдиреЗ рдКрд░реНрдзреНрд╡рд╛рдзрд░ рдЖрдВрджреЛрд▓рди рдХреЛ рд╕реАрдорд┐рдд рдХрд░рддрд╛ рд╣реИред рдЗрд╕реЗ рдХреНрд╖реИрддрд┐рдЬ рд░реВрдк рд╕реЗ рд╕реНрдерд╛рдирд╛рдВрддрд░рд┐рдд рдХрд░реЗрдВ, рдпрд╣ рд╕рдВрднрд╡ рд╣реЛрдЧрд╛, рдЕрд╕реНрдерд╛рдпреА рд░реВрдк рд╕реЗ рдорд╛рдЙрд╕рдЬреЙрдЗрдВрдЯ рдмрдирд╛рдХрд░ред рд▓реЗрдХрд┐рди рдлрд┐рд░, рдореИрдВрдиреЗ рдлреИрд╕рд▓рд╛ рдХрд┐рдпрд╛ рдХрд┐
рдпрд╣ рдЖрд╕рд╛рди рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдП ред
рддрдереНрдп рдпрд╣ рд╣реИ рдХрд┐ рд░реИрдХреЗрдЯ рдХреЛ рдПрдХ рдЧрддрд┐рд╢реАрд▓ рд╡рд╕реНрддреБ рдмрдирд╛рдиреЗ рдХрд╛ рдирд┐рд░реНрдгрдп рдмрд╣реБрдд рд╕рдлрд▓ рдирд╣реАрдВ рд╣реИред Box2D рдХреЛ рд╣рд░ рд╕рдордп рдЧрддрд┐рд╢реАрд▓ рд╡рд╕реНрддреБрдУрдВ рдХреА рдЯрдХреНрдХрд░ рдХреЛ рдЯреНрд░реИрдХ рдХрд░рдирд╛ рд╣реЛрдЧрд╛, рдФрд░ рдпрд╣ рдХрд╛рд░реНрдп рдЗрддрдирд╛ рдЬрдЯрд┐рд▓ рд╣реИ рдХрд┐ Box2D рднреА рдЗрд╕реЗ рдмрд╣реБрдд рдЕрдЪреНрдЫреА рддрд░рд╣ рд╕реЗ рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИред SetBullet рдХреЛ рд╕реНрдерд╛рдкрд┐рдд рдХрд░рдиреЗ рдореЗрдВ рдорджрдж рдорд┐рд▓рддреА рд╣реИ, рд▓реЗрдХрд┐рди рдРрд╕реЗ рд╕рдордп рд╣реЛ рд╕рдХрддреЗ рд╣реИрдВ рдЬрдм рдЧреЗрдВрдж рд░реИрдХреЗрдЯ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдЙрдбрд╝ рдЬрд╛рдПрдЧреА, рдЬреЛ рдирд┐рд╢реНрдЪрд┐рдд рд░реВрдк рд╕реЗ, рд╣рдорд╛рд░реЗ рдорд╛рдорд▓реЗ рдореЗрдВ рдкреВрд░реА рддрд░рд╣ рд╕реЗ рдЕрд╕реНрд╡реАрдХрд╛рд░реНрдп рд╣реИред рдЗрд╕рд▓рд┐рдП, рд░реИрдХреЗрдЯ рдПрдХ рд╕реНрдерд┐рд░ рд╡рд╕реНрддреБ рд╣реЛрдЧреАред рд╣рдо рдмрд╕ рдЧрдгрдирд╛ рдЪрд░рдгреЛрдВ рдХреЗ рдмреАрдЪ рдЗрд╕реЗ рдирд╖реНрдЯ рдХрд░ рджреЗрдВрдЧреЗ рдФрд░ рдпрджрд┐ рдЖрд╡рд╢реНрдпрдХ рд╣реЛ, рддреЛ рдПрдХ рдирдИ рдЬрдЧрд╣ рдкрд░ рдмрдирд╛ рд╕рдХрддреЗ рд╣реИрдВред рдЕрдиреНрдп рдмрд╛рддреЛрдВ рдХреЗ рдЕрд▓рд╛рд╡рд╛, рдЗрд╕ рд╡рд┐рдзрд┐ рдХреЛ рд▓рд╛рдЧреВ рдХрд░рдирд╛ рдмрд╣реБрдд рдЖрд╕рд╛рди рд╣реИред
рд╣рдо рдкрд░рд┐рдпреЛрдЬрдирд╛ рдореЗрдВ рдЖрд╡рд╢реНрдпрдХ рдкрд░рд┐рд╡рд░реНрддрди рдХрд░реЗрдВрдЧреЗ:
arcanoid.mkb #!/usr/bin/env mkb options { module_path="../yaml" module_path="../box2d" } subprojects { iwgl yaml box2d } includepath { ./source/Main ./source/Model } files { [Main] (source/Main) Main.cpp Main.h Quads.cpp Quads.h Desktop.cpp Desktop.h IO.cpp IO.h + TouchPad.cpp + TouchPad.h [Model] (source/Model) Bricks.cpp Bricks.h Ball.cpp Ball.h Board.cpp Board.h + Handle.cpp + Handle.h } assets { (data) level.json }
рдпрд╣рд╛рдБ рд╕реЗ рдереЛрдбрд╝рд╛ рд╕рдВрд╢реЛрдзрд┐рдд рдЯрдЪрдкреИрдб рдореЙрдбреНрдпреВрд▓ рд▓реЗрдВ:
TouchPad.h #ifndef _TOUCHPAD_H_ #define _TOUCHPAD_H_ #include "s3ePointer.h" #include "Desktop.h" #define MAX_TOUCHES 3 enum EMessageType { emtNothing = 0x00, emtTouchEvent = 0x10, emtTouchIdMask = 0x03, emtTouchMask = 0x78, emtMultiTouch = 0x14, emtTouchOut = 0x18, emtTouchDown = 0x30, emtTouchUp = 0x50, emtTouchOutUp = 0x58, emtTouchMove = 0x70, emtSingleTouchDown = 0x30, emtSingleTouchUp = 0x50, emtSingleTouchMove = 0x70, emtMultiTouchDown = 0x34, emtMultiTouchUp = 0x54, emtMultiTouchMove = 0x74 }; struct Touch { int x, y; bool isActive, isPressed, isMoved; int id; }; class TouchPad { private: bool IsAvailable; bool IsMultiTouch; Touch Touches[MAX_TOUCHES]; Touch* findTouch(int id); static void HandleMultiTouchButton(s3ePointerTouchEvent* event); static void HandleMultiTouchMotion(s3ePointerTouchMotionEvent* event); public: static bool isTouchDown(int eventCode); static bool isTouchUp(int eventCode); bool isAvailable() const { return IsAvailable; } bool isMultiTouch() const { return IsMultiTouch; } Touch* getTouchByID(int id); Touch* getTouch(int index) { return &Touches[index]; } Touch* getTouchPressed(); int getTouchCount() const; bool init(); void release(); void update(); void clear(); }; extern TouchPad touchPad; #endif
TouchPad.cpp #include "TouchPad.h" TouchPad touchPad; bool TouchPad::isTouchDown(int eventCode) { return (eventCode & emtTouchMask) == emtTouchDown; } bool TouchPad::isTouchUp(int eventCode) { return (eventCode & emtTouchMask) == emtTouchUp; } void TouchPad::HandleMultiTouchButton(s3ePointerTouchEvent* event) { Touch* touch = touchPad.findTouch(event->m_TouchID); if (touch != NULL) { touch->isPressed = event->m_Pressed != 0; touch->isActive = true; touch->x = event->m_x; touch->y = event->m_y; touch->id = event->m_TouchID; } } void TouchPad::HandleMultiTouchMotion(s3ePointerTouchMotionEvent* event) { Touch* touch = touchPad.findTouch(event->m_TouchID); if (touch != NULL) { if (touch->isActive) { touch->isMoved = true; } touch->isActive = true; touch->x = event->m_x; touch->y = event->m_y; } } void HandleSingleTouchButton(s3ePointerEvent* event) { Touch* touch = touchPad.getTouch(0); touch->isPressed = event->m_Pressed != 0; touch->isActive = true; touch->x = event->m_x; touch->y = event->m_y; touch->id = 0; } void HandleSingleTouchMotion(s3ePointerMotionEvent* event) { Touch* touch = touchPad.getTouch(0); if (touch->isActive) { touch->isMoved = true; } touch->isActive = true; touch->x = event->m_x; touch->y = event->m_y; } Touch* TouchPad::getTouchByID(int id) { for (int i = 0; i < MAX_TOUCHES; i++) { if (Touches[i].isActive && Touches[i].id == id) return &Touches[i]; } return NULL; } Touch* TouchPad::getTouchPressed() { for (int i = 0; i < MAX_TOUCHES; i++) { if (Touches[i].isPressed && Touches[i].isActive) return &Touches[i]; } return NULL; } Touch* TouchPad::findTouch(int id) { if (!IsAvailable) return NULL; for (int i = 0; i < MAX_TOUCHES; i++) { if (Touches[i].id == id) return &Touches[i]; } for (int i = 0; i < MAX_TOUCHES; i++) { if (!Touches[i].isActive) { Touches[i].id = id; return &Touches[i]; } } return NULL; } int TouchPad::getTouchCount() const { if (!IsAvailable) return 0; int r = 0; for (int i = 0; i < MAX_TOUCHES; i++) { if (Touches[i].isActive) { r++; } } return r; } void TouchPad::update() { for (int i = 0; i < MAX_TOUCHES; i++) { Touches[i].isMoved = false; } if (IsAvailable) { s3ePointerUpdate(); } } void TouchPad::clear() { for (int i = 0; i < MAX_TOUCHES; i++) { if (!Touches[i].isPressed) { Touches[i].isActive = false; } Touches[i].isMoved = false; } } bool TouchPad::init() { IsAvailable = s3ePointerGetInt(S3E_POINTER_AVAILABLE) ? true : false; if (!IsAvailable) return false; for (int i = 0; i < MAX_TOUCHES; i++) { Touches[i].isPressed = false; Touches[i].isActive = false; Touches[i].isMoved = false; Touches[i].id = 0; } IsMultiTouch = s3ePointerGetInt(S3E_POINTER_MULTI_TOUCH_AVAILABLE) ? true : false; if (IsMultiTouch) { s3ePointerRegister(S3E_POINTER_TOUCH_EVENT, (s3eCallback)HandleMultiTouchButton, NULL); s3ePointerRegister(S3E_POINTER_TOUCH_MOTION_EVENT, (s3eCallback)HandleMultiTouchMotion, NULL); } else { s3ePointerRegister(S3E_POINTER_BUTTON_EVENT, (s3eCallback)HandleSingleTouchButton, NULL); s3ePointerRegister(S3E_POINTER_MOTION_EVENT, (s3eCallback)HandleSingleTouchMotion, NULL); } return true; } void TouchPad::release() { if (IsAvailable) { if (IsMultiTouch) { s3ePointerUnRegister(S3E_POINTER_TOUCH_EVENT, (s3eCallback)HandleMultiTouchButton); s3ePointerUnRegister(S3E_POINTER_TOUCH_MOTION_EVENT, (s3eCallback)HandleMultiTouchMotion); } else { s3ePointerUnRegister(S3E_POINTER_BUTTON_EVENT, (s3eCallback)HandleSingleTouchButton); s3ePointerUnRegister(S3E_POINTER_MOTION_EVENT, (s3eCallback)HandleSingleTouchMotion); } } }
IO.h #ifndef _IO_H_ #define _IO_H_ #include "TouchPad.h" class IO { private: bool KeysAvailable; public: void init(); void release(); void update(); void refresh(); bool isKeyDown(s3eKey key) const; }; extern IO io; #endif
IO.cpp #include "s3e.h" #include "IO.h" IO io; void IO::init() { touchPad.init(); } void IO::release() { touchPad.release(); } void IO::update() { touchPad.update(); s3eKeyboardUpdate(); } void IO::refresh() { touchPad.clear(); } bool IO::isKeyDown(s3eKey key) const { return (s3eKeyboardGetState(key) & S3E_KEY_STATE_DOWN) == S3E_KEY_STATE_DOWN; }
рдЕрдм, рд╣реИрдВрдбрд▓ рдореЙрдбреНрдпреВрд▓ рдЬреЛрдбрд╝реЗрдВ:
Handle.h #ifndef _HANDLE_H_ #define _HANDLE_H_ #include "IwGL.h" #include "s3e.h" #include "Desktop.h" #include "World.h" #include "IBox2DItem.h" #define HANDLE_COLOR 0xffff3000 #define HANDLE_H_WIDTH 40 #define HANDLE_H_HEIGHT 10 #define HANDLE_H_POS 50 class Handle: public IBox2DItem { private: int x; int y; int touchId; public: void init(); void release() {} void refresh(); void update(); virtual void setXY(int X, int Y); }; #endif
Handle.cpp #include "Handle.h" #include "Quads.h" #include "TouchPad.h" void Handle::init() { x = desktop.getWidth() / 2; y = desktop.getHeight(); touchId = -1; } void Handle::setXY(int X, int Y) { x = X; y = Y; } void Handle::refresh() { CIwGLPoint point(x, y); point = IwGLTransform(point); int16* quadPoints = quads.getQuadPoints(); uint32* quadCols = quads.getQuadCols(); if ((quadPoints == NULL) || (quadCols == NULL)) return; *quadPoints++ = point.x - desktop.toRSize(HANDLE_H_WIDTH); *quadPoints++ = point.y + desktop.toRSize(HANDLE_H_HEIGHT); *quadCols++ = HANDLE_COLOR; *quadPoints++ = point.x + desktop.toRSize(HANDLE_H_WIDTH); *quadPoints++ = point.y + desktop.toRSize(HANDLE_H_HEIGHT); *quadCols++ = HANDLE_COLOR; *quadPoints++ = point.x + desktop.toRSize(HANDLE_H_WIDTH); *quadPoints++ = point.y - desktop.toRSize(HANDLE_H_HEIGHT); *quadCols++ = HANDLE_COLOR; *quadPoints++ = point.x - desktop.toRSize(HANDLE_H_WIDTH); *quadPoints++ = point.y - desktop.toRSize(HANDLE_H_HEIGHT); *quadCols++ = HANDLE_COLOR; world.addHandle(x, y, desktop.toRSize(HANDLE_H_WIDTH), desktop.toRSize(HANDLE_H_HEIGHT), (IBox2DItem*)this); } void Handle::update() { Touch* t = NULL; if (touchId > 0) { t = touchPad.getTouchByID(touchId); } else { t = touchPad.getTouchPressed(); } if (t != NULL) { touchId = t->id; world.moveHandle(t->x, t->y); } else { touchId = -1; } }
рдФрд░ рд╡рд┐рд╢реНрд╡ рдФрд░ рдмреЛрд░реНрдб рдореЗрдВ рдмрджрд▓рд╛рд╡ рдХрд░реЗрдВ:
World.h #ifndef _WORLD_H_ #define _WORLD_H_ #include <vector> #include <Box2D.h> #include "Desktop.h" #include "IBox2DItem.h" const float W_WIDTH = 10.0f; const int HALF_MARGIN = 10; const int V_ITERATIONS = 10; const int P_ITERATIONS = 10; const float FRICTION = 0.0f; const float RESTITUTION = 1.0f; const float DYN_DENSITY = 0.0f; const float R_INVIS = 0.0f; const float EPS = 1.0f; const float SPEED_SQ = 10.0f; using namespace std; class World: public b2ContactListener { private: bool isStarted; + bool isHandleCreated; int HandleX, HandleH, HandleW; uint64 timestamp; int width, height; b2World* wp; b2Body* ground; b2Body* ball; b2Body* handle; b2Body* createBox(int x, int y, int hw, int hh, IBox2DItem* userData = NULL); float32 getTimeStep(); vector<b2Body*>* broken; void start(); void impact(b2Body* b); virtual void PostSolve(b2Contact* contact, const b2ContactImpulse* impulse); float toWorld(int x); int fromWorld(float x); public: World(): broken(), width(0), height(0), wp(NULL) {} void init(); void release(); void update(); void refresh(); b2Body* addBrick(int x, int y, int hw, int hh, IBox2DItem* userData) {return createBox(x, y, hw, hh, userData);} b2Body* addBall(int x, int y, int r, IBox2DItem* userData); + b2Body* addHandle(int x, int y, int hw, int hh, IBox2DItem* userData); + void moveHandle(int x, int y); typedef vector<b2Body*>::iterator BIter; }; extern World world; #endif // _WORLD_H_
World.cpp #include "s3e.h" #include "World.h" #include "Ball.h" World world; void World::init() { broken = new vector<b2Body*>(); isStarted = false; width = desktop.getWidth(); height = desktop.getHeight(); b2Vec2 gravity(0.0f, 0.0f); wp = new b2World(gravity); wp->SetContactListener(this); ground = createBox(width/2, -HALF_MARGIN, width/2, HALF_MARGIN); createBox(-HALF_MARGIN, height/2, HALF_MARGIN, height/2); createBox(width/2, height + HALF_MARGIN, width/2, HALF_MARGIN); createBox(width + HALF_MARGIN, height/2, HALF_MARGIN, height/2); ball = NULL; handle = NULL; } void World::release() { if (wp != NULL) { delete wp; wp = NULL; ball = NULL; handle = NULL; } delete broken; } float World::toWorld(int x) { return ((float)x * W_WIDTH) / (float)desktop.getWidth(); } int World::fromWorld(float x) { return (int)((x * (float)desktop.getWidth()) / W_WIDTH); } b2Body* World::createBox(int x, int y, int hw, int hh, IBox2DItem* userData) { b2BodyDef def; def.type = b2_staticBody; def.position.Set(toWorld(x), toWorld(y)); b2Body* r = wp->CreateBody(&def); b2PolygonShape box; box.SetAsBox(toWorld(hw), toWorld(hh)); b2FixtureDef fd; fd.shape = &box; fd.density = 0; fd.friction = FRICTION; fd.restitution = RESTITUTION; r->CreateFixture(&fd); r->SetUserData(userData); return r; } b2Body* World::addBall(int x, int y, int r, IBox2DItem* userData) { if (ball != NULL) { wp->DestroyBody(ball); } b2BodyDef def; def.type = b2_dynamicBody; def.linearDamping = 0.0f; def.angularDamping = 0.0f; def.position.Set(toWorld(x), toWorld(y)); ball = wp->CreateBody(&def); b2CircleShape shape; shape.m_p.SetZero(); shape.m_radius = toWorld(r) + R_INVIS; b2FixtureDef fd; fd.shape = &shape; fd.density = DYN_DENSITY; fd.friction = FRICTION; fd.restitution = RESTITUTION; ball->CreateFixture(&fd); ball->SetBullet(true); ball->SetUserData(userData); return ball; } +b2Body* World::addHandle(int x, int y, int hw, int hh, IBox2DItem* userData) { + HandleW = hw; HandleH = hh; + if (handle != NULL) { + wp->DestroyBody(handle); + } + b2BodyDef def; + def.type = b2_staticBody; + def.position.Set(toWorld(x), toWorld(y)); + handle = wp->CreateBody(&def); + b2PolygonShape box; + box.SetAsBox(toWorld(hw), toWorld(hh)); + b2FixtureDef fd; + fd.shape = &box; + fd.density = DYN_DENSITY; + fd.friction = FRICTION; + fd.restitution = RESTITUTION; + handle->CreateFixture(&fd); + handle->SetUserData(userData); + return handle; +} +void World::moveHandle(int x, int y) { + isHandleCreated = true; + HandleX = x; +} float32 World::getTimeStep() { uint64 t = s3eTimerGetMs(); int r = (int)(t - timestamp); timestamp = t; return (float32)r / 1000.0f; } void World::start() { if (ball != NULL) { ball->ApplyLinearImpulse(ball->GetWorldVector(b2Vec2(-10.0f, -10.0f)), ball->GetWorldPoint(b2Vec2(0.0f, 0.0f))); } } void World::impact(b2Body* b) { IBox2DItem* it = (IBox2DItem*)b->GetUserData(); if (it != NULL) { if (it->impact(b)) { for (BIter p = broken->begin(); p != broken->end(); ++p) { if (*p == b) return; } broken->push_back(b); } } } void World::PostSolve(b2Contact* contact, const b2ContactImpulse* impulse) { impact(contact->GetFixtureA()->GetBody()); impact(contact->GetFixtureB()->GetBody()); } void World::update() { if (!isStarted) { isStarted = true; start(); timestamp = s3eTimerGetMs(); srand((unsigned int)timestamp); } else { float32 timeStep = getTimeStep(); wp->Step(timeStep, V_ITERATIONS, P_ITERATIONS); } } void World::refresh() { for (BIter p = broken->begin(); p != broken->end(); ++p) { wp->DestroyBody(*p); } broken->clear(); + if (isHandleCreated) { + if (handle != NULL) { + int y = fromWorld(handle->GetPosition().y); + IBox2DItem* data = (IBox2DItem*)handle->GetUserData(); + if (HandleX < HandleW) { + HandleX = HandleW; + } + if (HandleX > desktop.getWidth() - HandleW) { + HandleX = desktop.getWidth() - HandleW; + } + handle = addHandle(HandleX, y, HandleW, HandleH, data); + b2Vec2 pos = handle->GetPosition(); + data->setXY(fromWorld(pos.x), fromWorld(pos.y)); + } + } if (ball != NULL) { b2Vec2 pos = ball->GetPosition(); Ball* b = (Ball*)ball->GetUserData(); if (b != NULL) { b->setXY(fromWorld(pos.x), fromWorld(pos.y)); } } }
Board.h #ifndef _BOARD_H_ #define _BOARD_H_ #include <yaml.h> #include <vector> #include <String> #include "Bricks.h" #include "Ball.h" +#include "Handle.h" #define MAX_NAME_SZ 100 using namespace std; enum EBrickMask { ebmX = 0x01, ebmY = 0x02, ebmComplete = 0x03, ebmWidth = 0x04, ebmHeight = 0x08, ebmIColor = 0x10, ebmOColor = 0x20 }; class Board { private: struct Type { Type(const char* s, const char* n, const char* v): s(s), n(n), v(v) {} Type(const Type& p): s(ps), n(pn), v(pv) {} string s, n, v; }; Bricks bricks; Ball ball; + Handle handle; yaml_parser_t parser; yaml_event_t event; vector<string> scopes; vector<Type> types; char currName[MAX_NAME_SZ]; int brickMask; int brickX, brickY, brickW, brickH, brickIC, brickOC; bool isTypeScope; void load(); void clear(); void notify(); const char* getScopeName(); void setProperty(const char* scope, const char* name, const char* value); void closeTag(const char* scope); int fromNum(const char* s); public: Board(): scopes(), types() {} void init(); void release(); void refresh(); void update(); typedef vector<string>::iterator SIter; typedef vector<Type>::iterator TIter; }; #endif // _BOARD_H_
Board.cpp #include "Board.h" #include "Desktop.h" const char* BOARD_SCOPE = "board"; const char* LEVEL_SCOPE = "level"; const char* TYPE_SCOPE = "types"; const char* TYPE_PROPERTY = "type"; const char* WIDTH_PROPERTY = "width"; const char* HEIGHT_PROPERTY = "height"; const char* IC_PROPERTY = "inner_color"; const char* OC_PROPERTY = "outer_color"; const char* X_PROPERTY = "x"; const char* Y_PROPERTY = "y"; void Board::init() { ball.init(); bricks.init(); + handle.init(); load(); } void Board::release() { + handle.release(); bricks.release(); ball.release(); } ... void Board::refresh() { bricks.refresh(); ball.refresh(); + handle.refresh(); } +void Board::update() { + handle.update(); +}
рд╡рд╣ рд╕рдм рд╣реИред
рдЕрдм, рд╣рдорд╛рд░реЗ рдкрд╛рд╕ Arcanoid рдЧреЗрдо рдХрд╛ рдПрдХ рдХрд╛рд░реНрдпрд╢реАрд▓ рдкреНрд░реЛрдЯреЛрдЯрд╛рдЗрдк рд╣реИ, рдЬрд┐рд╕реЗ Android рдФрд░ iPhone рджреЛрдиреЛрдВ рдХреЗ рд▓рд┐рдП рдмрдирд╛рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред