游戏中移动敌人的简单问题(C / SDL)

发布于 2024-11-26 00:56:03 字数 4697 浏览 2 评论 0原文

我正在编写一个简单的游戏来自学 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);
}

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

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

我只是无法弄清楚为什么前一个块能够正确执行而后一个块(本质上是同一件事)却不能正确执行。我确信这是我忽略的简单事情,但我会疯狂地试图找到它。

I'm hacking away at a simple game to teach myself C and I've come up against an infuriatingly simple problem that I haven't been able to Google an answer to.

Code follows, apologies for its noobie terribleness (criticisms appreciated!):

#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;
}

The issue arises at this part:

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);
}

The 'dude' object moves to the left correctly, but nothing happens when the right arrow key is pressed.

Adding a printf tells me the if statement is being executed correctly. Removing difference_in_time makes it work, so it's either something to do with that variable or the operation of it and AMOUNT_OF_PIXELS_TO_MOVE.

I just can't for the life of me figure out why the former block executes correctly and the latter (which is essentially the same thing) doesn't. I'm sure it's something simple I've overlooked but I'm going insane trying to find it.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

瞳孔里扚悲伤 2024-12-03 00:56:03

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

对于你的“家伙”,你使用的是 SDL_Rect,它使用整数坐标(如果我没记错的话,短 int )。

你将你的家伙速度配置为 50,如果你的游戏以 60fps 运行(可能是因为它的简单性,如果垂直同步关闭,速度可能会更高),你将得到每帧的运动值 0.83333。

该值将被截断为 int 并且结果将为零,例如,如果 dude.x 为 10 并且您按向右,计算出的值将是 10.83,截断后将得到 10。

对于向左,它的工作原理是因为该值向下舍入,再次假设 dude.x 为 10,当按下 left 时,在第一次迭代中计算出的值将为 9.17,截断此值将为您提供 9。

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

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

好的解决方案

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

Your problem is due to rounding.

For your "dude" you are using a SDL_Rect, that uses integer coordinates (short int if I remember correct).

You configured your dude speed to 50 and if your game is running at 60fps (probably due to its simplicity and it may be much more if vsync is off) you will get each frame a movement value of 0.83333.

This value will be truncated to a int and the result will be zero, for example, if dude.x is 10 and you press right, the calculated value will be 10.83 and when truncated this will result in 10.

For left, it works because the value is rounded down, assuming again dude.x is 10, when left is pressed, on the first iteration the calculated value would be 9.17, truncating this will give you 9.

Simple, bad and Hack Solution

Increase AMOUNT_OF_PIXELS_TO_MOVE to a higher value that forces the int to increase, this will fix the problem.

Good Solution

Does not use SDL_Rect for storing your characters position, create a "MyRect" and use float values in it and only does rounding when drawing the character. Actually you only need to store the character position, so I would create a Point2D struct with only x and y and use this to keep track of characters position.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文