(译)LearnOpenGL实际案例Breakout(五):小球

本文介绍了如何在Breakout游戏中实现小球的功能,包括小球的运动、反弹及与玩家挡板的交互。通过创建BallObject类并实现其Move方法,使得小球能够在游戏区域内移动并正确地反弹。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

英文原文

现在我们有一个砖块的关卡和一个可移动的玩家挡板。和经典Breakout唯一缺失的是小球。目标是让小球碰撞所有的砖块直到每一个可破坏的砖块被破坏,但是这有一个条件是小球不能触碰屏幕的底部边缘。
撇开一般的游戏组件对象,一个小球有一个半径和一个标识出小球是卡在挡板上还是可以自由移动的额外的bool值。当游戏开始,小球最初被卡在玩家挡板上直到玩家按下任意键开始游戏。
因为小球是有一些额外特性的游戏基础物体,让场景常见一个BallObject类作为GameObject的子集:

class BallObject : public GameObject
{
public:
    // Ball state   
    GLfloat   Radius;
    GLboolean Stuck;
    BallObject();
    BallObject(glm::vec2 pos, GLfloat radius, glm::vec2 velocity, Texture2D sprite);
    glm::vec2 Move(GLfloat dt, GLuint window_width);
    void      Reset(glm::vec2 position, glm::vec2 velocity);
};

BallObject的构造函数初始化它子集的值,也初始化它底层的GameObject。这个BallObject类有一个Move方法来让小球基于它的速度来移动以及检查它是否到达场景的任意一条边以及是否反弹小球的速度:

glm::vec2 BallObject::Move(GLfloat dt, GLuint window_width)
{
    // If not stuck to player board
    if (!this->Stuck)
    {
        // Move the ball
        this->Position += this->Velocity * dt;
        // Check if outside window bounds; if so, reverse velocity and restore at correct position
        if (this->Position.x <= 0.0f)
        {
            this->Velocity.x = -this->Velocity.x;
            this->Position.x = 0.0f;
        }
        else if (this->Position.x + this->Size.x >= window_width)
        {
            this->Velocity.x = -this->Velocity.x;
            this->Position.x = window_width - this->Size.x;
        }
        if (this->Position.y <= 0.0f)
        {
            this->Velocity.y = -this->Velocity.y;
            this->Position.y = 0.0f;
        }
    }
    return this->Position;
}

除了反弹小球的速度之外我们还想要沿着边移动小球。小球仅仅在它没有被卡住的时候移动。
你能在这找到小球对象的代码:
BallObject: header, code
首先让我们添加小球到游戏中。和玩家挡板相似,我们创建一个BallObject并且定义两个我们用来初始化小球的常量。作为小球的贴图,我们将会在LearnOpenGL Breakout游戏中使用一个来让场景变得完美:小球贴图。

// Initial velocity of the Ball
const glm::vec2 INITIAL_BALL_VELOCITY(100.0f, -350.0f);
// Radius of the ball object
const GLfloat BALL_RADIUS = 12.5f;

BallObject     *Ball;
void Game::Init()
{
    [...]
    glm::vec2 ballPos = playerPos + glm::vec2(PLAYER_SIZE.x / 2 - BALL_RADIUS, -BALL_RADIUS * 2);
    Ball = new BallObject(ballPos, BALL_RADIUS, INITIAL_BALL_VELOCITY,
        ResourceManager::GetTexture("face"));
}

我们必须在每一帧通过在game代码的Update方法中调用它的Move方法更新小球的位置:

void Game::Update(GLfloat dt)
{
    Ball->Move(dt, this->Width);
}

更多的,因为小球被初始化为固定在挡板上,我们必须让玩家能够从它的固定位置移除。我们选中空格键来从挡板释放小球。这意味着我们必须改变ProcessInput方法:

void Game::ProcessInput(GLfloat dt)
{
    if (this->State == GAME_ACTIVE)
    {
        GLfloat velocity = PLAYER_VELOCITY * dt;
        // Move playerboard
        if (this->Keys[GLFW_KEY_A])
        {
            if (Player->Position.x >= 0)
            {
                Player->Position.x -= velocity;
                if (Ball->Stuck)
                    Ball->Position.x -= velocity;
            }
        }
        if (this->Keys[GLFW_KEY_D])
        {
            if (Player->Position.x <= this->Width - Player->Size.x)
            {
                Player->Position.x += velocity;
                if (Ball->Stuck)
                    Ball->Position.x += velocity;
            }
        }
        if (this->Keys[GLFW_KEY_SPACE])
            Ball->Stuck = false;
    }
}

在这里,如果用户按下空格条,小球的附着参数变为false。当小球被固定住的时候我们仍然沿着挡板的位置更新ProcessInput方法来移动小球的位置。
最后,很显然我们需要渲染小球:

void Game::Render()
{
    if (this->State == GAME_ACTIVE)
    {
        [...]
        Ball->Draw(*Renderer);
    }
}

最终小球跟着挡板并且当我们按下空格条的时候自由漫步。小球仍然恰当的在左,右和顶部边缘反弹,但是它还没有碰撞任何一个砖块。
原文此处有个视频,但是我不会再CSDN博客插入mp4视频,有会的请告诉一声,谢谢。
转载请注明出处:http://blog.csdn.net/ylbs110/article/details/52722652
我们想要创建一个或多个方法来检查小球对象是否碰撞到关卡中的任何一个砖块,并且销毁这个砖块。这在下一节教程中称为碰撞检测方法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值