世界杯积分榜_世界杯几年一届 - fjmzsy.com

C语言 一步步教你做一个带有图形界面的冒险小游戏

6771

目录

简要介绍

游戏基本框架&主循环

如何在控制台实现图形界面

实现游戏不断的更新

消除闪屏

最后对一遍代码~

简要介绍

本文没有繁难的代码,所以很适合想做游戏但不知道如何做游戏的同学食用~

游戏基本框架&主循环

要想做一个游戏,首先要弄清楚游戏的基本框架:

其中,

Model代表游戏模型,存储着游戏的所有信息;

Update每时每刻都在根据Model的自身状态来对Model进行更新;

Handle是根据外界输入来调整Model的信息;

Show是对Model的信息进行翻译,并呈现在玩家眼前;

根据以上的基本理念,我们可以这样写:

int main()

{

//先处理用户的输入,并更改Model的数据

handle();

//在根据Model自身的数据来对Model进行更新

update();

//最后将Model的内容提取并展示出来

show();

handle();

update();

show();

handle();

update();

show();

...

...

}

当然,肯定不能就一直这样重复写,为此,我们需要构造一个main loop来不断读取用户输入,更新Model信息,并将信息翻译展示到玩家面前。

为了实现每秒循环一定次数的效果,我们需要#include 来构造主循环,具体如下:

#include

#define FPS 4

int main()

{

clock_t t1=0,t2=0;

while (1) {

t2 = clock();

if (t2-t1 > CLOCKS_PER_SEC*1.0/FPS) {

t1 = t2;

handle();

update();

show();

}

}

}

其中,除了三个基本函数handle,update,show外都是main loop的内容,这样便可以实现按一定的帧率(FPS)来进行游戏循环。

但是,一款游戏至少要做到随时响应玩家的输入,而现在的代码每隔1.0/FPS的时间才会响应一次玩家输入,因此我们需要多加这样几行代码:

#include

char key;

int main()

{

clock_t t1=0,t2=0;

while (1) {

t2 = clock();

if (_kbhit()) key = _getch();

if (t2-t1 > CLOCKS_PER_SEC*1.0/FPS) {

t1 = t2;

handle();

update();

show();

}

}

}

通过声明一个全局变量char key,同时又用if (_kbhit()) key = _getch()来每时每刻响应用户输入,如有输入便将用户的按键值传给key,这样handle所处理的内容便只是key的值。

OK,现在基本的东西已经搞好了,下面就可以随意发挥了!

如何在控制台实现图形界面

显然,我们并不打算去制作一款3D游戏(而且俺也不会啊(≧﹏ ≦)),而制作一款2D平面游戏的话,我们只需要一张画布即可。

首先,声明一块长宽固定的二维数组,将其当作画布(screen),然后构造一种结构类型作为演员(Actor),这样,游戏的Model就只需要存储每一位演员的样子和位置,再在需要show的时候把这些演员给渲染到screen上,最后把screen展示给玩家看即可。

#define WIDTH 100

#define HEIGHT 40

typedef struct _actor{

int width; //演员的宽度

int height; //演员的高度

char** image; //指向演员的图形

int x; //最左侧的位置

int y; //最顶部的位置

} Actor;

char screen[HEIGHT][WIDTH+1];

Actor boy; //创建一个名为boy的演员

int main()

{

...

...

}

现在,我们有一块画布宽为WIDTH+1,高为HEIGHT,之所以宽要加1,是想让每一行的最后一个字符存储的是'\n',这样在show的时候,我们可以先赋值screen[HEIGHT-1][WIDTH] = '\0',再直接把整块画布以'%s'的格式printf出来(是不是很棒的一个小技巧~)。

但是,相信大家已经注意到了,screen,key,boy这些全局变量在声明之后都还没有进行初始化,所以我们有必要统一地在一个函数里面进行全局变量的初始化。

#include //由于用到了strlen函数

void init(void)

{

for (int i = 0; i

key = '\0';

static char* image_boy[] =

//加static是为了保证离开init函数后,boy的图像依旧会被保护

{" ~@~ ",

" /BOY\\ ",

"~ ### ~",

" _/ \\_ "};

boy = (Actor){.x=2,.y=4,.width=strlen(image_boy[0]),.height=4,.image = image_boy};

}

int main()

{

init();

//main loop ...

{

最后运行的效果如下:(当然,现在show()还没有写好,所以你还看不见~( ̄▽ ̄)~*)

然后,为了能尽快看到效果,我们先把show()给写出来。(ヾ(•ω•`)o)

show()应该包含两个部分:render()以及draw()。render即渲染,把演员给誊到画布上,draw即显示,把画布给玩家显示出来。

void show(void);

void render(void);

void clear(void);

void load(Actor* actor);

void draw(void);

void show(void)

{

render();//渲染

system("cls");//清空控制台内容

draw();//显示

}

void render(void)

{

clear();//先把画布弄干净

load(&boy);//把boy誊上画布

}

void clear(void)

{

for (int i = 0; i< HEIGHT; i++) {

for (int j = 0; j < WIDTH; j ++) {

screen[i][j] = ' ';//用' '填充画布

}

}

}

void load(Actor* actor)

//传入actor的指针,而非actor本身,传输速度更快

{

for (int i = 0; iheight; i++) {

for (int j = 0; jwidth; j++) {

if (actor->image[i][j] != ' ') {

//if条件的添加,使得boy的图片像是png图像一样,有透明像素

screen[actor->y+i][actor->x+j] = actor->image[i][j];

}

}

}

}

void draw(void)

{

screen[HEIGHT-1][WIDTH] = '\0';

printf("%s\n",screen);

}

好了!现在你也能看到小boy了,是不是非常奈斯~

最后我们对一下代码,看看是不是一样的:

#include

#include

#include

#include

#include

#define FPS 4

#define WIDTH 100

#define HEIGHT 40

typedef struct _actor{

int width;

int height;

char** image;

int x;

int y;

} Actor;

char screen[HEIGHT][WIDTH+1];

char key;

Actor boy;

void init(void);

void handle(void);

void update(void);

void show(void);

void render(void);

void clear(void);

void load(Actor* actor);

void draw(void);

int main()

{

init();

clock_t t1=0,t2=0;

while (1) {

t2 = clock();

if (_kbhit()) key = _getch();

if (t2-t1 > CLOCKS_PER_SEC*1.0/FPS) {

t1 = t2;

handle();

update();

show();

}

}

}

void init(void)

{

for (int i = 0; i

key = '\0';

static char* image_boy[] =

{" ~@~ ",

" /BOY\\ ",

"~ ### ~",

" _/ \\_ "};

boy = (Actor){.x=2,.y=4,.width=strlen(image_boy[0]),.height=4,.image = image_boy};

}

void handle(void)

{

}

void update(void)

{

}

void show(void)

{

render();

system("cls");

draw();

}

void render(void)

{

clear();

load(&boy);

}

void clear(void)

{

for (int i = 0; i< HEIGHT; i++) {

for (int j = 0; j < WIDTH; j ++) {

screen[i][j] = ' ';

}

}

}

void load(Actor* actor)

{

for (int i = 0; iheight; i++) {

for (int j = 0; jwidth; j++) {

if (actor->image[i][j] != ' ') {

screen[actor->y+i][actor->x+j] = actor->image[i][j];

}

}

}

}

void draw(void)

{

screen[HEIGHT-1][WIDTH] = '\0';

printf("%s\n",screen);

}

实现游戏不断的更新

现在,我们只剩下handle和update没有写了,之所以最后写,是因为这两个函数是十分灵活的,完全取决于你的游戏内容。

那我就写一个我想的故事吧(。・ω・。)

先介绍一下所有参演角色:

static char* image_boy[] =

{" ~@~ ",

" /BOY\\ ",

"~ ### ~",

" _/ \\_ "};

boy = (Actor){.x=4,.y=22,.width=strlen(image_boy[0]),.height=4,.image = image_boy};

static char* image_bed[] =

{"| |",

"| |",

"+#############################+",

"| |__| |",

"| |__| |",

"| |__| |",

"| |__| |",

"| |__| |",

"| |__| |",

"| |__| |",

"| |__| |",

"+#############################+",

"| |",

"| |"};

bed = (Actor){.x=50,.y=10,.width=strlen(image_bed[0]),.height=14,.image=image_bed};

static char* image_guard[] =

{"! @ T",

"*~~GUARD~~+",

" \\###/ |",

" /###\\ |",

" L L |"};

guard = (Actor){.x=65,.y=16,.width=strlen(image_guard[0]),.height=5,.image = image_guard};

static char* image_ground[] =

{"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"};

ground_1 = (Actor){.x=0,.y=30,.width=strlen(image_ground[0]),.height=1,.image=image_ground};

ground_2 = (Actor){.x=12,.y=23,.width=strlen(image_ground[0]),.height=1,.image=image_ground};

效果:

对了,还要注意一件事情,就是我们定义的结构Actor还是比较简陋的,因为角色可能有很多状态,比如说,我可以搞一个叫做Monster的结构,在Actor的基础上加入血量,等级,防御力,状态等等内容,然后可以在初始化的时候声明出Monster许多的形态,比如受伤,愉悦等等。

然后就要写handle和update了,,,

好累,,写一整天了教程了,能不能赏一个赞再看(′д` )…卑微新人还没有被赞过呢...感谢~~

✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨

void handle(void)

{

switch (key) {

case 'w':

if (boy.y > 20) {

boy.y --;

} break;

case 'a':

if (boy.x > 0) {

boy.x --;

} break;

case 's':

if (boy.y < 26) {

boy.y ++;

} break;

case 'd':

if (boy.x < 90) {

boy.x ++;

} break;

}

key = '\0';

}

void update(void)

{

if (boy.x >= guard.x-boy.width && boy.x <= guard.x+guard.width) {

//boy进入guard的攻击范围

guard.y += 2;//冲撞

if (boy.y <= guard.y+guard.height) {

//boy被撞到了

static char* image_boy[] =

{" ~www",

" (>_<) ",

" ~###~ ",

" / \\ "};

boy.image = image_boy;//更换表情

boy.x -= 10;//被撞飞

}

}

}

当然啦,这个update写的很简单,所以游戏也很简单,如果可以的话,建议你也写一个自己的故事,然后自己设计一下角色图片,比如之前我做的第一个图形小游戏: (这个小游戏剧情也有一百多行呢~)

消除闪屏

之所以会闪屏,原因就在于show()里面的system("cls")会导致整个界面会清空,所以我们可以不采用清空的做法,而是采用覆盖式显示,每次draw之前将光标移到控制台的最开始的位置,然后什么都不管,直接覆盖掉原有的图像。

所以很简单,只用把原来的system("cls")改成移动光标到开始处即可,别忘了#include

system("cls");

————>>>

HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);

COORD pos = { 0,0 };

SetConsoleCursorPosition(hOut, pos);

最后对一遍代码~

#include

#include

#include

#include

#include

#include

#define FPS 4

#define WIDTH 100

#define HEIGHT 40

typedef struct _actor{

int width;

int height;

char** image;

int x;

int y;

} Actor;

char screen[HEIGHT][WIDTH+1];

char key;

Actor boy;

Actor bed;

Actor guard;

Actor ground_1;

Actor ground_2;

void init(void);

void handle(void);

void update(void);

void show(void);

void render(void);

void clear(void);

void load(Actor* actor);

void draw(void);

int main()

{

init();

clock_t t1=0,t2=0;

while (1) {

t2 = clock();

if (_kbhit()) key = _getch();

if (t2-t1 > CLOCKS_PER_SEC*1.0/FPS) {

t1 = t2;

handle();

update();

show();

}

}

}

void init(void)

{

for (int i = 0; i

key = '\0';

static char* image_boy[] =

{" ~@~ ",

" /BOY\\ ",

"~ ### ~",

" _/ \\_ "};

boy = (Actor){.x=4,.y=22,.width=strlen(image_boy[0]),.height=4,.image = image_boy};

static char* image_bed[] =

{"| |",

"| |",

"+#############################+",

"| |__| |",

"| |__| |",

"| |__| |",

"| |__| |",

"| |__| |",

"| |__| |",

"| |__| |",

"| |__| |",

"+#############################+",

"| |",

"| |"};

bed = (Actor){.x=50,.y=10,.width=strlen(image_bed[0]),.height=14,.image=image_bed};

static char* image_guard[] =

{"! @ T",

"*~~GUARD~~+",

" \\###/ |",

" /###\\ |",

" L L |"};

guard = (Actor){.x=65,.y=16,.width=strlen(image_guard[0]),.height=5,.image = image_guard};

static char* image_ground[] =

{"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"};

ground_1 = (Actor){.x=0,.y=30,.width=strlen(image_ground[0]),.height=1,.image=image_ground};

ground_2 = (Actor){.x=12,.y=23,.width=strlen(image_ground[0]),.height=1,.image=image_ground};

}

void handle(void)

{

switch (key) {

case 'w':

if (boy.y > 20) {

boy.y --;

} break;

case 'a':

if (boy.x > 0) {

boy.x --;

} break;

case 's':

if (boy.y < 26) {

boy.y ++;

} break;

case 'd':

if (boy.x < 90) {

boy.x ++;

} break;

}

key = '\0';

}

void update(void)

{

if (boy.x >= guard.x-boy.width && boy.x <= guard.x+guard.width) {

guard.y += 2;

if (boy.y <= guard.y+guard.height) {

static char* image_boy[] =

{" ~www",

" (>_<) ",

" ~###~ ",

" / \\ "};

boy.image = image_boy;

boy.x -= 10;

}

}

}

void show(void)

{

render();

HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);

COORD pos = { 0,0 };

SetConsoleCursorPosition(hOut, pos);

draw();

}

void render(void)

{

clear();

load(&ground_1);

load(&ground_2);

load(&bed);

load(&guard);

load(&boy);

}

void clear(void)

{

for (int i = 0; i< HEIGHT; i++) {

for (int j = 0; j < WIDTH; j ++) {

screen[i][j] = ' ';

}

}

}

void load(Actor* actor)

{

for (int i = 0; iheight; i++) {

for (int j = 0; jwidth; j++) {

if (actor->image[i][j] != ' ') {

screen[actor->y+i][actor->x+j] = actor->image[i][j];

}

}

}

}

void draw(void)

{

screen[HEIGHT-1][WIDTH] = '\0';

printf("%s\n",screen);

}

闯红灯去哪里交罚款
赋的成语