接上篇,小球可以自由触碰各个方向并反弹之后,下面我们来制作挡板,并让挡板可以按照我们的规则控制起来。

以及其他的游戏控制,如基本的暂停和继续功能。大家可以站在用户的角度去思考需要什么功能


接着思路想,如论是控制挡板移动,还是游戏暂停继续,都需要按键来接受,要不停的监控用户是否按下键,并且还需要异步接受(因为同步的话会导致游戏暂停!)这里是一个难点


这里给大家介绍一个函数叫做GetAsyncKeyState,它是一个可以异步接受用户键盘输入按键的函数,即不会卡在这里不停的等待,而是会继续往下执行代码,且还有个好处就是,运行后当前窗口即便不是选中状态,控制台也能接收到按键输入。


为了简单流程方便大家理解主线,我这里给大家直接提供思路,游戏挡板的左右控制用A和D来控制,游戏暂停为P,继续为C


关于GetAsyncKeyState函数的用法,简单说该函数会返回某个键的按下情况,但由于返回有高低位两部分值,因此需要将其结果与0x8000按位与获得,如按下C键的代码则为:

1
GetAsyncKeyState(67) & 0x8000

返回值为1则表示按下,否则没有按下

我们可以首先完成暂停时调用的函数,其思路为写一个循环,不停的sleep即可,一旦收到跳出命令,则跳出循环结束,完整的暂停函数代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
int pause()        //暂停
{
    while(1)
    {
        Sleep(100);
        if(GetAsyncKeyState(67) & 0x8000 )  //按c键跳出循环,继续
        {
            break;
        }
    }
    return 0;
}

然后我们在主循环中,增加按下其他按键的判断和操作,分别判断向左向右时,即将走下一步时是否碰撞到边界,若没有就将小球的坐标更新。

注意,本次代码相比于上一版,随着需求需要适当规范了一些代码,比如多定义了一些变量,如小球坐标、挡板每次移动的步伐大小等等。

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
if(GetAsyncKeyState(65) & 0x8000) //向左
{
    if(Board_x1-STEP<=0)
    {
        Board_x1=0;
        Board_x2=100;
    }
    else
    {
        Board_x1=Board_x1-STEP;
        Board_x2=Board_x2-STEP;
    }
}
if(GetAsyncKeyState(68) & 0x8000) //向右
{
    if(Board_x2+STEP>=WIDTH-205)
    {
        Board_x1=WIDTH-305;
        Board_x2=WIDTH-205;
    }
    else
    {
        Board_x1=Board_x1+STEP;
        Board_x2=Board_x2+STEP;
    }
}
if(GetAsyncKeyState(80) & 0x8000)//暂停
{
    pause();
}

可以看到多个if判断,分别判断是否是a键、是否是d键、以及是否是p键,完成后编译程序

测试运行效果如下:

挡板移动即暂停继续控制

这里我尝试了左右移动和继续、暂停的按钮,均得到的期望的效果(虽然屏幕上没有提示,但可以看到效果)

大家可以根据自己情况尝试修改。完整代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
//弹球游戏
//www.dotcpp.com
#include <graphics.h>        // 引用图形库头文件
#include <conio.h>
#include <stdio.h>
 
#define WIDTH 640
#define HIGH 480
#define R 10
#define STEP 10
 
int Board_x1=150,Board_y1=HIGH-5,Board_x2=250,Board_y2=HIGH;
int pause()        //暂停
{
    while(1)
    {
        Sleep(100);
        if(GetAsyncKeyState(67) & 0x8000 )
        {
            break;
        }
    }
    return 0;
}
int main()
{
    int i;
    char ch;
    int score=0;
    char control;
    TCHAR ScoreBuffer[100]={"当前分数:"};
     
    int Vx=3,Vy=3;
    int x=(WIDTH-200)-100,y=HIGH/2;   //表示小球初始圆心坐标
    initgraph(WIDTH, HIGH);    // 创建绘图窗口 640x480 像素
    fillrectangle(WIDTH-200,0,WIDTH-195,HIGH);//绘制右墙
    BeginBatchDraw();
    while(1)
    {  
        //绘制小球
        setfillcolor(GREEN);   
        fillcircle(x,y,R);
 
        //绘制挡板
        setfillcolor(YELLOW);
        fillrectangle(Board_x1,Board_y1,Board_x2,Board_y2);
         
        FlushBatchDraw();
        Sleep(5);
        //原位置擦除小球图案
        setcolor(BLACK);
        setfillcolor(BLACK);
        fillcircle(x,y,R);
 
        //原位置擦除挡板
        setfillcolor(BLACK);
        fillrectangle(Board_x1,Board_y1,Board_x2,Board_y2);
     
 
        if(GetAsyncKeyState(65) & 0x8000) //向左
        {
            if(Board_x1-STEP<=0)
            {
                Board_x1=0;
                Board_x2=100;
            }
            else
            {
                Board_x1=Board_x1-STEP;
                Board_x2=Board_x2-STEP;
            }
        }
        if(GetAsyncKeyState(68) & 0x8000) //向右
        {
            if(Board_x2+STEP>=WIDTH-205)
            {
                Board_x1=WIDTH-305;
                Board_x2=WIDTH-205;
            }
            else
            {
                Board_x1=Board_x1+STEP;
                Board_x2=Board_x2+STEP;
            }
        }
        if(GetAsyncKeyState(80) & 0x8000)//暂停
        {
            pause();
        }
        x=x+Vx;
        y=y+Vy;
        if(x<=R || x>=WIDTH-203-R)
        {
            Vx=-Vx;
        }
        if(y<=R || y>=HIGH-R)
        {
            Vy=-Vy;
        }
 
    }
    EndBatchDraw();
    getch();                // 按任意键继续
    closegraph();           // 关闭绘图窗口
    return 0;
}


未完待续,下一篇我们继续~

点赞(161)

C语言网提供由在职研发工程师或ACM蓝桥杯竞赛优秀选手录制的视频教程,并配有习题和答疑,点击了解:

一点编程也不会写的:零基础C语言学练课程

解决困扰你多年的C语言疑难杂症特性的C语言进阶课程

从零到写出一个爬虫的Python编程课程

只会语法写不出代码?手把手带你写100个编程真题的编程百练课程

信息学奥赛或C++选手的 必学C++课程

蓝桥杯ACM、信息学奥赛的必学课程:算法竞赛课入门课程

手把手讲解近五年真题的蓝桥杯辅导课程

Dotcpp在线编译      (登录可减少运行等待时间)
#include<stdio.h>
int main()
הההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההה
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX