我为我公司的其他学员编写了一个(或多或少)简单的俄罗斯方块游戏作为例子。由于我已经习惯了我的编码风格,所以我想让其他人来查看它,也许可以给我一些建议来提高代码的可读性。
选择代码中的一些类名(比如演员)是为了给出一些关于电子游戏中的部分的更一般的想法(不是说我是那个领域的专家),所以如果我想开发一个俄罗斯方块游戏,也许我会选择不同的名称,所以请记住这一点。
是的,我计划将代码拆分到头/cpp文件中,是的,我忽略了头保护。
打字机h:
//The pixelUtility isn't included in the uploaded code since that is what i provide others as a "blackbox" library to work with, as well as the mangolib.h
//Please focus at the game code and not the naming of the mango:: or the graphic:: classes/structs, they will be explained to the people who use them pretty extensive
//The mango library is used since it implements some c++11 features I want to use and our IDE does not provide (shared_ptr and lambda for instance and later threading)
//btw. feel free to use this code as you please, as general example or if necessary (I hope it's not that bad ;) ) as negativ example, but I won't provide
//a code sample without my library, but im pretty sure it won't be much work to change the code to regular c++11 for whoever wants to use it.
#define NO_THREAD_ALLOC //disables thread_safety in my customallocator for better performance since this project is single threaded and locks are not needed
#include <Gaming/pixelutility.h> //header which contains graphic::Character, the GraphicController the KatCoord struct etc, includes <mangolib.h> --> mango::
namespace engine
{
typedef typename graphic::Character actor; //a simple graphic class with a position, animations and collision
typedef typename mango::shared_ptr<graphic::Character> actor_handle;
typedef typename mango::vector<mango::shared_ptr<graphic::Character> > actor_list;
typedef typename graphic::KatCoord point; //simple point class p(int32 x, int32 y)
typedef typename mango::vector<graphic::KatCoord> point_list;
typedef mango::int32 layerID;
typedef mango::int32 counter;
}石碑:
#include "typedefs.h"
#define Rot0 0
#define Rot90 1
#define Rot180 2
#define Rot270 3
namespace engine
{
namespace tetris
{
namespace shapes
{
enum shape
{
RLShape,
LLShape,
NTShape,
NIShape,
RZShape,
LZShape,
SQShape
};
}
//Shapes
//
// RL: #
// #
// # #
//
// LL: #
// #
// # #
//
// NT: # # #
// #
//
// NI: #
// #
// #
// #
//
// RZ: #
// # #
// #
//
// LZ: #
// # #
// #
//
// SQ: # #
// # #
//
//Shapes
typedef typename shapes::shape shape;
class RotationProcessor //this class is meant to make the Stone class smaller so I outsourced the rotation to this class
{
public:
void Rotate(mango::shared_ptr<engine::actor_list> segments, mango::int32& state, shape sh, bool counterClockwise)
{
switch (sh)
{
case shapes::RLShape:
RotateRL(segments, state, counterClockwise);
break;
case shapes::LLShape:
RotateLL(segments, state, counterClockwise);
break;
case shapes::NTShape:
RotateNT(segments, state, counterClockwise);
break;
case shapes::NIShape:
RotateNI(segments, state, counterClockwise);
break;
case shapes::RZShape:
RotateRZ(segments, state, counterClockwise);
break;
case shapes::LZShape:
RotateLZ(segments, state, counterClockwise);
break;
default:
break;
}
}
void RotateNI(mango::shared_ptr<engine::actor_list> segments, mango::int32& state, bool counterClockwise)
{
if (counterClockwise)
{
RotateNI(segments, state, false);
RotateNI(segments, state, false);
}
if (!state)
{
segments->at(0)->Move( 0, 20);
segments->at(1)->Move( 10, 10);
segments->at(2)->Move( 20, 0);
segments->at(3)->Move( 30, -10);
state = !state;
return;
}
segments->at(0)->Move( 0, -20);
segments->at(1)->Move(-10, -10);
segments->at(2)->Move(-20, 0);
segments->at(3)->Move(-30, 10);
state = !state;
return;
}
void RotateRZ(mango::shared_ptr<engine::actor_list> segments, mango::int32& state, bool counterClockwise)
{
if (counterClockwise)
{
RotateRZ(segments, state, false);
RotateRZ(segments, state, false);
}
if(!state)
{
segments->at(0)->Move( 20, 10);
segments->at(1)->Move( 10, 0);
segments->at(2)->Move( 0 , 10);
segments->at(3)->Move(-10, 0);
state = !state;
return;
}
segments->at(0)->Move(-20, -10);
segments->at(1)->Move(-10, 0);
segments->at(2)->Move( 0, -10);
segments->at(3)->Move( 10, 0);
state = !state;
return;
}
void RotateLZ(mango::shared_ptr<engine::actor_list> segments, mango::int32& state, bool counterClockwise)
{
if (counterClockwise)
{
RotateLZ(segments, state, false);
RotateLZ(segments, state, false);
}
if (!state)
{
segments->at(0)->Move(-10, 10);
segments->at(1)->Move( 0, 0);
segments->at(2)->Move( 10, 10);
segments->at(3)->Move( 20, 0);
state = !state;
return;
}
segments->at(0)->Move( 10, -10);
segments->at(1)->Move( 0, 0);
segments->at(2)->Move(-10, -10);
segments->at(3)->Move(-20, 0);
state = !state;
return;
}
void RotateLL(mango::shared_ptr<engine::actor_list> segments, mango::int32& state, bool counterClockwise)
{
if (counterClockwise)
{
RotateLL(segments, state, false);
RotateLL(segments, state, false);
}
if (Rot0 == state)
{
segments->at(0)->Move( 10, 20);
segments->at(1)->Move( 0, 10);
segments->at(2)->Move(-10, 0);
segments->at(3)->Move( 0, -10);
++state;
return;
}
if (Rot90 == state)
{
segments->at(0)->Move(-20, 0);
segments->at(1)->Move(-10, -10);
segments->at(2)->Move( 0, -20);
segments->at(3)->Move( 10, -10);
++state;
return;
}
if (Rot180 == state)
{
segments->at(0)->Move( 0, -10);
segments->at(1)->Move( 10, 0);
segments->at(2)->Move( 20, 10);
segments->at(3)->Move( 10, 20);
++state;
return;
}
if (Rot270 == state)
{
segments->at(0)->Move( 10, -10);
segments->at(1)->Move( 0, 0);
segments->at(2)->Move(-10, 10);
segments->at(3)->Move(-20, 0);
state = Rot0;
return;
}
return;
}
void RotateRL(mango::shared_ptr<engine::actor_list> segments, mango::int32& state, bool counterClockwise) //GOTO:
{
if (counterClockwise)
{
RotateRL(segments, state, false);
RotateRL(segments, state, false);
}
if (Rot0 == state)
{
segments->at(0)->Move( 20, 10);
segments->at(1)->Move( 10, 0);
segments->at(2)->Move( 0, -10);
segments->at(3)->Move(-10, 0);
++state;
return;
}
if (Rot90 == state)
{
segments->at(0)->Move(-10, 10);
segments->at(1)->Move( 0, 0);
segments->at(2)->Move( 10, -10);
segments->at(3)->Move( 0, -20);
++state;
return;
}
if (Rot180 == state)
{
segments->at(0)->Move(-10, 0);
segments->at(1)->Move( 0, 10);
segments->at(2)->Move( 10, 20);
segments->at(3)->Move( 20, 10);
++state;
return;
}
if (Rot270 == state)
{
segments->at(0)->Move( 0, -20);
segments->at(1)->Move(-10, -10);
segments->at(2)->Move(-20, 0);
segments->at(3)->Move(-10, 10);
state = Rot0;
return;
}
return;
}
void RotateNT(mango::shared_ptr<engine::actor_list> segments, mango::int32& state, bool counterClockwise)
{
if (counterClockwise)
{
RotateNT(segments, state, false);
RotateNT(segments, state, false);
}
if (Rot0 == state)
{
segments->at(0)->Move( 0, 0);
segments->at(1)->Move(-10, -10);
segments->at(2)->Move( 0, -20);
segments->at(3)->Move(-20, 0);
++state;
return;
}
if (Rot90 == state)
{
segments->at(0)->Move( 0, 10);
segments->at(1)->Move( 10, 0);
segments->at(2)->Move( 20, 10);
segments->at(3)->Move( 0, -10);
++state;
return;
}
if (Rot180 == state)
{
segments->at(0)->Move(-10, -10);
segments->at(1)->Move( 0, 0);
segments->at(2)->Move(-10, 10);
segments->at(3)->Move( 10, -10);
++state;
return;
}
if (Rot270 == state)
{
segments->at(0)->Move( 10, 0);
segments->at(1)->Move( 0, 10);
segments->at(2)->Move(-10, 0);
segments->at(3)->Move( 10, 20);
state = Rot0;
return;
}
return;
}
};
class Stone
{
public:
Stone(mango::shared_ptr<engine::actor_list> segments, mango::shared_ptr<engine::point_list> collisionPoints, engine::point pos, shape sh)
: m_Segments(segments), m_CollisionPoints(collisionPoints), m_Position(pos), m_Shape(sh), m_State(0)
{}
void Draw(Gdiplus::Graphics* graphic, mango::mutex& lock)
{
lambda((engine::actor_handle actor, Gdiplus::Graphics* graphic, mango::mutex& lock) { actor->Draw(graphic, lock); return 0; }, 1);
mango::for_each(m_Segments->begin(), m_Segments->end(), exp1, graphic, lock);
}
void Rotate(bool counterClockwise)
{
RotationProcessor re;
re.Rotate(m_Segments, m_State, m_Shape, counterClockwise);
mango::shared_ptr<engine::point_list> tmpCollisionPoints = GetPoints(m_Segments);
m_CollisionPoints->swap(*tmpCollisionPoints);
}
void Move(mango::int32 x, mango::int32 y)
{
m_Position.X += x;
m_Position.Y += y;
lambda((engine::actor_handle actor, mango::int32 x, mango::int32 y) { actor->Move(x, y); return 0; }, 1);
mango::for_each(m_Segments->begin(), m_Segments->end(), exp1, x, y);
m_CollisionPoints = GetPoints(m_Segments);
}
bool Contains(mango::shared_ptr<Stone> actor)
{
mango::int32 result = 0;
mango::int32* resultHandle = &result;
lambda((engine::actor_handle actor, const engine::point_list& points, mango::int32* result)
{
for (mango::int32 current = 0; points.size() > current; ++current)
{
*result += actor->Contains(points.at(current));
}
return 0;
}, 1);
mango::for_each(m_Segments->begin(), m_Segments->end(), exp1, *actor->m_CollisionPoints, resultHandle);
return result != 0;
}
bool ContainedBy(mango::shared_ptr<engine::actor> actor)
{
mango::int32 result = 0;
for (mango::int32 current = 0; m_CollisionPoints->size() > current; ++current)
{
result += actor->Contains(m_CollisionPoints->at(current));
}
return result != 0;
}
mango::shared_ptr<engine::actor_list> GetSegments()
{
mango::shared_ptr<engine::actor_list> tmp = m_Segments;
m_Segments.reset();
return tmp;
}
bool GetVisibility()
{
return true;
}
static mango::shared_ptr<engine::point_list> GetPoints(mango::shared_ptr<engine::actor_list> actors)
{
mango::shared_ptr<engine::point_list> tmpCP = new engine::point_list();
for (mango::int32 current = 0; actors->size() > current; ++current)
{
engine::point pos = actors->at(current)->GetPosition();
tmpCP->push_back(engine::point(pos.X + 1, pos.Y + 1));
tmpCP->push_back(engine::point(pos.X + 9, pos.Y + 1));
tmpCP->push_back(engine::point(pos.X + 9, pos.Y + 9));
tmpCP->push_back(engine::point(pos.X + 1, pos.Y + 9));
tmpCP->push_back(engine::point(pos.X + 3, pos.Y + 3));
tmpCP->push_back(engine::point(pos.X + 7, pos.Y + 7));
tmpCP->push_back(engine::point(pos.X + 7, pos.Y + 3));
tmpCP->push_back(engine::point(pos.X + 3, pos.Y + 7));
}
return tmpCP;
}
private:
mango::shared_ptr<engine::actor_list> m_Segments;
mango::shared_ptr<engine::point_list> m_CollisionPoints;
engine::point m_Position;
shape m_Shape;
mango::int32 m_State;
};
typedef typename Stone t_actor;
typedef typename mango::shared_ptr<Stone> t_actor_handle;
typedef typename mango::vector<mango::shared_ptr<Stone> > t_actor_list;
//not optimal naming ---> t_ => tetris_ to make it easier to spot if you have an engine::actor or a engine::tetris::actor
class StoneFactory
{
public:
StoneFactory(mango::int32 stoneSize)
: m_StoneSize(stoneSize)
{}
t_actor_handle BuildStone(shape stoneShape, engine::point pos)
{
switch (stoneShape)
{
case shapes::RLShape:
return BuildRLStone(pos, stoneShape);
break;
case shapes::LLShape:
return BuildLLStone(pos, stoneShape);
break;
case shapes::NTShape:
return BuildNTStone(pos, stoneShape);
break;
case shapes::NIShape:
return BuildNIStone(pos, stoneShape);
break;
case shapes::RZShape:
return BuildRZStone(pos, stoneShape);
break;
case shapes::LZShape:
return BuildLZStone(pos, stoneShape);
break;
case shapes::SQShape:
return BuildSQStone(pos, stoneShape);
break;
default:
return nullptr;
break;
}
return nullptr;
}
private:
t_actor_handle BuildSQStone(engine::point pos, shape sh)
{
engine::point pos1 = pos;
engine::point pos2 = pos;
engine::point pos3 = pos;
engine::point pos4 = pos;
pos1.Y += 10;
pos2.Y += 20;
pos3.Y += 10;
pos4.Y += 20;
pos3.X += 10;
pos4.X += 10;
mango::shared_ptr<engine::actor_list> actors = new engine::actor_list();
engine::actor_handle tmp = new engine::actor(pos1, m_StoneSize, m_StoneSize);
tmp->LoadAnimation(0, "square_vm", 1);
actors->push_back(tmp);
tmp = new engine::actor(pos2, m_StoneSize, m_StoneSize);
tmp->LoadAnimation(0, "square_vm", 1);
actors->push_back(tmp);
tmp = new engine::actor(pos3, m_StoneSize, m_StoneSize);
tmp->LoadAnimation(0, "square_vm", 1);
actors->push_back(tmp);
tmp = new engine::actor(pos4, m_StoneSize, m_StoneSize);
tmp->LoadAnimation(0, "square_vm", 1);
actors->push_back(tmp);
t_actor_handle tmpActor = new t_actor(actors, t_actor::GetPoints(actors), pos, sh);
return tmpActor;
}
t_actor_handle BuildRLStone(engine::point pos, shape sh)
{
engine::point pos1 = pos;
engine::point pos2 = pos;
engine::point pos3 = pos;
engine::point pos4 = pos;
pos2.Y += 10;
pos3.Y += 20;
pos4.X += 10;
pos4.Y += 20;
mango::shared_ptr<engine::actor_list> actors = new engine::actor_list();
engine::actor_handle tmp = new engine::actor(pos1, m_StoneSize, m_StoneSize);
tmp->LoadAnimation(0, "square_bm", 1);
actors->push_back(tmp);
tmp = new engine::actor(pos2, m_StoneSize, m_StoneSize);
tmp->LoadAnimation(0, "square_bm", 1);
actors->push_back(tmp);
tmp = new engine::actor(pos3, m_StoneSize, m_StoneSize);
tmp->LoadAnimation(0, "square_bm", 1);
actors->push_back(tmp);
tmp = new engine::actor(pos4, m_StoneSize, m_StoneSize);
tmp->LoadAnimation(0, "square_bm", 1);
actors->push_back(tmp);
t_actor_handle tmpActor = new t_actor(actors, t_actor::GetPoints(actors), pos, sh);
return tmpActor;
}
t_actor_handle BuildLLStone(engine::point pos, shape sh)
{
engine::point pos1 = pos;
engine::point pos2 = pos;
engine::point pos3 = pos;
engine::point pos4 = pos;
pos1.X += 10;
pos2.Y += 10;
pos2.X += 10;
pos3.Y += 20;
pos3.X += 10;
pos4.Y += 20;
mango::shared_ptr<engine::actor_list> actors = new engine::actor_list();
engine::actor_handle tmp = new engine::actor(pos1, m_StoneSize, m_StoneSize);
tmp->LoadAnimation(0, "square_rm", 1);
actors->push_back(tmp);
tmp = new engine::actor(pos2, m_StoneSize, m_StoneSize);
tmp->LoadAnimation(0, "square_rm", 1);
actors->push_back(tmp);
tmp = new engine::actor(pos3, m_StoneSize, m_StoneSize);
tmp->LoadAnimation(0, "square_rm", 1);
actors->push_back(tmp);
tmp = new engine::actor(pos4, m_StoneSize, m_StoneSize);
tmp->LoadAnimation(0, "square_rm", 1);
actors->push_back(tmp);
t_actor_handle tmpActor = new t_actor(actors, t_actor::GetPoints(actors), pos, sh);
return tmpActor;
}
t_actor_handle BuildNTStone(engine::point pos, shape sh)
{
engine::point pos1 = pos;
engine::point pos2 = pos;
engine::point pos3 = pos;
engine::point pos4 = pos;
pos1.X += 10;
pos1.Y += 10;
pos2.X += 10;
pos2.Y += 20;
pos3.Y += 20;
pos4.X += 20;
pos4.Y += 20;
mango::shared_ptr<engine::actor_list> actors = new engine::actor_list();
engine::actor_handle tmp = new engine::actor(pos1, m_StoneSize, m_StoneSize);
tmp->LoadAnimation(0, "square_gm", 1);
actors->push_back(tmp);
tmp = new engine::actor(pos2, m_StoneSize, m_StoneSize);
tmp->LoadAnimation(0, "square_gm", 1);
actors->push_back(tmp);
tmp = new engine::actor(pos3, m_StoneSize, m_StoneSize);
tmp->LoadAnimation(0, "square_gm", 1);
actors->push_back(tmp);
tmp = new engine::actor(pos4, m_StoneSize, m_StoneSize);
tmp->LoadAnimation(0, "square_gm", 1);
actors->push_back(tmp);
t_actor_handle tmpActor = new t_actor(actors, t_actor::GetPoints(actors), pos, sh);
return tmpActor;
}
t_actor_handle BuildNIStone(engine::point pos, shape sh)
{
engine::point pos1 = pos;
engine::point pos2 = pos;
engine::point pos3 = pos;
engine::point pos4 = pos;
pos2.Y += 10;
pos3.Y += 20;
pos4.Y += 30;
mango::shared_ptr<engine::actor_list> actors = new engine::actor_list();
engine::actor_handle tmp = new engine::actor(pos1, m_StoneSize, m_StoneSize);
tmp->LoadAnimation(0, "square_ym", 1);
actors->push_back(tmp);
tmp = new engine::actor(pos2, m_StoneSize, m_StoneSize);
tmp->LoadAnimation(0, "square_ym", 1);
actors->push_back(tmp);
tmp = new engine::actor(pos3, m_StoneSize, m_StoneSize);
tmp->LoadAnimation(0, "square_ym", 1);
actors->push_back(tmp);
tmp = new engine::actor(pos4, m_StoneSize, m_StoneSize);
tmp->LoadAnimation(0, "square_ym", 1);
actors->push_back(tmp);
t_actor_handle tmpActor = new t_actor(actors, t_actor::GetPoints(actors), pos, sh);
return tmpActor;
}
t_actor_handle BuildRZStone(engine::point pos, shape sh)
{
engine::point pos1 = pos;
engine::point pos2 = pos;
engine::point pos3 = pos;
engine::point pos4 = pos;
pos2.Y += 10;
pos3.X += 10;
pos3.Y += 10;
pos4.X += 10;
pos4.Y += 20;
mango::shared_ptr<engine::actor_list> actors = new engine::actor_list();
engine::actor_handle tmp = new engine::actor(pos1, m_StoneSize, m_StoneSize);
tmp->LoadAnimation(0, "square_pm", 1);
actors->push_back(tmp);
tmp = new engine::actor(pos2, m_StoneSize, m_StoneSize);
tmp->LoadAnimation(0, "square_pm", 1);
actors->push_back(tmp);
tmp = new engine::actor(pos3, m_StoneSize, m_StoneSize);
tmp->LoadAnimation(0, "square_pm", 1);
actors->push_back(tmp);
tmp = new engine::actor(pos4, m_StoneSize, m_StoneSize);
tmp->LoadAnimation(0, "square_pm", 1);
actors->push_back(tmp);
t_actor_handle tmpActor = new t_actor(actors, t_actor::GetPoints(actors), pos, sh);
return tmpActor;
}
t_actor_handle BuildLZStone(engine::point pos, shape sh)
{
engine::point pos1 = pos;
engine::point pos2 = pos;
engine::point pos3 = pos;
engine::point pos4 = pos;
pos1.X += 10;
pos2.X += 10;
pos2.Y += 10;
pos3.Y += 10;
pos4.Y += 20;
mango::shared_ptr<engine::actor_list> actors = new engine::actor_list();
engine::actor_handle tmp = new engine::actor(pos1, m_StoneSize, m_StoneSize);
tmp->LoadAnimation(0, "square_tm", 1);
actors->push_back(tmp);
tmp = new engine::actor(pos2, m_StoneSize, m_StoneSize);
tmp->LoadAnimation(0, "square_tm", 1);
actors->push_back(tmp);
tmp = new engine::actor(pos3, m_StoneSize, m_StoneSize);
tmp->LoadAnimation(0, "square_tm", 1);
actors->push_back(tmp);
tmp = new engine::actor(pos4, m_StoneSize, m_StoneSize);
tmp->LoadAnimation(0, "square_tm", 1);
actors->push_back(tmp);
t_actor_handle tmpActor = new t_actor(actors, t_actor::GetPoints(actors), pos, sh);
return tmpActor;
}
mango::int32 m_StoneSize;
};
void rotatePoint(engine::point& p, const engine::point& center)
{
mango::int32 tmpX = p.X - center.X;
mango::int32 tmpY = p.Y - center.Y;
p.X = center.X + tmpY;
p.Y = center.Y - tmpX;
}
}
}工程师:
#include "typedefs.h"
#include "stone.h"
namespace engine
{
class Engine
{
public:
Engine()
: m_Graphic(new graphic::GraphicController()), m_Factory(10), m_UpdateInterval(0.5f), m_SoundDuration(83.0f)
{
srand((mango::uns32)time(nullptr));
CreateNewPlayerActor();
//the magic numbers will be wrapped in const values when I split the files in header/cpp
m_Ground = new engine::actor(engine::point(0, 290), 640, 50, 0, false); //engine::actor(point position, int32 width, int32 height, int32 renderLayer, bool visibility);
m_Ground->LoadAnimation(0, "default", 1); //LoadAnimation(int32 animationID, string fileName, int32 numberOfFrames); //"default" is an empty transparent sprite
m_Background = new engine::actor(engine::point(8, -8), 204, 291, 0, true);
m_Background->LoadAnimation(0, "Background", 1);
m_LeftBorder = new engine::actor(engine::point(0, 0), 10, 290, 0, false);
m_LeftBorder->LoadAnimation(0, "default", 1);
m_RightBorder = new engine::actor(engine::point(210, 0), 10, 290, 0, false);
m_RightBorder->LoadAnimation(0, "default", 1);
for (mango::int32 current = 0; 290 > current * 10; ++current)
{
m_Layers.push_back(mango::key_pair<layerID, counter>(current, 0));
}
}
void Play()
{
bool isRunning = true;
m_Timer.start();
m_SpeedTimer.start();
m_SoundTimer.start();
audio::playSound("Sounds\\sound.wav");
while (isRunning && nullptr != m_PlayerActor)
{
Audio();
Move();
Controls(isRunning);
Draw();
Present();
}
audio::stopSound();
}
private:
void Audio()
{
m_SoundTimer.tick();
if (m_SoundDuration <= m_SoundTimer.totalTime())
{
audio::stopSound();
audio::playSound("Sounds\\sound.wav");
ResetTimer(m_SoundTimer);
}
}
void CreateNewPlayerActor()
{
while (nullptr == m_PlayerActor)
{
mango::int32 shape = rand() % 40; //I chose a higher value to get more different shapes spawned
m_PlayerActor = m_Factory.BuildStone(*reinterpret_cast<engine::tetris::shape*>(&shape), engine::point(150, 1));
}
}
void RemoveLayer(mango::int32 layer)
{
for (mango::int32 current = 0; m_Actors.size() > current; ++current) //erase actors in layer
{
if ((mango::int32)(m_Actors.at(current)->GetPosition().Y / 10) == layer)
{
m_Actors.erase(current);
--current;
}
}
for (mango::int32 current = 0; m_Actors.size() > current; ++current) //move down actors in higher layers
{
if ((mango::int32)(m_Actors.at(current)->GetPosition().Y / 10) < layer)
{
m_Actors.at(current)->Move(0, 10);
}
}
for (mango::int32 current = layer; 0 < current; --current)
{
m_Layers.at(current).a = m_Layers.at(current - 1).a; // mango::key_pair<class KEY, class A> x; ---> x.a; to access the value;
}
m_Layers.front().a = 0;
}
void Collision()
{
if (0 < m_Layers.at(4).a) //Layer 4 is the highest layer to reach until game over
{
m_Actors.clear();
m_PlayerActor.reset();
m_Background = new engine::actor(engine::point(10, 100), 600, 100);
m_Background->LoadAnimation(0, "game_over", 1);
return;
}
//lambda((parameters){function}, int32 ID); --> exp + ID is used to call the expression the id has to be unique in its scope
mango::int32 result = 0;
lambda((engine::actor_handle actor, engine::tetris::t_actor_handle playerActor, mango::int32& result)
{
if (playerActor->ContainedBy(actor))
{
++result;
}
return 0;
}, 2);
if (0 != m_Actors.size())
{
mango::for_each(m_Actors.begin(), m_Actors.end(), exp2, m_PlayerActor, result);
}
if (m_PlayerActor->ContainedBy(m_Ground) || 0 != result)
{
m_PlayerActor->Move(0, -10);
mango::shared_ptr<engine::actor_list> actors = m_PlayerActor->GetSegments();
for (mango::int32 current = 0; actors->size() > current; ++current) //transfer segments to global actor pipeline
{
m_Actors.push_back(actors->at(current));
++m_Layers.at((actors->at(current)->GetPosition().Y) / 10).a;
}
m_PlayerActor.reset();
CreateNewPlayerActor();
const mango::int32 layerWidth = 20;
for (mango::int32 current = m_Layers.size() - 1; 0 <= current; --current) //Remove Filled layers
{
if (layerWidth == m_Layers.at(current).a)
{
RemoveLayer(current);
current = m_Layers.size() - 1;
}
}
}
}
void ResetTimer(mango::delta_timer& timer)
{
timer.stop();
timer.reset();
timer.start();
}
void ChangeSpeed()
{
m_SpeedTimer.tick();
if (30.0f <= m_SpeedTimer.totalTime() && m_UpdateInterval > 0.1f)
{
ResetTimer(m_SpeedTimer);
m_UpdateInterval -= 0.05f; //increase game speed over time
}
}
void Move()
{
m_Timer.tick();
if (m_UpdateInterval <= m_Timer.totalTime())
{
ResetTimer(m_Timer);
ChangeSpeed();
m_PlayerActor->Move(0, 10); //move player down
Collision();
}
}
void TryRotationLeft()
{
m_PlayerActor->Rotate(true);
mango::int32 result = 0;
lambda((engine::actor_handle actor, engine::tetris::t_actor_handle playerActor, mango::int32& result)
{
if (playerActor->ContainedBy(actor))
{
++result;
}
return 0;
}, 2);
if (0 != m_Actors.size())
{
mango::for_each(m_Actors.begin(), m_Actors.end(), exp2, m_PlayerActor, result);
}
if (0 != result || m_PlayerActor->ContainedBy(m_LeftBorder) || m_PlayerActor->ContainedBy(m_RightBorder))
{
m_PlayerActor->Rotate(false); //undo rotation if collision detected
}
}
void TryRotationRight()
{
m_PlayerActor->Rotate(false);
mango::int32 result = 0;
lambda((engine::actor_handle actor, engine::tetris::t_actor_handle playerActor, mango::int32& result)
{
if (playerActor->ContainedBy(actor))
{
++result;
}
return 0;
}, 2);
if (0 != m_Actors.size())
{
mango::for_each(m_Actors.begin(), m_Actors.end(), exp2, m_PlayerActor, result);
}
if (0 != result || m_PlayerActor->ContainedBy(m_LeftBorder) || m_PlayerActor->ContainedBy(m_RightBorder))
{
m_PlayerActor->Rotate(true); //undo rotation if collision detected
}
}
void TryMoveLeft()
{
m_PlayerActor->Move(-10, 0);
mango::int32 result = 0;
lambda((engine::actor_handle actor, engine::tetris::t_actor_handle playerActor, mango::int32& result)
{
if (playerActor->ContainedBy(actor))
{
++result;
}
return 0;
}, 2);
if (0 != m_Actors.size())
{
mango::for_each(m_Actors.begin(), m_Actors.end(), exp2, m_PlayerActor, result);
}
if (0 != result || m_PlayerActor->ContainedBy(m_LeftBorder) || m_PlayerActor->ContainedBy(m_RightBorder))
{
m_PlayerActor->Move(10, 0);
}
}
void TryMoveRight()
{
m_PlayerActor->Move(10, 0);
mango::int32 result = 0;
lambda((engine::actor_handle actor, engine::tetris::t_actor_handle playerActor, mango::int32& result)
{
if (playerActor->ContainedBy(actor))
{
++result;
}
return 0;
}, 2);
if (0 != m_Actors.size())
{
mango::for_each(m_Actors.begin(), m_Actors.end(), exp2, m_PlayerActor, result);
}
if (0 != result || m_PlayerActor->ContainedBy(m_LeftBorder) || m_PlayerActor->ContainedBy(m_RightBorder))
{
m_PlayerActor->Move(-10, 0);
}
}
void TryMoveDown()
{
m_PlayerActor->Move(0, 10);
Collision();
}
void Controls(bool& isRunning)
{
mango::Byte input = ' ';
if (_kbhit())
{
input = mango::archive::mgetch();
if ('q' == input)
{
TryRotationLeft();
}
if ('e' == input)
{
TryRotationRight();
}
if ('a' == input)
{
TryMoveLeft();
}
if ('d' == input)
{
TryMoveRight();
}
if ('s' == input)
{
TryMoveDown();
}
if ('X' == input)
{
isRunning = false;
}
}
}
void Draw()
{
m_Graphic->ClearBuffer();
m_Graphic->Draw(m_Background.get()); //Background is drawn first
lambda((engine::actor_handle actor, graphic::GraphicController* gc) { gc->Draw(actor.get()); return 0; }, 1);
if (0 != m_Actors.size())
{
mango::for_each(m_Actors.begin(), m_Actors.end(), exp1, m_Graphic);
}
if (nullptr != m_PlayerActor) //Player is drawn last
{
m_Graphic->Draw(m_PlayerActor.get());
}
}
void Present()
{
m_Graphic->Present();
}
mango::vector<mango::key_pair<mango::int32, mango::int32> > m_Layers;
engine::actor_handle m_RightBorder; //Special basic Actor
engine::actor_handle m_LeftBorder; //Special basic Actor
engine::actor_handle m_Background; //Special basic Actor
engine::actor_handle m_Ground; //Special basic Actor
engine::tetris::t_actor_handle m_PlayerActor; //Special tetris Actor (t_actor --> tetris_actor)
mango::shared_ptr<graphic::GraphicController> m_Graphic; //Graphic controller which contains "swap_chain" buffers and draw capabilities
engine::tetris::StoneFactory m_Factory; //Creates stones (t_actors)
engine::actor_list m_Actors; //All other Actors
mango::delta_timer m_Timer; //Core game timer to specify update rate
mango::delta_timer m_SpeedTimer; //Timer which indicates the increase game speed over time
mango::delta_timer::seconds m_UpdateInterval; //Interval witch controls the update rate --> higher update right faster game
mango::delta_timer m_SoundTimer; //Timer which tracks the duration of the background sound
mango::delta_timer::seconds m_SoundDuration; //duration of the background sound file
};
}main.cpp:
#include "engine.h"
mango::int32 main()
{
mango::shared_ptr<engine::Engine> game(new engine::Engine);
game->Play();
mango::archive::mgetch(); //Wrapper for _getch()
return 0;
}这是一张跑步游戏的图片:

正如我已经提到的,可以随意重用代码。
发布于 2017-03-23 10:41:57
嗯,imho中有一些C结构,当您试图编写C++时。
例如
typedef typename graphic::Character actor;会像这样更好:
using actor=graphic::Character;但也许这只是一个编码风格的东西。
然后可以将typedef typename shapes::shape shape;简化为using shape::shape;。
然后,例如void Rotate(mango::shared_ptr<engine::actor_list> segments,,因为您已经在名称空间engine中,编写mango::shared_ptr<actor_list>可能就足够了。如果您之前定义了using mango::shared_ptr;,甚至可以将其简化为
void Rotate(shared_ptr<actor_list> segments我会将类RotationProcessor和StoneFactory放在一个单独的文件中。
关于文件:不要在头文件中写入您的实现。头文件只应包含定义。C文件包含实现。(唯一的例外是模板类和-functions。)
关于模板:RotateXX函数似乎有很多共同之处。有什么方法可以提取共性并编写单个模板函数吗?那么您需要维护的代码就会少得多。
还有关于RotateXX函数:目前这些函数是作为成员函数实现的:您需要一个对象来使用它们。但是,它们不依赖于RotationProcessor对象。所以为什么不让他们成为static。这样你就可以用RotationProcessor::Rotate(...);打电话给他们。
我在想这个功能:
mango::shared_ptr<engine::actor_list> GetSegments()
{
mango::shared_ptr<engine::actor_list> tmp = m_Segments;
m_Segments.reset();
return tmp;
}因此,m_Segments内容的所有权被转移到GetSegments()的调用方。对我来说,这听起来更像是unique_ptr,而不是shared_ptr。
最后,尝试从代码中删除所有幻数。例如:
m_PlayerActor->Move(0, -10);包含两个幻数。更好的方法是用(n内联)函数调用(C++样式)或至少定义(C-样式)替换行。
还有更多的东西,但我会把它留给其他人;)
编辑:好的,还有一件事:
if ('q' == input)
{
TryRotationLeft();
}
[...etc.etc...]
if ('X' == input)
{
isRunning = false;
}使用开关语句如何?例如:
switch (input) {
case 'q': TryRotationLeft(); break;
case 'e': TryRotationRight(); break;
case 'a': TryMoveLeft(); break;
case 'd': TryMoveRight(); break;
case 's': TryMoveDown(); break;
case 'X': isRunning = false; break;
}https://codereview.stackexchange.com/questions/158592
复制相似问题