【问题标题】:Simple problem moving enemy in game (C / SDL)在游戏中移动敌人的简单问题(C / SDL)
【发布时间】:2023-12-28 18:20:02
【问题描述】:

我正在尝试一个简单的游戏来自学 C,但我遇到了一个非常简单的问题,我无法在 Google 上找到答案。

代码如下,为它的菜鸟可怕道歉(感谢批评!):

#include <stdio.h>
#include <stdlib.h>
#include <SDL/SDL.h>

#define AMOUNT_OF_ENEMIES 10
#define AMOUNT_OF_PIXELS_TO_MOVE 50.0

struct enemy
{
    int alive;
    SDL_Rect rect;
};

void create_enemy(struct enemy *position)
{
// Take a pointer to an array. Iterate through array looking for any 'dead' instances.
// (Re)initialise when found, ignore entirely if array is full of alive instances.

int j = 0;
while(position[j].alive == 1 && j < AMOUNT_OF_ENEMIES)
{
    ++j;
}

if(position[j].alive == 0)
{
    position[j].alive = 1;
    position[j].rect.y = 0;
}
}

void update_enemies(struct enemy *position)
{
// Iterate through a passed array looking for alive instances. If found increment     vertical position,
// unless instance is at bottom of screen in which case it's marked as dead.

int j = 0;
while(j < AMOUNT_OF_ENEMIES)
{
    if(position[j].alive == 1)
    {
        position[j].rect.y += 1;
        if(position[j].rect.y > 570)
        {
            position[j].alive = 0;
            }
        }
        ++j;
    }
}

int main(void)
{
// INITS *********************************************************************
int k;
int current_time = 0;
int previous_time = 0;
float difference_in_time = 0.0;

// Load SDL library
if(SDL_Init(SDL_INIT_EVERYTHING) != 0)
{
    printf("Problem, yo\n");
    return 1;
}

// Setup event queue
SDL_Event event;

// Create array to store enemys, initialise it
struct enemy *enemy_array = malloc(sizeof(struct enemy) * AMOUNT_OF_ENEMIES);
int j;
for(j = 0; j < AMOUNT_OF_ENEMIES; ++j)
{
    enemy_array[j].alive = 0;
    enemy_array[j].rect.x = 150;
    enemy_array[j].rect.y = 0;
}

// Create an array to flag keypresses, initialise it
int pressed_keys[323];
int l;
for(l = 0; l < 323; ++l)
{
    pressed_keys[l] = 0;
}

// Create surfaces
SDL_Surface *screen = SDL_SetVideoMode(300, 600, 0, SDL_HWSURFACE);
int black = SDL_MapRGB(screen->format, 0, 0, 0);

SDL_Surface *tower = SDL_LoadBMP("tower.bmp");
SDL_Rect tower_rect;
tower_rect.x = 50;
tower_rect.y = 0;
tower_rect.w = 200;
tower_rect.h = 600;

SDL_Surface *dude = SDL_LoadBMP("dude.bmp");
float dude_x = 0.0;
SDL_Rect dude_rect;
dude_rect.x = 120;
dude_rect.y = 500;
dude_rect.w = 60;
dude_rect.h = 100;

SDL_Surface *enemy = SDL_LoadBMP("enemy.bmp");

// GAME LOOP *****************************************************************
while(1)
{
    current_time = SDL_GetTicks();
    difference_in_time = (float)(current_time - previous_time) / 1000;
    previous_time = current_time;

    if(SDL_PollEvent(&event))
    {
        if(event.key.keysym.sym == SDLK_DOWN)
        {   
            create_enemy(enemy_array);
        }
        else
        {
            switch(event.type)
            {
                case SDL_QUIT:
                    printf("NOOOOOO\n");
                    SDL_FreeSurface(screen);
                    SDL_FreeSurface(tower);
                    SDL_FreeSurface(enemy);
                    free(enemy_array);
                    SDL_Quit();
                return 0;

                case SDL_KEYDOWN:
                    pressed_keys[event.key.keysym.sym] = 1;
                    break;

                case SDL_KEYUP:
                    pressed_keys[event.key.keysym.sym] = 0;
                    break;
            }
        }
    }

    if(pressed_keys[SDLK_LEFT] && dude_rect.x > 50)
    {
        dude_rect.x -= (AMOUNT_OF_PIXELS_TO_MOVE * difference_in_time);
    }

    if(pressed_keys[SDLK_RIGHT] && dude_rect.x < 190)
    {
        dude_rect.x += (AMOUNT_OF_PIXELS_TO_MOVE * difference_in_time);
    }

    update_enemies(enemy_array);

    SDL_FillRect(screen, NULL, black);
    SDL_BlitSurface(tower, NULL, screen, &tower_rect);
    for(k = 0; k < AMOUNT_OF_ENEMIES; ++k)
    {
        if(enemy_array[k].alive == 1)
        {
            SDL_BlitSurface(enemy, NULL, screen, &enemy_array[k].rect);
        }
    }
    SDL_BlitSurface(dude, NULL, screen, &dude_rect);
    SDL_Flip(screen);
}
return 0;
}

问题出现在这部分:

if(pressed_keys[SDLK_LEFT] && dude_rect.x > 50)
{
    dude_rect.x -= (AMOUNT_OF_PIXELS_TO_MOVE * difference_in_time);
}

if(pressed_keys[SDLK_RIGHT] && dude_rect.x < 190)
{
    dude_rect.x += (AMOUNT_OF_PIXELS_TO_MOVE * difference_in_time);
}

“dude”对象正确地向左移动,但按下右箭头键时没有任何反应。

添加 printf 告诉我 if 语句正在正确执行。删除 difference_in_time 使其工作,因此它要么与该变量有关,要么与它的操作和 AMOUNT_OF_PIXELS_TO_MOVE 有关。

我一生都无法弄清楚为什么前一个块正确执行而后者(本质上是同一件事)没有。我敢肯定这是我忽略的一些简单的事情,但我要疯了才能找到它。

【问题讨论】:

    标签: c sdl


    【解决方案1】:

    您的问题是由于四舍五入造成的。

    对于您的“老兄”,您使用的是 SDL_Rect,它使用整数坐标(如果我没记错的话,短整数)。

    您将老兄速度配置为 50,如果您的游戏以 60fps 运行(可能是因为它的简单性,如果关闭 vsync 可能会更高),您将获得每帧 0.83333 的移动值。

    此值将被截断为 int,结果为零,例如,如果 dude.x 为 10,并且您按右,则计算值将为 10.83,截断后将导致 10。

    对于左,它可以工作,因为该值被四舍五入,再次假设 dude.x 为 10,当按下左时,在第一次迭代中计算的值将是 9.17,截断它会给你 9。

    简单、糟糕的黑客解决方案

    将 AMOUNT_OF_PIXELS_TO_MOVE 增加到一个更高的值,强制 int 增加,这将解决问题。

    好的解决方案

    不使用 SDL_Rect 来存储您的字符位置,创建一个“MyRect”并在其中使用浮点值,并且仅在绘制字符时进行舍入。实际上你只需要存储字符位置,所以我会创建一个只有 x 和 y 的 Point2D 结构并使用它来跟踪字符位置。

    【讨论】:

    • 很好的答案,非常感谢。但是, SDL_BlitSurface 函数似乎只接受 SDL_Rect 。我会四处寻找,看看能不能找到替代方案。
    • 好吧,他已经编写了解决方案。编写一个函数(正是lazyfoo.net第2课中给出的那个),它将获取源和目标矩形的x/y位置、宽度和高度创建这些矩形,然后进行 blit。然后,当您实际执行 blitting 时,传递上面给出的 myRect 类中的浮点值。
    最近更新 更多