【问题标题】:Class management to differentiate between player keys类管理以区分玩家键
【发布时间】:2013-12-30 02:06:18
【问题描述】:

制作一个 pong 克隆,但在运动和课程方面遇到了一些问题。所以我有一个类Game 管理类Paddle 的两个实例,并在Game 类的构造函数中启动两个不同桨类中的变量并将变量player 设置为1 或@ 987654326@ 基于类将响应运动的键。然后在Paddle 类事件函数中,我使用if(player == 1)if(player == 2) 来判断何时检查键以更改桨的y 速度。我遇到的问题是因为Game 类的事件函数如下所示:

void Game::events()
{
    PlayerOne.events();
    PlayerTwo.events();
    Game_Ball.events();
}

Paddle 类的事件函数和类定义如下所示:

class Paddle
{
public:
    int player;
    SDL_Surface *sprite = NULL;
    float x, y, w, h;
    float yVel;
    SDL_Rect *clip;
    void events();
    void logic(Uint32 deltaTicks);
    void render();
    Paddle();
    ~Paddle();
};

void Paddle::events()
{
    while (SDL_PollEvent(&event))
    {
        Uint8 *keystates = SDL_GetKeyState(NULL);
        if (player == 1)
        {
            if (keystates[SDLK_o] == 1)
            {
                yVel -= 100;
            }
            if (keystates[SDLK_k] == 1)
            {
                yVel += 100;
            }
        }
        else
        {
            if (keystates[SDLK_o] == 0)
            {
                yVel += 100;
            }
            if (keystates[SDLK_k] == 0)
            {
                yVel -= 100;
            }
        }
        if (player == 2)
        {
            if (keystates[SDLK_w] == 1)
            {
                yVel -= 100;
            }
            if (keystates[SDLK_s] == 1)
            {
                yVel += 100;
            }
        }
        else
        {
            if (keystates[SDLK_w] == 0)
            {
                yVel += 100;
            }
            if (keystates[SDLK_s] == 0)
            {
                yVel -= 100;
            }
        }
    }
}

发生了一些混淆键的事情。通常 PlayerOne 使用“O/K”移动,PlayerTwo 使用“W/S”移动,但有时我按其中一个,对面的类会移动。这似乎没有意义。这是Game类的构造函数和定义

class Game : public GameState
{
private:
    int server;
    TTF_Font *score = NULL;
    Paddle PlayerOne;
    Paddle PlayerTwo;
    Ball Game_Ball;
public:
    SDL_Rect clip[2];
    void events();
    void logic();
    void render();
    Game();
    ~Game();
};

Game::Game()
{
    //RESOURSES
    PlayerOne.sprite = load_image("Game_sprite.png");
    PlayerTwo.sprite = load_image("Game_sprite.png");
    clip[0].x = 0;
    clip[0].y = 0;
    clip[0].w = 20;
    clip[0].h = 20;
    clip[1].x = 0;
    clip[1].y = 20;
    clip[1].w = 20;
    clip[1].h = 100;
    //PLAYER ONE
    PlayerOne.x = 420;
    PlayerOne.y = 100;
    PlayerOne.w = 60;
    PlayerOne.h = 100;
    PlayerOne.clip = &clip[1];
    PlayerOne.yVel = 0;
    PlayerOne.player = 1;
    //PLAYER TWO
    PlayerTwo.x = 60;
    PlayerTwo.y = 100;
    PlayerTwo.w = 60;
    PlayerTwo.h = 100;
    PlayerTwo.clip = &clip[1];
    PlayerTwo.yVel = 0;
    PlayerTwo.player = 2;
    //BALL
    Game_Ball.Ball_Bound.x = 190;
    Game_Ball.Ball_Bound.y = 190;
    Game_Ball.Ball_Bound.w = 60;
    Game_Ball.Ball_Bound.h = 60;
    Game_Ball.clip = &clip[0];
}

player 明确设置在两个对象中,Paddle 类的事件部分清楚地区分它们,那么,为什么键会混淆?我可以很容易地为第二个玩家编写另一个类,但这会效率低下,我宁愿使用同一个类的两个副本,除了键状态之外,它们的功能都相同。所以,我不确定发生了什么。

【问题讨论】:

    标签: c++ class sdl game-development


    【解决方案1】:

    乍一看,您似乎可以使用:

        if (player == 1)
        {
            if (keystates[SDLK_o] == 1)
            {
                yVel -= 100;
            }
            if (keystates[SDLK_k] == 1)
            {
                yVel += 100;
            }
        }
        else // player == 2
        {
            if (keystates[SDLK_w] == 1)
            {
                yVel -= 100;
            }
            if (keystates[SDLK_s] == 1)
            {
                yVel += 100;
            }
        }
    

    我猜对了,当错误的光标移动时,O 会向下移动错误的光标吗?

    【讨论】:

    • 你是对的,它看似随机移动,但当它移动错误时,它也会向错误的方向移动。这是为什么呢?
    • 这就是你所拥有的elses。即当 player 为 1 时,您将点击第一个 if 语句的第一部分,但您也会点击第二个 if 语句的 else 部分,即 if (player == 2) 将带你到其他部分:-)
    • 哦,我明白了。那将是正确的答案。也许你可以帮助解决桨的另一个问题。由于游戏状态具有三个不同的轮询功能,我认为三分之一的时间它没有注册键,如果你想移动,需要你按按钮混搭。我该如何解决?
    • 似乎其他答案可能对此有所帮助。我只是指出了对我来说很明显的问题,我并不热衷于猜测和给出糟糕的建议。如果您不接受答案并将其标记为有用,我不会生气,因为我似乎没有完全解决您的问题:-)
    • 哦,不,你完全做到了,按钮捣碎是一个完全不同的问题。
    【解决方案2】:

    问题似乎是你有

    if (player == 1) {
      check keys O K pressed
    }
    else {
      check keys O K released
    } 
    

    这没有任何意义,因为这会修改与在 player2 上释放的键 OK 相关的值。

    在任何情况下,您都不应该让任何游戏对象轮询事件。主游戏循环应该将它们汇集一次并将它们分派给相应的游戏元素,例如:

    void gameLoop() {
        while (true) {
        draw();
        updatePositions();
        handleEvents();
      }
    }
    
    void handleEvents() {
      while (SDL_PollEvent(&event)) {
        Uint8 *keystates = SDL_GetKeyState(NULL);
    
        if (keystates[SDLK_o]) paddle1->startMovingUp();
        else if (keystates[SDLK_k]) paddle1->startMovingDown();
        else paddle1->stopMoving();
    
        // same thing for player2
      }
    }
    
    Paddle::startMovingUp() {
      uvelY = -100;
    }
    
    Paddle::startMovingDown() {
      uvelY = 100;
    }
    
    Paddle::stopMoving() {
      uvelY = 0;
    }
    
    Paddle::updatePosition() {  // called on each frame
      positionY += uvelY;
    }
    

    您可以简化设计并仅在 handleEvents() 函数中更新位置,但是将位置更新与事件管理分开是一件好事。

    【讨论】:

    • 是的,我正在使用状态机,所以我认为让游戏对象进行轮询是可以的。 lazyfoo.net/articles/article06/index.php 对吗?还是应该在 Game::events()` 而不是 Paddle::events()` 中进行投票?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-19
    • 1970-01-01
    • 2016-01-06
    相关资源
    最近更新 更多