Немного c++ игровой движок 2D я сделал


Следующий код представляет собой "маленький" 2D движок, я разработал, чтобы играть вокруг немного. Кода зашел в один заголовок, не лучшая практика, но я хотел, чтобы двигатель Как подключить и головой играть, так что мне не придется добавить несколько файлов в проект.

Двигатель расчитан на Windows и работает с GDI+ в качестве графической библиотеки.

Я решил не включать "обычный" физико-часть, которая работает с регулярными тяжести, так как что бы раздуты еще больше. Единственный возможный физики на данный момент вроде невесомости физика. Физико расчеты не реальности соответствует, но они делают хорошее задание для предполагаемого использования.

Двигатель довольно ограничен, но должен быть абсолютно достаточно, чтобы крена меньше игр, таких как космических захватчиков, такие как игры или тетрис и понг. С гравитацией часть он бы даже быть в состоянии обрабатывать более мелкие sidescroll шутер.

Я активно решил использовать спрайт листы из-за лени, но я знаю, что через спрайт листы приведет к более высокой производительности в целом.

Двигатель имеет очень минималистичный компонент системы, который может быть продлен довольно легко и утилиты::актер может быть легко заменен индивидуальный класс, который наследует от обычного актера.

#include <Windows.h>
#include <stdio.h>
#include <gdiplus.h>
#include <dshow.h>
#include <string>
#include <memory>
#include <vector>
#include <algorithm>
#include <conio.h>
#include <ctime>
#include <functional>
#include <map>

#pragma comment(lib,"gdiplus.lib")
#pragma comment(lib, "winmm.lib")

#pragma warning( disable : 4996 )

namespace utility
{
    //I shifted the Vector2 struct into a seperate namespace so I can
    //make the operators global. Later I loaded Vector2 into the 
    //utility namespace so it's as easy accessible as the rest.

    //Vector2 is a 2D vector thought to store positions and motions- 

    namespace operators
    {
        struct Vector2;

        inline Vector2 operator + (const Vector2& a, const Vector2& b);
        inline Vector2 operator - (const Vector2& a, const Vector2& b);
        inline Vector2 operator * (const Vector2& a, const double& d);
        inline Vector2 operator / (const Vector2& a, const double& d);

        struct Vector2
        {
            Vector2(int x = 0, int y = 0)
                : X(x), Y(y)
            {}

            Vector2& operator += (const Vector2& a)
            {
                Vector2& me = *const_cast<Vector2*>(this);

                me = me + a;

                return me;
            }

            Vector2& operator -= (const Vector2& a)
            {
                Vector2& me = *const_cast<Vector2*>(this);

                me = me - a;

                return me;
            }

            Vector2& operator *= (const double& d)
            {
                Vector2& me = *const_cast<Vector2*>(this);

                me = me * d;

                return me;
            }

            Vector2& operator /= (const double& d)
            {
                Vector2& me = *const_cast<Vector2*>(this);

                me = me / d;

                return me;
            }

            int X;
            int Y;
        };

        inline Vector2 operator + (const Vector2& a, const Vector2& b)
        {
            return Vector2(a.X + b.X, a.Y + b.Y);
        }

        inline Vector2 operator - (const Vector2& a, const Vector2& b)
        {
            return Vector2(a.X - b.X, a.Y - b.Y);
        }

        inline Vector2 operator * (const Vector2& a, const double& d)
        {
            return Vector2((int)(a.X * d), (int)(a.Y * d));
        }

        inline Vector2 operator / (const Vector2& a, const double& d)
        {
            return Vector2((int)(a.X / d), (int)(a.Y / d));
        }
    }

    using Vector2 = operators::Vector2;

    //The FrameBuffer contains frame informations and the GDI graphics

    struct FrameBuffer
    {
        FrameBuffer(Vector2 res, HWND window = GetConsoleWindow())
        {
            wnd = window;

            Memhdc = 0;
            hdc = GetDC(wnd);

            GetClientRect(wnd, &Client_Rect);

            Memhdc = CreateCompatibleDC(hdc);
            Membitmap = CreateCompatibleBitmap(hdc, res.X, res.Y);

            SelectObject(Memhdc, Membitmap);

            Graphics = Gdiplus::Graphics::FromHDC(Memhdc);
        }

        ~FrameBuffer()
        {
            HDC          Memhdc = 0;
            HDC          hdc = 0;
            HBITMAP      Membitmap = 0;
            HWND         wnd = 0;

            SendMessage(wnd, WM_CLOSE, 0, 0);
        }

        RECT               Client_Rect;
        HDC                Memhdc;
        HDC                hdc;
        HBITMAP            Membitmap;
        HWND               wnd;

        Gdiplus::Graphics* Graphics;
    };

    //Simple object to initalize GDI

    class GDI
    {
    public:
        GDI()
        {
            GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
        }

        ~GDI()
        {
            Gdiplus::GdiplusShutdown(gdiplusToken);
        }

    private:
        Gdiplus::GdiplusStartupInput gdiplusStartupInput;
        ULONG_PTR gdiplusToken;
    };

    inline const wchar_t * to_wchar(const char *c)
    {
        const size_t cSize = strlen(c) + 1;
        wchar_t* wc = new wchar_t[cSize];
        mbstowcs(wc, c, cSize);

        return wc;
    }

    //Simple representation of a 2D sprite

    class Sprite
    {
    public:
        using GSprite = std::shared_ptr<Gdiplus::Image>;

        Sprite(Vector2 position, Vector2 resolution)
            : m_Bitmap(nullptr), m_Position(position), m_Resolution(resolution)
        {}

        Sprite(const Sprite& spr)
            : m_Bitmap(spr.m_Bitmap), m_Position(spr.m_Position), m_Resolution(spr.m_Resolution)
        {}

        Sprite& operator = (const Sprite& spr)
        {
            if (m_Bitmap)
            {
                m_Bitmap.reset();
            }

            m_Bitmap = spr.m_Bitmap;
            m_Position = spr.m_Position;
            m_Resolution = spr.m_Resolution;

            return *const_cast<Sprite*>(this);
        }

        ~Sprite()
        {}

        void loadSprite(std::string name, std::string path = "")
        {
            std::wstring nameAndPath = to_wchar((path + name + std::string(".png")).c_str());

            m_Bitmap = std::make_shared<Gdiplus::Image>(nameAndPath.c_str());
        }

        void draw(Gdiplus::Graphics* graphics) const
        {
            Gdiplus::RectF ImgRect((Gdiplus::REAL)m_Position.X, (Gdiplus::REAL)m_Position.Y, (Gdiplus::REAL)m_Resolution.X, (Gdiplus::REAL)m_Resolution.Y);
            graphics->DrawImage(m_Bitmap.get(), ImgRect);
        }

        void clear(Gdiplus::Graphics* graphics)
        {
            graphics->Clear(RGB(0, 0, 0));
        }

        void setPosition(Vector2 position)
        {
            m_Position = position;
        }

        void move(Vector2 motion)
        {
            m_Position += motion;
        }

        Vector2 getResolution() const
        {
            return m_Resolution;
        }

        Vector2 getPosition() const
        {
            return m_Position;
        }

    private:
        GSprite m_Bitmap;
        Vector2 m_Position;
        Vector2 m_Resolution;
    };

    //Contains a collection of sprites and data to paly animations

    class Animation
    {
    public:
        Animation(std::string animationName, Vector2 position, Vector2 resolution)
            : m_AnimationName(animationName), m_Position(position), m_Resolution(resolution), m_CurrentFrame(0)
        {}

        Animation(const Animation& anim)
            : m_Frames(anim.m_Frames), m_AnimationName(anim.m_AnimationName), m_Position(anim.m_Position), m_Resolution(anim.m_Resolution), m_CurrentFrame(0)
        {}

        Animation& operator = (const Animation& anim)
        {
            m_Frames = anim.m_Frames;
            m_AnimationName = anim.m_AnimationName;
            m_Position = anim.m_Position;
            m_Resolution = anim.m_Resolution;
            m_CurrentFrame = 0;

            return *const_cast<Animation*>(this);
        }

        void draw(Gdiplus::Graphics* graphics) const
        {
            m_Frames.at(m_CurrentFrame)->draw(graphics);
        }

        void update()
        {
            m_CurrentFrame + 1 == m_Frames.size() ? m_CurrentFrame = 0 : ++m_CurrentFrame;
        }

        void loadAnimation(std::string name, int numberOfFrames, std::string path = "")
        {
            for (int frameToLoad = 0; numberOfFrames > frameToLoad; ++frameToLoad)
            {
                m_Frames.push_back(std::make_shared<Sprite>(m_Position, m_Resolution));
                m_Frames.back()->loadSprite(name + std::to_string(frameToLoad), path);
            }
        }

        void setPosition(Vector2 position)
        {
            std::for_each(m_Frames.begin(), m_Frames.end(), [&](std::shared_ptr<Sprite> sprite)->void { sprite->setPosition(position); });
        }

        void move(Vector2 motion)
        {
            std::for_each(m_Frames.begin(), m_Frames.end(), [&](std::shared_ptr<Sprite> sprite)->void { sprite->move(motion); });
        }

        Vector2 getResolution() const
        {
            return m_Resolution;
        }

        Vector2 getPosition() const
        {
            return m_Position;
        }

    private:
        std::vector<std::shared_ptr<Sprite> > m_Frames;
        std::string                           m_AnimationName;
        Vector2                               m_Position;
        Vector2                               m_Resolution;
        int                                   m_CurrentFrame;
    };

    //General object for graphical interactions like drawing, etc

    class GraphicController
    {
    public:
        GraphicController(HWND window, Vector2 resolution)
            : m_Resolution(resolution), m_Buffer(m_Resolution, window), m_GDI(InitGDI())
        {}

        template <class T> void draw(const T& sprite) const
        {
            sprite.draw(m_Buffer.Graphics);
        }

        void present()
        {
            BitBlt(m_Buffer.hdc, 0, 0, m_Resolution.X, m_Resolution.Y, m_Buffer.Memhdc, 0, 0, SRCCOPY);
        }

        void clearScreen()
        {
            m_Buffer.Graphics->Clear(Gdiplus::Color::Black);
            present();
        }

        void clearBuffer()
        {
            m_Buffer.Graphics->Clear(Gdiplus::Color::Black);
        }

    private:
        static std::shared_ptr<GDI> InitGDI()
        {
            static std::shared_ptr<GDI> StaticGDI(new GDI);

            return StaticGDI;
        }

        Vector2                        m_Resolution;
        std::shared_ptr<GDI>           m_GDI;
        FrameBuffer                    m_Buffer;
    };

    //checks if key was pressed
    inline int check_key()
    {
        return _kbhit();
    }

    //get key input
    inline int get_key()
    {
        return _getch();
    }

    //returns mouse position
    inline Vector2 get_mouse(HWND window = GetConsoleWindow())
    {
        POINT pos;

        GetCursorPos(&pos);
        ScreenToClient(window, &pos);

        return Vector2(pos.x, pos.y);
    }

    //Inverts capital to no capital and vice versa

    inline char invert_character(char character)
    {
        return character ^ 0x20;
    }

    //starts playing a sound
    inline void playSound(std::string path)
    {
        std::string command = "play ";
        command.append(path);
        mciSendString(command.c_str(), NULL, 0, NULL);
    }

    //stops playing last started sound
    inline void stopSound(std::string path)
    {
        std::string command = "stop ";
        command.append(path);
        mciSendString(command.c_str(), NULL, 0, NULL);
    }

    //Simple stop watch

    class Timer
    {
    public:
        Timer()
            : m_Total(0.0), m_Start(0), m_End(0), m_Running(false)
        {}

        double totalTime() const
        {
            return m_Total;
        }

        void reset()
        {
            m_Total = 0;
            m_Start = 0;
            m_End = 0;
        }

        void start()
        {
            if (!m_Running)
            {
                m_Start = clock();
                m_Running = true;
            }
        }

        void stop()
        {
            if (m_Running)
            {
                m_End = clock();
                m_Total = ((double)(m_End - m_Start)) / CLOCKS_PER_SEC;

                m_Running = false;
            }
        }

        void tick()
        {
            if (m_Running)
            {
                m_Total = ((double)(clock() - m_Start)) / CLOCKS_PER_SEC;
            }
        }

    private:
        double  m_Total;

        clock_t m_Start;
        clock_t m_End;

        bool    m_Running;
    };

    //Function to resize the console

    inline void resizeConsole(Vector2 resolution)
    {
        HWND console = GetConsoleWindow();
        RECT r;
        GetWindowRect(console, &r);
        MoveWindow(console, r.left, r.top, resolution.X, resolution.Y, TRUE);
    }
}

namespace utility
{
    class Actor;

    class Component
    {
    public:
        friend Actor;

        Component(const std::string& name)
            : m_Name(name)
        {}

        virtual ~Component()
        {}

        virtual void Update() = 0;
        virtual void Move(utility::Vector2 motion) = 0;
        virtual void SetPosition(utility::Vector2 pos) = 0;

        virtual utility::Vector2 GetPosition() const = 0;

        virtual std::string GetName() const
        {
            return m_Name;
        }

        Actor* GetOwner() const
        {
            return m_Owner;
        }

    private:
        void SetOwner(Actor* actor)
        {
            m_Owner = actor;
        }

        std::string m_Name;
        Actor*      m_Owner;

    };
}

namespace utility
{

    //Info struct which is needed to load animations
    struct AnimationInfo
    {
        AnimationInfo(int id, const std::string& name, int nFrames, const std::string& path)
            : animationID(id), fileName(name), numFrames(nFrames), filePath(path)
        {}

        int         animationID;
        std::string fileName;
        int         numFrames;
        std::string filePath;
    };

    class Graphic : public utility::Component
    {
    public:
        Graphic(utility::Vector2 position, utility::Vector2 resolution)
            : Component("graphic"), m_Position(position), m_Resolution(resolution), m_FrameDuration(1), m_CurrentFrame(0)
        {}

        ~Graphic()
        {
            std::for_each(m_Animations.begin(), m_Animations.end(), [&](std::pair<const int, utility::Animation*>& an)->void { delete an.second; });
        }

        void Load(std::vector<AnimationInfo> animations)
        {
            std::for_each(animations.begin(), animations.end(), [&](AnimationInfo& info)
            {
                utility::Animation* tmp = new utility::Animation(std::to_string(info.animationID), m_Position, m_Resolution);
                tmp->loadAnimation(info.fileName, info.numFrames, info.filePath);
                m_Animations.insert(std::make_pair(info.animationID, tmp));
            });
        }

        void Draw()
        {
            if (m_Animations.size() != 0)
            {
                GetController().draw(*m_Animations.at(m_ActiveAnimation));
            }
        }

        void Update()
        {
            if (m_Animations.size() != 0)
            {
                if (m_CurrentFrame == m_FrameDuration)
                {
                    m_Animations.at(m_ActiveAnimation)->update();
                    m_CurrentFrame = 0;
                }
                else
                {
                    ++m_CurrentFrame;
                }
            }
        }

        void SetFrameDuration(int n)
        {
            m_FrameDuration = n;
        }

        void Move(utility::Vector2 motion)
        {
            std::for_each(m_Animations.begin(), m_Animations.end(), [&](std::pair<const int, utility::Animation*>& an)->void { an.second->move(motion); });
            m_Position += motion;
        }

        void SetPosition(utility::Vector2 pos)
        {
            std::for_each(m_Animations.begin(), m_Animations.end(), [&](std::pair<const int, utility::Animation*>& an)->void { an.second->setPosition(pos); });
            m_Position = pos;
        }

        utility::Vector2 GetPosition() const
        {
            return m_Position;
        }

        utility::Vector2 GetResolution() const
        {
            return m_Resolution;
        }

        void SetActiveAnimation(int animationID)
        {
            if (m_Animations.find(animationID) != m_Animations.end())
            {
                m_ActiveAnimation = animationID;
            }
        }

        int GetActiveAnimation() const
        {
            return m_ActiveAnimation;
        }

        static utility::GraphicController& GetController()
        {
            static utility::GraphicController* gc = nullptr;

            if (!gc)
            {
                gc = new utility::GraphicController(GetConsoleWindow(), utility::Vector2(640, 640));
            }

            return *gc;
        }

    private:
        std::map<int, utility::Animation*> m_Animations;
        utility::Vector2                   m_Position;
        utility::Vector2                   m_Resolution;
        int                                m_ActiveAnimation;
        int                                m_FrameDuration;
        int                                m_CurrentFrame;
    };
}

namespace utility
{
    class Collision : public utility::Component
    {
    public:
        Collision(utility::Vector2 position, utility::Vector2 resolution)
            : Component("collision"), m_Position(position), m_Resolution(resolution)
        {}

        bool CollidesWith(Collision* target)
        {
            utility::Vector2 p1 = target->GetPosition();

            bool condition1 = p1.X >= m_Position.X && p1.X <= m_Position.X + m_Resolution.X && p1.Y >= m_Position.Y && p1.Y <= m_Position.Y + m_Resolution.Y;

            utility::Vector2 p2 = target->GetPosition();
            p2.X += target->m_Resolution.X;

            bool condition2 = p2.X >= m_Position.X && p2.X <= m_Position.X + m_Resolution.X && p2.Y >= m_Position.Y && p2.Y <= m_Position.Y + m_Resolution.Y;

            utility::Vector2 p3 = target->GetPosition();
            p3.Y += target->m_Resolution.Y;

            bool condition3 = p3.X >= m_Position.X && p3.X <= m_Position.X + m_Resolution.X && p3.Y >= m_Position.Y && p3.Y <= m_Position.Y + m_Resolution.Y;

            utility::Vector2 p4 = target->GetPosition();
            p4.X += target->m_Resolution.X;
            p4.Y += target->m_Resolution.Y;

            bool condition4 = p4.X >= m_Position.X && p4.X <= m_Position.X + m_Resolution.X && p4.Y >= m_Position.Y && p4.Y <= m_Position.Y + m_Resolution.Y;

            return condition1 || condition2 || condition3 || condition4;
        }

        bool CollidesWith(utility::Vector2 position)
        {
            utility::Vector2 p1 = position;

            bool condition = p1.X >= m_Position.X && p1.X <= m_Position.X + m_Resolution.X && p1.Y >= m_Position.Y && p1.Y <= m_Position.Y + m_Resolution.Y;

            return condition;
        }

        void Update()
        {}

        void Move(utility::Vector2 motion)
        {
            m_Position += motion;
        }

        void SetPosition(utility::Vector2 pos)
        {
            m_Position = pos;
        }

        utility::Vector2 GetPosition() const
        {
            return m_Position;
        }

    private:
        utility::Vector2 m_Position;
        utility::Vector2 m_Resolution;
    };
}

namespace utility
{
    template <class Actor>
    class EPhysic : public utility::Component
    {
    public:
        EPhysic(utility::Vector2 position)
            : Component("physic"), m_Position(position), m_XSpeed(0.0f), m_YSpeed(0.0f)
        {}

        void Update()
        {
            m_XMotionTimer.tick();
            m_YMotionTimer.tick();

            if (m_XSpeed > 0)
            {
                double speed = m_XSpeed + (-AirResistance()) * m_XMotionTimer.totalTime();

                if (speed > 0)
                {
                    ((Actor*)GetOwner())->Move(utility::Vector2((int)std::round(speed), 0));
                }
                else
                {
                    m_XSpeed = 0;

                    m_XMotionTimer.stop();
                    m_XMotionTimer.reset();
                }
            }
            if (m_XSpeed < 0)
            {
                double speed = m_XSpeed + AirResistance() * m_XMotionTimer.totalTime();

                if (speed < 0)
                {
                    ((Actor*)GetOwner())->Move(utility::Vector2((int)std::round(speed), 0));
                }
                else
                {
                    m_XSpeed = 0;

                    m_XMotionTimer.stop();
                    m_XMotionTimer.reset();
                }
            }
            if (m_YSpeed > 0)
            {
                double speed = m_YSpeed + (-AirResistance()) * m_YMotionTimer.totalTime();

                if (speed > 0)
                {
                    ((Actor*)GetOwner())->Move(utility::Vector2(0, (int)std::round(speed)));
                }
                else
                {
                    m_YSpeed = 0;

                    m_YMotionTimer.stop();
                    m_YMotionTimer.reset();
                }
            }
            if (m_YSpeed < 0)
            {
                double speed = m_YSpeed + AirResistance() * m_YMotionTimer.totalTime();

                if (speed < 0)
                {
                    ((Actor*)GetOwner())->Move(utility::Vector2(0, (int)std::round(speed)));
                }
                else
                {
                    m_YSpeed = 0;

                    m_YMotionTimer.stop();
                    m_YMotionTimer.reset();
                }
            }
        }

        void SetXSpeed(double speed)
        {
            m_XSpeed = speed;

            m_XMotionTimer.stop();
            m_XMotionTimer.reset();
            m_XMotionTimer.start();
        }

        void SetYSpeed(double speed)
        {
            m_YSpeed = speed;

            m_YMotionTimer.stop();
            m_YMotionTimer.reset();
            m_YMotionTimer.start();
        }

        void Move(utility::Vector2 motion)
        {
            m_Position += motion;
        }

        void SetPosition(utility::Vector2 pos)
        {
            m_Position = pos;
        }

        utility::Vector2 GetPosition() const
        {
            return m_Position;
        }

        static void SetAirResistance(double ar)
        {
            AirResistance() = ar;
        }

        static double GetAirResistance()
        {
            return AirResistance();
        }

    private:
        static double& AirResistance()
        {
            static double airResistance = 1.81;

            return airResistance;
        }

        utility::Timer   m_XMotionTimer;
        utility::Timer   m_YMotionTimer;

        utility::Vector2 m_Position;

        double            m_XSpeed;
        double            m_YSpeed;
    };
}

namespace utility
{
    using Physic = EPhysic<Actor>;

    class Actor
    {
    public:
        Actor(const std::string& name, utility::Vector2 position, bool graphic, bool physic, bool collision, utility::Vector2 resolution = utility::Vector2())
            : m_Name(name), m_Position(position), m_Destroyed(false), m_Delay(0)
        {
            if (graphic)
            {
                AddComponent(new Graphic(position, resolution));
            }
            if (physic)
            {
                AddComponent(new Physic(position));
            }
            if (collision)
            {
                AddComponent(new Collision(position, resolution));
            }
        }

        virtual void LoadAnimations(int n, AnimationInfo arg1, ...)
        {
            std::vector<AnimationInfo> animations;

            va_list argument_list;

            va_start(argument_list, n);

            for (int currentArg = 0; n > currentArg; ++currentArg)
            {
                AnimationInfo info = va_arg(argument_list, AnimationInfo);

                animations.push_back(info);
            }

            va_end(argument_list);

            struct graphic_finder
            {
                bool operator()(Component* ptr)
                {
                    return ptr->GetName() == "graphic";
                }
            };

            std::vector<Component*>::iterator component = std::find_if(m_Components.begin(), m_Components.end(), graphic_finder());

            if (component != m_Components.end())
            {
                ((utility::Graphic*)*component)->Load(animations);
            }
        }

        virtual ~Actor()
        {
            std::for_each(m_Components.begin(), m_Components.end(), [&](Component* cp)->void { delete cp; });
        }

        virtual std::string GetName()
        {
            return m_Name;
        }

        virtual void Draw()
        {
            struct graphic_finder
            {
                bool operator()(Component* ptr)
                {
                    return ptr->GetName() == "graphic";
                }
            };

            std::vector<Component*>::iterator component = std::find_if(m_Components.begin(), m_Components.end(), graphic_finder());

            if (component != m_Components.end())
            {
                ((utility::Graphic*)*component)->Draw();
            }
        }

        virtual void SetActiveAnimation(int animationID)
        {
            struct graphic_finder
            {
                bool operator()(Component* ptr)
                {
                    return ptr->GetName() == "graphic";
                }
            };

            std::vector<Component*>::iterator component = std::find_if(m_Components.begin(), m_Components.end(), graphic_finder());

            if (component != m_Components.end())
            {
                ((utility::Graphic*)*component)->SetActiveAnimation(animationID);
            }
        }

        virtual int GetActiveAnimation()
        {
            struct graphic_finder
            {
                bool operator()(Component* ptr)
                {
                    return ptr->GetName() == "graphic";
                }
            };

            std::vector<Component*>::iterator component = std::find_if(m_Components.begin(), m_Components.end(), graphic_finder());

            if (component != m_Components.end())
            {
                return ((utility::Graphic*)*component)->GetActiveAnimation();
            }

            return -1;
        }

        virtual utility::Vector2 GetResolution()
        {
            struct graphic_finder
            {
                bool operator()(Component* ptr)
                {
                    return ptr->GetName() == "graphic";
                }
            };

            std::vector<Component*>::iterator component = std::find_if(m_Components.begin(), m_Components.end(), graphic_finder());

            if (component != m_Components.end())
            {
                return ((utility::Graphic*)*component)->GetResolution();
            }

            return utility::Vector2();
        }

        virtual void SetFrameDuration(int n)
        {
            struct graphic_finder
            {
                bool operator()(Component* ptr)
                {
                    return ptr->GetName() == "graphic";
                }
            };

            std::vector<Component*>::iterator component = std::find_if(m_Components.begin(), m_Components.end(), graphic_finder());

            if (component != m_Components.end())
            {
                ((utility::Graphic*)*component)->SetFrameDuration(n);
            }
        }

        virtual bool CollidesWith(Actor* actor)
        {
            struct collision_finder
            {
                bool operator()(Component* ptr)
                {
                    return ptr->GetName() == "collision";
                }
            };

            std::vector<Component*>::iterator componentMe = std::find_if(m_Components.begin(), m_Components.end(), collision_finder());
            std::vector<Component*>::iterator componentHe = std::find_if(actor->m_Components.begin(), actor->m_Components.end(), collision_finder());

            if (componentMe != m_Components.end() && componentHe != actor->m_Components.end())
            {
                return ((utility::Collision*)*componentMe)->CollidesWith((utility::Collision*)*componentHe);
            }
            else
            {
                return false;
            }
        }

        virtual bool CollidesWith(utility::Vector2 point)
        {
            struct collision_finder
            {
                bool operator()(Component* ptr)
                {
                    return ptr->GetName() == "collision";
                }
            };

            std::vector<Component*>::iterator componentMe = std::find_if(m_Components.begin(), m_Components.end(), collision_finder());

            if (componentMe != m_Components.end())
            {
                return ((utility::Collision*)*componentMe)->CollidesWith(point);
            }
            else
            {
                return false;
            }
        }

        virtual void SetXSpeed(double speed)
        {
            struct physic_finder
            {
                bool operator()(Component* ptr)
                {
                    return ptr->GetName() == "physic";
                }
            };

            std::vector<Component*>::iterator componentMe = std::find_if(m_Components.begin(), m_Components.end(), physic_finder());

            if (componentMe != m_Components.end())
            {
                ((utility::EPhysic<Actor>*)*componentMe)->SetXSpeed(speed);
            }
        }

        virtual void SetYSpeed(double speed)
        {
            struct physic_finder
            {
                bool operator()(Component* ptr)
                {
                    return ptr->GetName() == "physic";
                }
            };

            std::vector<Component*>::iterator componentMe = std::find_if(m_Components.begin(), m_Components.end(), physic_finder());

            if (componentMe != m_Components.end())
            {
                ((utility::EPhysic<Actor>*)*componentMe)->SetYSpeed(speed);
            }
        }

        virtual void Update()
        {
            std::for_each(m_Components.begin(), m_Components.end(), [&](Component* cp)->void { cp->Update(); });

            if (m_Destroyed)
            {
                --m_Delay;
            }
        }

        virtual void Move(utility::Vector2 motion)
        {
            std::for_each(m_Components.begin(), m_Components.end(), [&](Component* cp)->void { cp->Move(motion); });
            m_Position += motion;
        }

        virtual void SetPosition(utility::Vector2 pos)
        {
            std::for_each(m_Components.begin(), m_Components.end(), [&](Component* cp)->void { cp->SetPosition(pos); });
            m_Position = pos;
        }

        virtual void AddComponent(Component* component)
        {
            component->SetOwner(this);
            m_Components.push_back(component);
        }

        virtual utility::Vector2 GetPosition() const
        {
            return m_Position;
        }

        virtual bool Destroyed() const
        {
            return m_Destroyed && m_Delay == 0;
        }

        virtual void Destroy()
        {
            m_Destroyed = true;
        }

        virtual void DestroyDelayed(int frames)
        {
            if (!m_Destroyed)
            {
                m_Destroyed = true;
                m_Delay     = frames;
            }
        }

    private:
        std::vector<Component*> m_Components;
        std::string             m_Name;
        utility::Vector2        m_Position;
        int                     m_Delay;
        bool                    m_Destroyed;
    };
}

namespace utility
{
    class Engine
    {
    public:
        Engine()
            : m_OnFrame(place_holder), m_OnCollision(place_holder_cl), m_OnInit(place_holder)
        {   
            utility::resizeConsole(utility::Vector2(640, 640));
            Graphic::GetController().clearBuffer();
        }

        void Run()
        {
            m_OnInit();

            m_Timer.start();
            m_LastFrame = 0.0;
            m_Running   = true;

            while (m_Running)
            {
                m_Timer.tick();
                if (m_Timer.totalTime() - m_LastFrame >= 1.0f / 60.0f)
                {
                    m_LastFrame = m_Timer.totalTime();

                    m_OnFrame();
                    Clear();
                    Update();
                    Collision();
                    Draw();
                    Present();
                }
            }
        }

        void AddActor(Actor* actor)
        {
            m_Actors.push_back(actor);
        }

        template <class T> void SetOnFrame(T fnc)
        {
            m_OnFrame = fnc;
        }

        template <class T> void SetOnCollision(T fnc)
        {
            m_OnCollision = fnc;
        }

        template <class T> void SetOnInit(T fnc)
        {
            m_OnInit = fnc;
        }

        Actor* GetActor(const std::string& name)
        {
            struct actor_finder
            {
                actor_finder(const std::string& n)
                    : m_ActorName(n)
                {}

                bool operator()(Actor* ptr)
                {
                    return ptr->GetName() == m_ActorName;
                }

                std::string m_ActorName;
            };

            std::vector<Actor*>::iterator actor = std::find_if(m_Actors.begin(), m_Actors.end(), actor_finder(name));

            if (actor != m_Actors.end())
            {
                return *actor;
            }
            else
            {
                return nullptr;
            }
        }

        std::vector<Actor*>& GetActors()
        {
            return m_Actors;
        }

        void Exit()
        {
            m_Running = false;
        }

        static Engine& GetEngine()
        {
            static Engine utility;

            return utility;
        }

    private:
        void Collision()
        {
            for (unsigned int currentIndexA = 0; m_Actors.size() > currentIndexA; ++currentIndexA)
            {
                for (unsigned int currentIndexB = currentIndexA + 1; m_Actors.size() > currentIndexB; ++currentIndexB)
                {
                    if (m_Actors.at(currentIndexA)->CollidesWith(m_Actors.at(currentIndexB)))
                    {
                        m_OnCollision(m_Actors.at(currentIndexA), m_Actors.at(currentIndexB));
                    }
                }
            }
        }

        void Update()
        {
            std::for_each(m_Actors.begin(), m_Actors.end(), [](Actor* actor)->void { actor->Update(); });
        }

        void Draw()
        {
            std::for_each(m_Actors.begin(), m_Actors.end(), [](Actor* actor)->void { actor->Draw(); });
        }

        void Clear()
        {
            for (unsigned int currentIndex = 0; m_Actors.size() > currentIndex; ++currentIndex)
            {
                if (m_Actors.at(currentIndex)->Destroyed())
                {
                    delete m_Actors.at(currentIndex);
                    m_Actors.erase(m_Actors.begin() + currentIndex);
                    --currentIndex;
                }
            }

            utility::Graphic::GetController().clearBuffer();
        }

        void Present()
        {
            utility::Graphic::GetController().present();
        }

        static void place_holder_cl(Actor* a, Actor* b)
        {

        }

        static void place_holder()
        {

        }

        std::vector<Actor*>                     m_Actors;
        std::function<void(Actor* a, Actor* b)> m_OnCollision;
        std::function<void()>                   m_OnFrame;
        std::function<void()>                   m_OnInit;
        utility::Timer                          m_Timer;
        double                                  m_LastFrame;
        bool                                    m_Running;
    };
}

Я дам немного космической игры захватчиков в качестве примера, как работает двигатель.

int main()
{
    utility::Engine& Engine = utility::Engine::GetEngine();

    Engine.SetOnInit(init);
    Engine.SetOnFrame(frame);
    Engine.SetOnCollision(collision);

    Engine.Run();

    return 0;
}

Я решил дать пользователю доступ на три важные функции. Init(), Frame()иCollision(). Все три функции могут быть определены, а затем просто добавил к двигателю на SetOn"FunctionName"(xyz) функции. Таким образом, вы можете взять много неприятностей от застройщика. Все три функции будут вызываться двигателя при необходимости.

Инит-это мысль установить игру и добавить такие вещи, как фон и плеер например. Это называется, прежде чем игра начнется.

void createBackground()
{
    utility::Engine& Engine = utility::Engine::GetEngine();
    utility::Actor*   actor = new utility::Actor("background", utility::Vector2(0, -600), true, true, false, utility::Vector2(640, 1200));

    actor->LoadAnimations(1, utility::AnimationInfo(AnimationIDs::idle, "background", 1, "Sprites\\misc\\"));
    Engine.AddActor(actor);
}

void createPlayer(utility::Vector2 position)
{
    utility::Engine& Engine = utility::Engine::GetEngine();
    utility::Actor*   actor = new utility::Actor("player", utility::Vector2(100, 400), true, true, true, utility::Vector2(72, 72)); //48

    actor->LoadAnimations(2, utility::AnimationInfo(AnimationIDs::idle,    "ship",       1, "Sprites\\ships\\"), 
                             utility::AnimationInfo(AnimationIDs::explode, "explosion",  5, "Sprites\\effects\\"));
    Engine.AddActor(actor);
}

void init()
{
    utility::Engine& Engine = utility::Engine::GetEngine();

    createBackground();
    createPlayer(utility::Vector2(100, 400));

    utility::Physic::SetAirResistance(1.1);
}

Я разделил функции init в 2 подфункции. В createBackground() функция будет загружать в фоновом режиме и установить его в положение, когда createPlayer() функция установки актера. Чтобы создать актера, вам придется дать конструктору имя, должность (представлены в Vector2 структуры), трех значений bool в зависимости от того, какие компоненты вы хотите на вашем актера и Vector2 с размером столкновения ящик, который вы хотите создать.

Следующим шагом является на самом деле загрузить некоторые спрайты (если вы хотите графической составляющей). Первый параметр функции указывает, сколько анимации, который вы хотите загрузить, остальные будут заполнены AnimationInfo структуры. Функция нагрузки N спрайтов, а n-количество кадров вы даете AnimationInfo. Функция может загрузить .PNG-файлов по имени, как spritename + currentFrameNumber.ПНГ. Если ваша анимация называется ShipIdle экземпляра вам придется назвать ShipIdle0 кадров.ПНГ, ShipIdle1.PNG и так далее.

Последним шагом будет добавление актера на двигатель.

Следующая функция-это Frame() функция.

void frame()
{
    utility::Engine& Engine = utility::Engine::GetEngine();
    utility::Actor* player  = Engine.GetActor("player");

    if (!player)
    {
        std::cout << "game over";
        utility::Engine::GetEngine().Exit();
        utility::get_key();
        return;
    }

    controls(player);

    playerMovement(player); 
    backgroundMovement();
    actorMovement();

    spawn();
}

Эта функция вызывается каждый кадр, и хотя является содержат фактические игровую логику.

Первая подфункция я создан был controls(actor*) функция, которая будет применяться пользовательский ввод для актера.

void controls(utility::Actor* player)
{
    utility::Engine& Engine = utility::Engine::GetEngine();

    if (utility::check_key())
    {
        char key = utility::get_key();

        switch (key)
        {
        case 'w':
        {
            player->SetYSpeed(-3);
            break;
        }
        case 'a':
        {
            player->SetXSpeed(-3);
            break;
        }
        case 's':
        {
            player->SetYSpeed(3);
            break;
        }
        case 'd':
        {
            player->SetXSpeed(3);
            break;
        }
        case' ':
        {
            shoot(player, true);
            break;
        }
        case 'x':
        {
            Engine.Exit();
            break;
        }
        default:
        {
            break;
        }
        }
    }
}

Он содержится в простейшем случае выключатель, который будет ускоренно актер в нужном направлении, если игрок или выйти из программы нажимает клавишу, в то время как следующая функция предотвращает игрока из видимого экрана.

void playerMovement(utility::Actor* player)
{
    if (player->GetPosition().X > 560)
    {
        player->SetPosition(utility::Vector2(560, player->GetPosition().Y));
    }
    if (player->GetPosition().X < 0)
    {
        player->SetPosition(utility::Vector2(  0, player->GetPosition().Y));
    }
    if (player->GetPosition().Y > 500)
    {
        player->SetPosition(utility::Vector2(player->GetPosition().X, 500));
    }
    if (player->GetPosition().Y < 0)
    {
        player->SetPosition(utility::Vector2(player->GetPosition().X,   0));
    }
}

А вот функции на нерест выстрелов и врагов.

void shoot(utility::Actor* actor, bool player)
{
    utility::Engine& Engine   = utility::Engine::GetEngine();
    utility::Actor*  shot     = nullptr;
    std::string      name     = "";
    utility::Vector2 position = utility::Vector2();

    if (player)
    {
        name     = "playerShot";
        position = utility::Vector2(actor->GetPosition().X + (actor->GetResolution().X / 2) - 10, actor->GetPosition().Y - 21);
    }
    else
    {
        name     = "enemyShot";
        position = utility::Vector2(actor->GetPosition().X + (actor->GetResolution().X / 2) - 10, actor->GetPosition().Y + actor->GetResolution().Y + 21);
    }

    shot = new utility::Actor(name, position, true, true, true, utility::Vector2(20, 20));

    shot->LoadAnimations(1, utility::AnimationInfo(0, "laser_basic", 1, "Sprites\\effects\\"));
    Engine.AddActor(shot);
}

void spawnEnemy(utility::Timer& timer)
{
    static utility::random_engine  rnd(0, 540);

    static double spawnInterval = 2.2;
    static double lastSpawn     = 0.0;

    if (timer.totalTime() - lastSpawn >= spawnInterval)
    {
        lastSpawn = timer.totalTime();

        utility::Vector2 pos(rnd.generate(), 0);
        createEnemy(pos);
    }
}

utility::Actor* getRandomEnemy(std::vector<utility::Actor*>& actors)
{
    static utility::random_engine rnds(0, (int)utility::Engine::GetEngine().GetActors().size() - 1);

    rnds.changeMax(actors.size() - 1);
    int tries = 0;

    utility::Actor* actor = nullptr;
    while (tries != 30 && (actor == nullptr || actor->GetName() != "enemy"))
    {
        actor = actors.at(rnds.generate());
        ++tries;
    }

    return actor->GetName() == "enemy" ? actor : nullptr;
}

void spawnShot(utility::Timer& timer)
{
    static double shootInterval = 1.0;
    static double lastShot      = 0.0;

    std::vector<utility::Actor*>& actors = utility::Engine::GetEngine().GetActors();

    if (timer.totalTime() - lastShot >= shootInterval && actors.size() > 1)
    {
        lastShot = timer.totalTime();

        utility::Actor* actor = getRandomEnemy(actors);

        if (actor)
        {
            shoot(actor, false);
        }
    }
}

void spawn()
{
    static utility::Timer timer;
    static bool once = false;

    if (!once)
    {
        timer.start();
    }

    timer.tick();

    spawnEnemy(timer);
    spawnShot(timer);
}

Наши следующие две функции перемещения/сброс фона и другие актеры в игре (как враги и стреляли).

void backgroundMovement()
{
    utility::Engine& Engine     = utility::Engine::GetEngine();
    utility::Actor*  background = Engine.GetActor("background");

    if (background)
    {
        background->SetYSpeed(1);

        if (background->GetPosition().Y >= 0)
        {
            background->SetPosition(utility::Vector2(0, -600));
        }
    }
}

void actorMovement()
{
    utility::Engine& Engine = utility::Engine::GetEngine();

    std::vector<utility::Actor*>& actors = Engine.GetActors();

    std::for_each(actors.begin(), actors.end(), [](utility::Actor* actor)->void { if (actor->GetName() == "playerShot") { actor->SetYSpeed(-6); } });
    std::for_each(actors.begin(), actors.end(), [](utility::Actor* actor)->void { if (actor->GetName() == "enemyShot")  { actor->SetYSpeed( 4); } });
    std::for_each(actors.begin(), actors.end(), [](utility::Actor* actor)->void { if (actor->GetName() == "enemy")      { actor->SetYSpeed( 1); } });

    std::for_each(actors.begin(), actors.end(), [](utility::Actor* actor)->void { if ((actor->GetPosition().Y > 680 || actor->GetPosition().Y < -90) && actor->GetName() != "background") { actor->Destroy(); } });

}

Последние две функции относятся к collision(actor*, actor*) функции и determinCollision(actor*) функция.

void determinCollision(utility::Actor* actor)
{
    if (actor->GetName().find("Shot") == std::string::npos)
    {
        actor->SetActiveAnimation(AnimationIDs::explode);
        actor->SetFrameDuration(3);
        actor->DestroyDelayed(15);
    }
    else
    {
        actor->Destroy();
    }
}

void collision(utility::Actor* a, utility::Actor* b)
{
    if ((a->GetName().find("Shot") != std::string::npos && b->GetName().find("Shot") != std::string::npos) || (a->GetName() == "background" || b->GetName() == "background"))
    {
        return;
    }

    determinCollision(a);
    determinCollision(b);
}

Функция столкновения будет вызываться каждый раз, когда я сталкиваются. Его цель состоит в том, чтобы дать разработчику возможность решать, что будет происходить во время нашего столкновения.

В нашем случае он будет вызывать determinCollision(actor) функция, чтобы решить, какой актер должен быть уничтожен.

Актер не должен быть разрушен deleteон должен быть убит actor::destroy() или actor::destroyDelayed(n) чтобы дать двигателю возможность очистить его, если он больше не требуется.

Вот наша готовая игра, которая может выглядеть так (в зависимости от леших):

enter image description here



420
14
задан 5 апреля 2018 в 02:04 Источник Поделиться
Комментарии
3 ответа

Это много кода. Вот что я заметил, но я не смотрю на все абсолютно и без сомнений пропустили вещи. Есть некоторые общие сведения, которые упоминаются один или два раза, но не каждый раз, когда они происходят.

В namespace operatorsвы не нужны inline сайта, когда вперед объявив ваших операторов. Вам нужно только то, что при определении их позже.

Каждое место вы передаете параметр по const double &это может быть double.

В Vector2 класс, const_cast используется внутри операторов является излишним, поскольку *this не const значение. Использование me на самом деле не улучшить положение вещей. Вы могли бы просто использовать *this = *this + a; return *this;.

В ~FrameBufferвы объявляете несколько неиспользуемых локальных переменных, что тень учащихся. Я не думаю, что это то, чего вы хотите. Опустить видах со всех 4-х деклараций. Вы также обнуление wnd прежде чем позвонить SendMessage, поэтому сообщение не попадет в нужное место.

Перейти к class Spriteназначение оператора не является безопасным для самостоятельного назначения. И const_cast в инструкции return можно опустить.

В одном месте вы называете to_wchar, у вас есть string объект, который можно преобразовать в C-строку. Затем в to_wchar вы называете strlen. Просто передать строку объект to_wchar так что вы будете уже иметь длину доступна и не придется считать символы.

Sprite::clear может быть статическая функция-член, так как он не имеет доступа к любой из переменных-членов или других функций-членов Sprite.

Вы пройдете много Vector2 объекты const &но в setPosition и move вы передаете по значению, которое копирует вам не нужно сделать. Эти две функции должны взять на должность const Vector2& position.

В Animation класс имеет несколько таких же проблем, как Sprite; я не буду их повторять. В updateты злоупотребляешь условного оператора в качестве if заявление. Просто использовать ifили напишите выражение, которое использует % оператор вместо условного.

Вы можете использовать emplace_back вместо push_back в loadAnimation. В setPosition и moveвам не нужно явно указывать, что ваш лямбда-функции возвращают Void. Этого будет выведен компилятором.

В GraphicController конструктор, вы должны список инициализатора значения в порядке их объявления (m_Resolution, m_GDI, m_Buffer), так это того, компилятор будет вызывать конструкторы. Если ваш уровень предупреждений установлен в /W4 вы должны получать предупреждение об этом.

Ваш Component конструктор не устанавливает начальной (нулевым) значением m_Owner.

Graphic::Load получает параметр по значению, что делает копию вектора. Это должны быть передан по константной.

В Graphic::Draw функция проверки на пустоту m_Animations карте, но не проверить, что запрашиваемый анимация уже есть. Это может потенциально вызвать разыменование null-указателя.

В Graphic::GetControllerвы можете инициализировать gc в своем заявлении, а его инициализации значением nullptr и проверки, чтобы увидеть, если он был создан.

Collision::CollidesWith может просто вернуться true когда он находит истинное состояние, а не всегда учитываются все 4 и проверить в конце. p4 могут быть устранены путем повторного использования p2 или p3 с соответствующей корректировкой.

Использование Actor в качестве шаблона параметра name в EPhysic сбивает с толку, так как там тоже Actor класс.

В Actor конструктор m_Destroyed и m_Delay местами. Ты объявлении виртуальных функций в нем, но я не вижу, где он используется как базовый класс.

У вас есть несколько идентичных заявлений вспомогательных классов graphic_finder, collision_finderи physic_finder. Там должно быть только одно определение для тех, чтобы избежать повторения. Кроме того, создать единый FindComponent функция для использования в Draw, SetActiveAnimationи т. д., а не повторять все что найдут код.

Actor::GetName() может быть const функция.

Engine::Engine опять-таки член конструкторы указаны в неправильном порядке.

playerMovement может использовать лучший способ, чтобы изменить позицию игрока. Поскольку вы только поставили или X или Y значения там должен быть простой способ сделать это. Помимо этого, в рамках и пусть player объект проверять и обновлять свою собственную позицию.

В actorMovementможно свернуть несколько проходов через actors вектор в одну, проверять тип каждого актера, как вы идете. Это было бы легче, если способ определения актерского типа (GetName) использовать что-то вроде перечислимое значение вместо.

10
ответ дан 5 апреля 2018 в 09:04 Источник Поделиться

Несколько замечаний о 'вещи, которые я не делаю...

Я предполагаю, что код, который вы дали в заголовке файла. Если это так, то это очень много кода для одного заголовочного файла. Пожалуй, один заголовок для каждого класса?

Еще одно общее дело, что вы не должны рядный ничего сверх простые геттеры и сеттеры, если вы не можете определить, что подстановка дает значительный выигрыш в производительности. Он держит ваш интерфейс намного чище и не вызывает ваших клиентов, чтобы получить удивительные заголовки к ним. Это также означает, что у вас больше свободы в изменении своей реализации, не вызывая код клиента должен быть восстановлен.

Более конкретно:

Почему это? predeclaring это не очень полезно

    inline Vector2 operator + (const Vector2& a, const Vector2& b);
inline Vector2 operator - (const Vector2& a, const Vector2& b);
inline Vector2 operator * (const Vector2& a, const double& d);
inline Vector2 operator / (const Vector2& a, const double& d);

просто объявить их inline, когда вы определяете метод (который, как вы объявляете их в классе, вам все равно не нужно)

Этот конструктор:

        Vector2(int x = 0, int y = 0)
: X(x), Y(y)
{}

позволяет объявить Vector2 x(5). Это то, что вы действительно хотите, чтобы люди поступали? Также, как вы не сделали это explicitвы можете сделать Vector2 x = 5 что почти наверняка не так. Я думаю, что два отдельных конструкторов без параметров дефолт был бы лучше.

У вас также есть много такого:

            Vector2& me = *const_cast<Vector2*>(this);

me = me - a;

return me;

Во-первых, const_cast является излишним, поскольку this не const (в качестве способа нет). Во-вторых, используя const_cast это код запах. Если вам действительно нужно сделать это, вы должны объяснить, почему, так как это может вызвать всякие неприятные поведения.

У вас есть оператор using

using Vector2 = operators::Vector2;
enter code here

Не делайте этого в заголовочном файле. Вы могли бы также положить Vector2 в пространство имен. Это не своего рода вещь, чтобы сделать, чтобы люди, которые используют заголовок.

    FrameBuffer(Vector2 res, HWND window = GetConsoleWindow())
{

Опять же, это должно быть явным для безопасности. Опять же, ИМО, это должно быть два отдельных конструкторов, а это означает, что ваш заголовок должен тянуть в зависимости от заголовков Windows определяет GetConsoleWindow, что ваши клиенты, вероятно, не хотят знать.

        wnd = window;

Memhdc = 0;
hdc = GetDC(wnd);

Использовать список инициализации тестов для инициализации членов, когда вы можете. Компилятор должен инициализировать все члены, так что вы будете в конечном итоге с инициализации по умолчанию с последующим назначением. И не забудьте заказать список инициализации тестов в том же порядке, как и переменные-члены.

        GetClientRect(wnd, &Client_Rect);

Memhdc = CreateCompatibleDC(hdc);
Membitmap = CreateCompatibleBitmap(hdc, res.X, res.Y);

SelectObject(Memhdc, Membitmap);

Graphics = Gdiplus::Graphics::FromHDC(Memhdc);

Это много кода, для встроенной функции и тянет за собой много заголовков в коде, что ваши клиенты действительно не нужно знать.

    }

~FrameBuffer()
{
HDC Memhdc = 0;
HDC hdc = 0;
HBITMAP Membitmap = 0;
HWND wnd = 0;

Один - это объявляет локальные переменные с 0 значениями. Это не нулевого значения в классе.
Два: это деструктор. Этот объект никогда не будет снова доступно. Зачем?
Три: деструкторы не должны быть inline. Деструктор должен уничтожить все переменные-члены, и что может неожиданно генерировать много кода в каждый клиент.

inline const wchar_t * to_wchar(const char *c)
{
const size_t cSize = strlen(c) + 1;
wchar_t* wc = new wchar_t[cSize];
mbstowcs(wc, c, cSize);

return wc;
}

Не то, что у меня серьезные проблемы с этим, но вы, вероятно, следует возвращать unique_ptr или аналогичные, иначе клиент несет ответственность за утечку возвращаемое значение.

       if (m_Animations.size() != 0)

использовать if (not m_Animations.empty()) - это гарантированное время O(1), тогда как size не

Это:

   static utility::GraphicController& GetController()
{
static utility::GraphicController* gc = nullptr;

if (!gc)
{
gc = new utility::GraphicController(GetConsoleWindow(), utility::Vector2(640, 640));
}

return *gc;
}

утечки один экземпляр GraphicController. Вы должны избегать синглтонов. Или клиент должен быть ответственным за жизни.

У вас есть много c-стиля бросает в классе EPhysic. Пожалуйста, избегайте их, они снимаются и могут скрыть проблем. использовать static_cast (или другой соответствующей литой)

Я не проверял, так как я должен вернуться к работе, и прокрутка вверх и вниз-это начало, чтобы добраться до меня...

3
ответ дан 6 апреля 2018 в 10:04 Источник Поделиться

Нет времени на полный обзор.

Но ты делаешь оператора перегрузка неправильный путь вокруг. Вы defineing operator += с точки зрения operator +. Это вызывает дополнительные копии, вы должны сделать наоборот и определить operator + С точки зрения operator +=.

Исходный Код:

    Vector2& operator += (const Vector2& a)
{
// This is particularly smelly.
// Never case away constness.
Vector2& me = *const_cast<Vector2*>(this);

me = me + a;

return me;
}
inline Vector2 operator + (const Vector2& a, const Vector2& b)
{
return Vector2(a.X + b.X, a.Y + b.Y);
}

Я бы сделал это так:

   Vector2& operator += (Vector2 const& a) {
X += a.X;
Y += a.Y;
return *this;
}
Vector2 operator + (Vector2 const& a, Vector2 const& b) {
Vector2 result(a);
return result += b;
}

1
ответ дан 6 апреля 2018 в 07:04 Источник Поделиться