首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >俄罗斯方块游戏的一般例子

俄罗斯方块游戏的一般例子
EN

Code Review用户
提问于 2017-03-23 08:46:05
回答 1查看 3.1K关注 0票数 8

我为我公司的其他学员编写了一个(或多或少)简单的俄罗斯方块游戏作为例子。由于我已经习惯了我的编码风格,所以我想让其他人来查看它,也许可以给我一些建议来提高代码的可读性。

选择代码中的一些类名(比如演员)是为了给出一些关于电子游戏中的部分的更一般的想法(不是说我是那个领域的专家),所以如果我想开发一个俄罗斯方块游戏,也许我会选择不同的名称,所以请记住这一点。

是的,我计划将代码拆分到头/cpp文件中,是的,我忽略了头保护。

打字机h:

代码语言:javascript
复制
//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;
}

石碑:

代码语言:javascript
复制
#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;
        }
    }
}

工程师:

代码语言:javascript
复制
#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:

代码语言:javascript
复制
#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;
}

这是一张跑步游戏的图片:

正如我已经提到的,可以随意重用代码。

EN

回答 1

Code Review用户

发布于 2017-03-23 10:41:57

嗯,imho中有一些C结构,当您试图编写C++时。

例如

代码语言:javascript
复制
typedef typename graphic::Character actor;

会像这样更好:

代码语言:javascript
复制
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;,甚至可以将其简化为

代码语言:javascript
复制
void Rotate(shared_ptr<actor_list> segments

我会将类RotationProcessorStoneFactory放在一个单独的文件中。

关于文件:不要在头文件中写入您的实现。头文件只应包含定义。C文件包含实现。(唯一的例外是模板类和-functions。)

关于模板:RotateXX函数似乎有很多共同之处。有什么方法可以提取共性并编写单个模板函数吗?那么您需要维护的代码就会少得多。

还有关于RotateXX函数:目前这些函数是作为成员函数实现的:您需要一个对象来使用它们。但是,它们不依赖于RotationProcessor对象。所以为什么不让他们成为static。这样你就可以用RotationProcessor::Rotate(...);打电话给他们。

我在想这个功能:

代码语言:javascript
复制
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

最后,尝试从代码中删除所有幻数。例如:

代码语言:javascript
复制
m_PlayerActor->Move(0, -10);

包含两个幻数。更好的方法是用(n内联)函数调用(C++样式)或至少定义(C-样式)替换行。

还有更多的东西,但我会把它留给其他人;)

编辑:好的,还有一件事:

代码语言:javascript
复制
if ('q' == input)
{
    TryRotationLeft();
}
[...etc.etc...]
if ('X' == input)
{
    isRunning = false;
}

使用开关语句如何?例如:

代码语言:javascript
复制
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;
}
票数 5
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/158592

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档