• 使用C++与SFML编写一个简单的撞球游戏Part8——添加AI弹板


    一个人玩未免有点沉闷,现在让我们来添加一个AI弹板来充当对手吧!!!

    AIPaddle.h

    #pragma once
    #include "visiblegameobject.h"
    class AIPaddle :
        public VisibleGameObject
    {
    public:
        AIPaddle(void);
        ~AIPaddle(void);
    
        void Update(float elapsedTime);
        void Draw(sf::RenderWindow& rw);
    
        float GetVelocity() const;
    
    private:
        float _velocity; 
        float _maxVelocity;
    };

    AIPaddle.cpp

    View Code
    #include "StdAfx.h"
    #include "AIPaddle.h"
    #include "Game.h"
    #include "GameBall.h"
    
    AIPaddle::AIPaddle() :
        _velocity(0),
        _maxVelocity(600.0f)
    {
        Load("images/paddle.png");
        assert(IsLoaded());
    
        GetSprite().setOrigin(GetSprite().getLocalBounds().width /2, GetSprite().getLocalBounds().height / 2);
    }
    
    
    AIPaddle::~AIPaddle()
    {
    }
    
    void AIPaddle::Draw(sf::RenderWindow & rw)
    {
        VisibleGameObject::Draw(rw);
    }
    
    float AIPaddle::GetVelocity() const
    {
        return _velocity;
    }
    
    void AIPaddle::Update(float elapsedTime)
    {
        const GameBall* gameBall = static_cast<GameBall*>
            (Game::GetGameObjectManager().Get("Ball"));
        sf::Vector2f ballPosition = gameBall->GetPosition();
    
        if(GetPosition().x -20 < ballPosition.x)
            _velocity += 15.0f;
        else if(GetPosition().x +20 > ballPosition.x)
            _velocity -= 10.0f;
        else
            _velocity = 0.0f;
    
    
        if(_velocity > _maxVelocity)
            _velocity = _maxVelocity;
    
        if(_velocity < -_maxVelocity)
            _velocity = -_maxVelocity;
    
    
        sf::Vector2f pos = this->GetPosition();
    
        if(pos.x  <= GetSprite().getLocalBounds().width/2
            || pos.x >= (Game::SCREEN_WIDTH - GetSprite().getLocalBounds().width/2))
        {
            _velocity = -_velocity; 
        }
    
        GetSprite().move(_velocity * elapsedTime, 0);
    }

    由于AI弹板也会反弹弹球,所以要把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;
    
    
        //获取玩家弹板
        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 playerVelocity1 = player1->GetVelocity();
    
                //当弹板向左移动时
                if(playerVelocity1 < 0)
                {
                    //使弹球角度减少
                    _angle -= 20.0f;
                    if(_angle < 0 )
                        _angle = 360.0f - _angle;
                }
                else if(playerVelocity1 > 0)
                {
                    _angle += 20.0f;
                    if(_angle > 360.0f)
                        _angle = _angle - 360.0f;
                }
                //每次碰撞弹板都使弹球速度增加
                _velocity += 5.0f;
            }
            
        }
    
    
    
        //敌人AI的设置
        AIPaddle* player2 = dynamic_cast<AIPaddle*>(Game::GetGameObjectManager().Get("Paddle2"));
        if(player2 != NULL)
        {
            //存储AI弹板的矩形区域
            sf::Rect<float> p2BB = player2->GetBoundingRect();
    
            //检测AI弹板的矩形区域与弹球的矩形区域是否有重叠
            //有则表示发生了碰撞,然后处理相关反弹的细节
            if(p2BB.intersects(GetBoundingRect()))
            { 
                _angle =  360.0f - (_angle - 180.0f);
                if(_angle > 360.0f)
                    _angle -= 360.0f;
    
                moveByY = -moveByY;
    
                // 确保弹球不会跑到弹板的矩形区域内
                if(GetBoundingRect().width > player2->GetBoundingRect().width)
                {
                    SetPosition(GetPosition().x,player2->GetBoundingRect().width - GetWidth()/2 -1 );
                }
    
    
                float playerVelocity2 = player2->GetVelocity();
    
                //当弹板向左移动时
                if(playerVelocity2 < 0)
                {
                    //使弹球角度减少
                    _angle -= 20.0f;
                    if(_angle < 0 )
                        _angle = 360.0f - _angle;
                }
                else if(playerVelocity2 > 0)
                {
                    _angle += 20.0f;
                    if(_angle > 360.0f)
                        _angle = _angle - 360.0f;
                }
                //每次碰撞弹板都使弹球速度增加
                _velocity += 5.0f;
            }
        }
    
    
        //当弹球碰撞到屏幕两边时的处理
        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;
        }
    
    
        //当弹球碰撞到屏幕上方则令其反弹
        if(GetPosition().y - GetHeight()/2 <= 0)
        {
    //         _angle =  180 - _angle;
    //         moveByY = -moveByY;        
            GetSprite().setPosition(Game::SCREEN_WIDTH/2, Game::SCREEN_HEIGHT/2);
            _angle = std::rand() % 360 + 1;
            _velocity = 220.0f;
            _elapsedTimeSinceStart = 0.0f;
        }
    
    
        //当弹球落到比弹板低的地方则重置弹球
        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 ));
    }

    最后还要回到Game.cpp中把AI弹板加进去(Game.h别忘记include AIPaddle)

    //添加玩家弹板并设置其位置
      PlayerPaddle *player1 = new PlayerPaddle();
      player1->Load("images/paddle.png");
      player1->SetPosition((SCREEN_WIDTH/2),700);
    
      //添加敌人AI
      AIPaddle * player2 = new AIPaddle();
      player2->SetPosition((SCREEN_WIDTH/2),40);
    
      //添加弹球
      GameBall *ball = new GameBall();
      ball->SetPosition((SCREEN_WIDTH/2),(SCREEN_HEIGHT/2)-15);
    
      _gameObjectManager.Add("Paddle1",player1);
      _gameObjectManager.Add("Paddle2",player2);
      _gameObjectManager.Add("Ball",ball);

    于是一个游戏的雏形就此诞生了

    如果觉得过程太乱的话,下载完整代码回去慢慢查看吧~~~~~

    Part1

    Part2

  • 相关阅读:
    判断以下字符串中出现次数最多的字符,并且算出该字符出现的次数
    status的状态码
    call和apply的区别?
    闭包
    $(document).ready和window. onload的区别
    python_pandas常用操作
    python经典例题
    爬B站并保存成csv文件。提供数据
    data_analysis:初识numpy
    01爬取豆瓣网电影数据进行numpy的练习
  • 原文地址:https://www.cnblogs.com/tomboy/p/2571076.html
Copyright © 2020-2023  润新知