如何同时移动两个对象(Ncurses)

How to move two objects simultaneously (Ncurses)

我正在尝试让玩家和敌人同时进行基本的动作。有什么方法可以正确完成此操作吗?

下面是粗略的实现方式。我想移动 x 也在移动,但我一次只能让其中一个工作。我尝试使用 while 循环,但也许还需要其他东西...

有什么建议吗?

#include <stdio.h>
#include <stdlib.h>
#include <curses.h>
#include <windows.h>

WINDOW* createwindow();
char theplayer();
char theenemy();

int main()
{
    initscr();

    WINDOW* border=createwindow();

    while(1)
    {
    theplayer();
    theenemy();
    }
    wgetch(border);
    endwin();
    return 0;
}

WINDOW* createwindow()

{
    WINDOW* temp=newwin(15,40,10,10);
    box(temp,0,0);
    return temp;
}

char theplayer(WINDOW* border)
{
    int playerlocationy=3;
    int playerlocationx=3;
    int input;
    char player='@';
    keypad(border,true);

    mvwprintw(border,3,3,"%c",player);

    while(1)
    {
        input=wgetch(border);

        switch (input)
        {
            case KEY_LEFT:
            mvwprintw(border,playerlocationy,playerlocationx,"%c",' ');
            playerlocationx--;
            mvwprintw(border,playerlocationy,playerlocationx,"%c", player);
            break;
            case KEY_RIGHT:
            mvwprintw(border,playerlocationy,playerlocationx,"%c",' ');
            playerlocationx++;
            mvwprintw(border,playerlocationy,playerlocationx,"%c", player);
            break;
            case KEY_UP:
            mvwprintw(border,playerlocationy,playerlocationx,"%c",' ');
            playerlocationy--;
            mvwprintw(border,playerlocationy,playerlocationx,"%c", player);
            break;
            case KEY_DOWN:
            mvwprintw(border,playerlocationy,playerlocationx,"%c",' ');
            playerlocationy++;
            mvwprintw(border,playerlocationy,playerlocationx,"%c", player);
            break;
            default:
            break;
        }
break;
    }
return player;
}

char theenemy(WINDOW* border)
{
    char enemy='X';
    int enemylocationy=9;
    int enemylocationx=9;

    while(1)
    {
        mvwprintw(border,enemylocationy,enemylocationx,"%c", enemy);

        mvwprintw(border,enemylocationy,enemylocationx,"%c",' ');
        enemylocationx++;
        mvwprintw(border,enemylocationy,enemylocationx,"%c", enemy);
        wrefresh(border);
        Sleep(1000);
    }
return 0;
}

首先,这些函数 声明

char theplayer();
char theenemy();

是 C 的 obsolescent feature,也就是说这些函数将采用 未指定 但固定数量的参数。有了这个,编译器就无法推断出这些函数的调用应该是什么样子。

这隐藏了您的程序有 undefined behaviour 的事实。两个函数 definitions 都需要一个 WINDOW * 参数,但你调用它们时没有参数。

while(1)
{
    theplayer();
    theenemy();
}

这个程序能按原样运行在任何程度上纯属偶然。始终在声明中使用正确的函数原型

WINDOW *createwindow(void);
char theplayer(WINDOW *);           
char theenemy(WINDOW *);

这将有助于发现错误。


Sleep 使用 <windows.h> 会降低程序的可移植性。您已经在使用 curses,它提供了非常相似的 napms 功能。


至于“同步移动”,大意是只有一个主事件循环。每次迭代,这个循环

  1. 处理输入
  2. 更新实体
  3. 重绘屏幕

没有其他东西应该阻止程序的执行(即,永远循环)。

要更新你的敌人,你需要一些方法来跟踪已经过了多少时间。这可以像 delta timing 一样高级,也可以像帧计数器一样简单,如下所示。

这是一个粗略的示例,可以帮助您入门:

#include <curses.h>

struct entity {
    int y;
    int x;
    unsigned char repr;
};

void update_player(struct entity *, int);
void update_enemy(struct entity *, unsigned);
void draw_entity(struct entity *, WINDOW *);

int main(void)
{
    initscr();
    noecho();
    curs_set(0);

    WINDOW *field = newwin(15, 40, 10, 10);
    keypad(field, TRUE);
    wtimeout(field, 0);

    struct entity player = { 3, 3, '@' };
    struct entity enemy = { 9, 9, 'X' };
    unsigned tick = 1;

    while (1) {
        /* handle input */
        int c = wgetch(field);

        if ((c & A_CHARTEXT) == 'q')
            break;

        /* update stuff */
        update_player(&player, c);
        update_enemy(&enemy, tick);

        /* draw things */
        wclear(field);
        box(field, 0, 0);
        draw_entity(&player, field);
        draw_entity(&enemy, field);
        wrefresh(field);

        tick = (tick > 60) ? 0 : tick + 1;
        napms(16);
    }

    delwin(field);
    endwin();
}

void update_player(struct entity *p, int ch)
{
    switch (ch) {
        case KEY_LEFT:
            p->x--;
            break;
        case KEY_RIGHT:
            p->x++;
            break;
        case KEY_UP:
            p->y--;
            break;
        case KEY_DOWN:
            p->y++;
            break;
    }
}

void update_enemy(struct entity *e, unsigned t)
{
    if (t == 60)
        e->x++;
}

void draw_entity(struct entity *et, WINDOW *f)
{
    mvwaddch(f, et->y, et->x, et->repr);
}