zoukankan      html  css  js  c++  java
  • 使用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

  • 相关阅读:
    [译文] 实体与值对象到底是不是一回事?
    实现 WebApi 自托管服务宿主于 WinForms 及其交互
    [译文] C# 8 已成旧闻, 向前, 抵达 C# 9!
    [译文] 为什么你在 C# 里总是应该使用 "var" 关键字
    通过设置iis在局域网中访问网页
    windows 10 安装使用kafka
    ASP.NET Core 2.1 中的 HttpClientFactory (Part 4) 整合Polly实现瞬时故障处理
    ASP.NET Core 2.1 中的 HttpClientFactory (Part 3) 使用Handler实现传出请求中间件
    ASP.NET Core 2.1 中的 HttpClientFactory (Part 2) 定义命名化和类型化的客户端
    Asp.net Core 2.0 OpenId Connect Handler缺失Claims?
  • 原文地址:https://www.cnblogs.com/tomboy/p/2571076.html
Copyright © 2011-2022 走看看