You are on page 1of 13

局部更新版本目录

I.游戏主体的实现--------------------------------------------------------------02
A.如何设计数组------------------------------------------------------02
B.如何生成实体------------------------------------------------------02
1)对向小车:move_raceDowntrN----------------------02
2)对向油包:move_fuelDown---------------------------03
C.如何实现对向实体下落-----------------------------------------04
1)对向小车:move_raceDowntrN----------------------04
2)对向油包:move_fuelDown---------------------------04
3)道路标线:relativity_theory--------------------------05
D.如何判断碰撞------------------------------------------------------05
1)对向实体下落导致 collision----------------------------05
2)小车移动导致 collision----------------------------------06
E.如何使小车移动---------------------------------------------------06
1)左右移动:move_carR/L----------------------------------06
2)前后移动:move_carF/B----------------------------------08
F.如何清除实体-------------------------------------------------------09
G.如何重置数据------------------------------------------------------10
II.显示部分(局部更新)的实现------------------------------------------10
III.BGM 与音效的实现---------------------------------------------------------11
A.如何将资源挂载在资源文件中-------------------------------11
B.PlaySound 的播放与停止---------------------------------------13
C.mciSendString 的部署与播放----------------------------------13
IV.其他代码与问题解决--------------------------------------------------------13
A.如何使用 rand 函数------------------------------------------------------13

1
I.游戏主体的实现(配合数组规划表)
此赛车游戏分为设计数组、生成实体、对向实体下落、判断碰撞、实体变道、清除实体与
重置数据。
所有操作都针对数组来进行,最终将数组内容按排版打印出来作为画面。

A.如何设计数组

本游戏设定了一个全局的二维 char 类型数组作为实体数据储存区,0 组成本


向小车,I 组成对向小车,|组成车道划线,F 为加油包。
在数组中最后两行为防止溢出区,因为对向车要最终落入这两行,故需要预
留。
生成实体、对向实体下落、判断碰撞、实体变道、清除实体与重置数据都是对此
全局数组进行操作。设计赛道数组时可以利用 excel 表格来辅助设计,附件已携带
数组规划表。

B.如何生成实体

本向实体只有自己的 0 小车,0 小车直接写在赛道数组中。对向实体生成利用


move_raceDowntrN 和 move_fuelDown 函数生成。

1)对向小车:move_raceDowntrN
对向小车利用 rowN 记录操作行,passN 记录经过行,sideN 记录各行车
数量(方便判定总数,但每条车道最多一辆车)。

生成前
a)在主函数中判断确定 sideN 总和小于最高生成车数量,再使用 rand
函数确定本次生成小车的赛道 pick_side。
b)判断确定新生成的小车不会造成如下图的围困(数组规划表中
sheet1 围困),造成则离开生成。

c)判断确定 pike_side 对应的 sideN==0 确保一个赛道不会出现两辆车


d)设定 sideN=1,passN=0,rowN=0

2
生成
判定 sideN==1 调用 move_raceDowntrN 函数,函数会在对应操作位置{ [rowN]
[4*N-3], [rowN][4*N-1], [rowN+1][4*N-2], [rowN+2][4*N-3], [rowN+2][4*N-1]
}(如下图)

放置‘ ’并使得操作行 rowN++,在新的对应操作位置放置‘I',最终各路效果


如下图。

3
2)对向油包:move_fuelDown
油包利用 fuel_side 记录油包赛道,fuel_set 记录是否生成了油包,
row_fuel 记录油包操作行,fuel_bak 记录上一次吃到油包时的行驶距离。
生成前
a)在主函数中判断确定 fuel_set=0,即没有生成油包,再跟据行驶距离
count 减上次吃到油包时的行驶距离 fuel_bak 得出中间经过路程,路程大于
难度乘 7.5 保证高难度时少生成油包,再使用 rand 函数确定本次生成油包的
赛道 fuel_side。
b)判断确定新生成的油包不与对向小车重叠。
c)设定 fuel_set=1,row_fuel=0
生成
判定 sideN==1 调用 move_raceDowntrN 函数,函数会在对应操作位置
[row_fuel][fuel_side*4+2]处放置‘ ’并使得操作行 row_fuel++,在新的对应操
作位置放置‘F'。

C.如何实现对向实体下落

1)对向小车:move_raceDowntrN
对向小车利用 rowN 记录操作行,passN 记录经过行,sideN 记录各行车
数量(方便判定总数,但每条车道最多一辆车)。
判定 sideN==1 调用 move_raceDowntrN 函数,函数会在对应操作位置{ [rowN]
[4*N-3], [rowN][4*N-1], [rowN+1][4*N-2], [rowN+2][4*N-3], [rowN+2][4*N-1]
}使用’ ’替换’I’(如下图)

使得操作行 rowN++,在新的对应操作位置放置‘I'。

4
2)对向油包:move_fuelDown
油包利用 fuel_side 记录油包赛道,fuel_set 记录是否生成了油包,
row_fuel 记录油包操作行。
判定 sideN==1 调用 move_raceDowntrN 函数,函数会在对应操作位置
[row_fuel][fuel_side*4+2]处放置‘ ’将上一个‘F’抹掉并使得操作行
row_fuel++,在新的对应操作位置放置‘F'。

3)道路标线:relativity_theory
道路标线利用 steps 记录总行进步数。
道路标线在下落中共有 3 种状态,分别标号为 0,1,2。见下图可以看出 0 时 0
为空格其他为|,利用%对 steps 和 row 取余,按照规律分别赋值空格与|。

D.如何判断碰撞

1)对向实体下落导致 collision
先根据小车前进量 car_pos 确定车前位置的坐标[ROW-5-car_pos][4*N-3]
(如图所示红色方框为车前位置)

5
如果车前位置为 I,即有对向来车,则判断碰撞发生,collision =
true。
判断获得加油包与碰撞类似,先获取车中间 0 的操作坐标,再在油包下
落时判断油包是否会将改‘0’覆写,是则获得油包并重置油包状态。

2)小车移动导致 collision
代码已规定在左右有车时不可变动赛道,具体参见 1)左右移动:move_carL/R
,所以小车移动导致 collision 只考虑前后移动情况。
先根据小车前进量 car_pos 确定车位置的坐标[ROW-4-car_pos][4*N-3](左
前轮,见上图)与[ROW-2-car_pos][4*N-3](左后轮,见上图)。
在可前进时判断[ROW-5-car_pos][4*N-3](左前轮上方,见上图)是不
是‘I’,是则判定碰撞。
在可后退时判断[ROW-1-car_pos][4*N-3](左后轮下方,见上图)是不
是‘I’,是则判定碰撞。
判断获得加油包与碰撞类似,先获取车中间 0 的操作坐标,再在前进后
退与左右移动时判断新的操作坐标是否会将‘F’覆写,是则获得油包并重置
油包状态。

E.如何使小车移动

1)左右移动:move_carR/L
小车前进量用 car_pos 储存,最开始时前进量为 0 如下图。

6
移动前
如需要向右变动赛道先判定右侧无车,即下图中红色区域不存在‘I’。
向左移动同理。图中红色区域坐标为 [ROW - 5 - car_pos][10]到[ROW - 1 -
car_pos][10]。

同时还需确定是否能左右移动,如在 tr1 则不能左移,在 tr4 则不能右移。


移动时
如向右移动一个赛道,将下图红色区域中的所有‘0’覆写上‘ ’,同
时在右边第四格写入‘0’。
注意顺序,向右移动时需要从右往左遍历将 0 搬走,向左移动则相反,
即将‘0’搬到已经遍历过的区域而不是接下来即将继续遍历的区域,否则将
不断循环将‘0’搬到最左/右边。

7
如果在中间的‘0’右方第四格有‘F’,则获得加油包并重置加油包状
态。

8
2)前后移动:move_carF/B
小车前进量用 car_pos 储存,最开始时前进量为 0 如下图。

移动前
先判定 car_pos 是否等于 0 或者等于最大值,若等于 0 则无法后退,等于
最大值则无法前进。
移动时
将下图红色区域中的所有‘0’覆写上‘ ’,同时在上/下方写入‘0’。
注意顺序,向前(上)移动时需要从上往下遍历将 0 搬走,向后(下)
移动则相反,即将‘0’搬到已经遍历过的区域而不是接下来即将继续遍历的
区域,否则将不断循环将‘0’搬到最上/下边。

如果在中间的‘0’上/下方有‘F’,则获得加油包并重置加油包状态。

9
F.如何清除实体

在对向实体下落时,有 passN 与 pass_fuel 记录下落的路程,当 passN 或


pass_fuel 等于 ROW-1 时为下图的状态。

此时将所有放置状态重置为 0,即可停止下落。(参照 C.如何实现实体下


落 在放置状态为 0 时不下落)此时实体只剩显示残留。
将下图的红色区域都写入‘ ’,即可消除显示残留,而更下方的两行防
溢出区因为不打印不必写入‘ ’。

10
G.如何重置数据

为了能重复游玩,在重新开始前应当将所有数据重置,重中之重是重置
赛道,可在 clear 函数中预存车道数组备份,在重置时使用嵌套循环将备份赋
值给赛道数组。
在双缓冲显示中,还应当把 Game Over 提示与残留的赛道清理掉,需要
运用 WriteConsoleOutputCharacterA 函数使用填满空格的数组逐行打印在两个缓冲
区上。

II.显示部分(局部更新)的实现
引入 gotoxy 函数,原理为获得系统显示缓冲区的句柄,将光标移至
(0,0),不清屏只替换不同部分减少闪屏。
只需要将 system(“cls”)替换为 gotoxy(0, 0)即可。

III.BGM 与音效的实现
PlaySound 函 数 一 次 只 能 播 放 一 首 曲 子 , SND_NOSTOP 的 实 现 不 理 想 , 所 以 额 外 需 要
mciSendString 来实现播放音效。同时 Playsound 只能播放 wav 格式的音频,mciSendString 只
能播放 mp3 格式的音频。

A.如何将资源挂载在资源文件中

如果读取本地目录,那么编译后的 exe 的移植性就不太好,会在脱离电


脑与目录时无法播放音乐音效,所以可以将音乐资源内置在资源文件内。

11
选中文件后选择打开,打开后不管提示任何“已打开…………”都选择
确定。若导入 mp3 文件,格式选择或填写 MP3。之后应当会生成一个.rc 文件,
按下面的图打开它并继续确认。

打开后下图红圈处是资源编号,可用 MAKEINTRESOURCE(IDR_WAVE1)形
式供调用。

12
B.PlaySound 的播放与停止

播放参数参见:c++—— 使用 PlaySound() 播放声音 _playsound 调用声



停止:运用 PlaySound(NULL, NULL, SND_FILENAME)播放空文件即可停
止播放 BGM。

C.mciSendString 的部署与播放

1)声明 N+1 个全局 TCHAR 类型数组储存路径信息(N 为音效个数)


2)用 extract 函数调用 ExtractResource 函数批量导出临时 mp3 文件。

3)利用 playMUSICNAME 播放音乐

IV.其他代码与问题解决

A.如何使用 rand 函数

由于 C 语言是利用 linear congruential generator 作为生成器来生成伪随机数,但是


这个生成器生成伪随机数,需要一个“种子”来进行运算。而如果我们仅仅调用 rand()
函数,而没有设置随机数种子,rand()函数在调用时,自动设计随机数种子为 1。随机
种子相同,每次产生的随机数也会相同。解决办法就是使用 srand()函数产生随机种子。
为保证每次产生不同的种子,可以使用 time(NULL)和 getpid(NULL)的返回值作为
srand 的参数,以产生不同的种子。
故而需要先在 main 函数内 srand((unsigned)time(NULL))。再调用 rand()。为了约束
rand 生成数的范围如生成 0-39 的随机数,可以使用 rand() % 40 来得到。

13

You might also like