• 使用C++与SFML编写一个简单的撞球游戏Part7——弹球的碰撞检测


    这一Part,我们会让球动起来!!!
    在VisibleGameObject.h的public部分
    //获取精灵对象的宽
    virtual float GetWidth() const;
    //获取精灵对象的高
    virtual float GetHeight() const;
    //获取精灵对象的矩形区域
    virtual sf::Rect<float> GetBoundingRect() const;
    VisibleGameObject.cpp
    float VisibleGameObject::GetHeight() const
    {
        return _sprite.getLocalBounds().height;
    }
    
    float VisibleGameObject::GetWidth() const
    {
        return _sprite.getLocalBounds().width;
    }
    
    sf::Rect<float> VisibleGameObject::GetBoundingRect() const
    {
        return _sprite.getGlobalBounds();
    }

    接下来回到Game类补充一个函数,Game.h的public部分

    const static GameObjectManager& GetGameObjectManager();

    Game.cpp中的实现

    const GameObjectManager& Game::GetGameObjectManager()
    {
        return Game::_gameObjectManager;
    }

    最后就是我们的压轴嘉宾——GameBall类,代码有点长,GameBall.h

    #pragma once
    #include "visiblegameobject.h"
    
    //继承自VisibleGameObject
    class GameBall :
        public VisibleGameObject
    {
    public:
        GameBall();
        virtual ~GameBall();
        void Update(float);  //更新弹球属性状态
    
    private:
        float _velocity;  //速度
        float _angle;  //移动的方向
        float _elapsedTimeSinceStart;  //游戏总时间
    
        float LinearVelocityX(float angle); //水平线速度
        float LinearVelocityY(float angle);  //垂直线速度
    
    };

    GameBall.cpp

    View Code
    #include "StdAfx.h"
    #include "GameBall.h"
    #include "Game.h"
    
    GameBall::GameBall() :
        _velocity(230.0f),
        _elapsedTimeSinceStart(0.0f)
    {
        //assert方法作用:括号里面的表达式必须返回true,若返回false则会出现系统错误
        Load("images/ball.png");
        assert(IsLoaded());
    
        GetSprite().setOrigin(15,15);
    
        //设置弹球的移动方向为1到360之间的随机值
        _angle = std::rand() % 360 + 1; 
        //_angle = (float)(sf::Randomizer::Random(0,360);
    }
    
    
    GameBall::~GameBall()
    {
    }
    
    
    void GameBall::Update(float elapsedTime)
    {
        _elapsedTimeSinceStart += elapsedTime;
    
        // 设置弹球在开始游戏3秒后才开始更新
        if(_elapsedTimeSinceStart < 3.0f)
            return;
    
        //弹球每帧的移动距离
        float moveAmount = _velocity * elapsedTime;
    
        //水平位移
        float moveByX = LinearVelocityX(_angle) * moveAmount;
        //垂直位移
        float moveByY = LinearVelocityY(_angle) * moveAmount;
    
    
        //当弹球碰撞到屏幕两边时的处理
        if(GetPosition().x + moveByX <= 0 + GetWidth()/2 
            || GetPosition().x + GetHeight()/2 + moveByX >= Game::SCREEN_WIDTH)
        {
            //调整方向以及更改水平位移使其反弹
            _angle = 360.0f - _angle;
            if(_angle > 260.0f && _angle < 280.0f)
                _angle += 20.0f;
            if(_angle > 80.0f && _angle < 100.0f)
                _angle += 20.0f;
            moveByX = -moveByX;
        }
    
    
        //获取玩家弹板
        PlayerPaddle* player1 = dynamic_cast<PlayerPaddle*>(Game::GetGameObjectManager().Get("Paddle1"));
        if(player1 != NULL)
        {
            //存储玩家弹板的矩形区域
            sf::Rect<float> p1BB = player1->GetBoundingRect();
            
            //检测玩家弹板的矩形区域与弹球的矩形区域是否有重叠
            //有则表示发生了碰撞,然后处理相关反弹的细节
            if(p1BB.intersects(GetBoundingRect()))
            { 
                _angle =  360.0f - (_angle - 180.0f);
                if(_angle > 360.0f)
                    _angle -= 360.0f;
    
    
    
                moveByY = -moveByY;
    
                // 确保弹球不会跑到弹板的矩形区域内
                if(GetBoundingRect().width > player1->GetBoundingRect().top)
                {
                    SetPosition(GetPosition().x,player1->GetBoundingRect().top - GetWidth()/2 -1 );
                }
    
                
                float playerVelocity = player1->GetVelocity();
    
                //当弹板向左移动时
                if(playerVelocity < 0)
                {
                    //使弹球角度减少
                    _angle -= 20.0f;
                    if(_angle < 0 )
                        _angle = 360.0f - _angle;
                }
                else if(playerVelocity > 0)
                {
                    _angle += 20.0f;
                    if(_angle > 360.0f)
                        _angle = _angle - 360.0f;
                }
                //每次碰撞弹板都使弹球速度增加
                _velocity += 5.0f;
            }
    
            //当弹球碰撞到屏幕上方则令其反弹
            if(GetPosition().y - GetHeight()/2 <= 0)
            {
                _angle =  180 - _angle;
                moveByY = -moveByY;
            }
    
    
            //当弹球落到比弹板低的地方则重置弹球
            if(GetPosition().y + GetHeight()/2 + moveByY >= Game::SCREEN_HEIGHT)
            {
                GetSprite().setPosition(Game::SCREEN_WIDTH/2, Game::SCREEN_HEIGHT/2);
                _angle = std::rand() % 360 + 1;
                _velocity = 220.0f;
                _elapsedTimeSinceStart = 0.0f;
            }
    
            //弹球的移动函数
            GetSprite().move(moveByX,moveByY);
        }
    }
    
    float GameBall::LinearVelocityX(float angle)
    {
        angle -= 90;
        if (angle < 0)
            angle = 360 + angle;
        return (float)std::cos( angle * ( 3.1415926 / 180.0f ));
    }
    
    float GameBall::LinearVelocityY(float angle)
    {
        angle -= 90;
        if (angle < 0)
            angle = 360 + angle;
        return (float)std::sin( angle * ( 3.1415926 / 180.0f ));
    }

    至此如无意外你将得到像下图那样游戏,赶快按F5试试吧~~~~~

  • 相关阅读:
    剑指offer-正则表达式匹配-字符串-python****
    剑指offer-构建乘积数组-数组-python
    剑指offer-数组中重复的数字-数组-python
    剑指offer-孩子们的游戏(圆圈中最后剩下的数)-知识迁移能力-python
    剑指offer-扑克牌顺子-知识迁移能力-python
    剑指offer-左旋转字符串-知识迁移能力-python
    剑指offer-和为S的两个数字-知识迁移能力-python
    Shortest Path [3](25分)
    Topological Sort (25分)
    计算机系统基础(一):程序的表示、转换与链接(第十二周小测验)
  • 原文地址:https://www.cnblogs.com/tomboy/p/2571014.html
Copyright © 2020-2023  润新知