如何用C语言编写游戏.docx
《如何用C语言编写游戏.docx》由会员分享,可在线阅读,更多相关《如何用C语言编写游戏.docx(38页珍藏版)》请在冰豆网上搜索。
![如何用C语言编写游戏.docx](https://file1.bdocx.com/fileroot1/2023-1/23/711b5acc-343b-4332-82d6-2532408e30e5/711b5acc-343b-4332-82d6-2532408e30e51.gif)
如何用C语言编写游戏
如何用C语言编写游戏
网络游戏是常谈的话题,是交互式娱乐的主力军,是一种高层次的综合艺术,更是一个民族的文化,世界观的全新传播方式作为游戏玩家的我们,是不是想设计一个属于自己的游戏呢
爱玩是人的天性,而C语言是我们计算机专业都要学习的一门基础学科.一般来说,是比较枯燥的.那么,我们能不能通过编一些小游戏来提高它的趣味性呢这样学习程序设计,就不会是一件艰苦,枯燥的事,它变得象电脑游戏一样充满好奇,富有乐趣.这正是我要写这文档目的.
1,总是从Hello,world开始
学习编程的第一个程序,一般就是打印一个亲切的词语——"Hell
o,world!
".让我们来看看这个最简单的C程序:
#incolude<>/*把输入输出函数的头文件包含进来*/
intmain()
{
printf("Hello,world!
");/*在屏幕上输出字符串"Hello,world!
"*/return0;/*退出main函数,并返回0*/
}
下面我们发现几个值得改进的地方,1,程序的运行结果一闪而过
.2,每执行这个程序一次都能看见上次运行留下的字符.3,我们还希望屏幕输出一个笑脸来欢迎我们.(大家不要小看了这个笑脸曾经有人发贴专门问呢)让我们来改进一下这个程序吧!
1,在return语句的前面加一句:
getch();,表示按任意键结
束.2,在printf语句前用clrscr函数清屏,要使用这个函数和getch函数,需要在程序开头再包含头文件码也有
许多非常好玩的字符,比如ASCII码值为2的就是一个笑脸,我们可
以用printf("%c",2)来输出一个笑脸.
现在我们把Hello,world程序改成一个更好看的Hello,world了.下面让我们开始做游戏吧!
2,心动的开始,一个运动中的笑脸
大家小时侯喜欢看动画片吗哈哈,我猜你们都喜欢吧!
下面就让我们来做一个小动画吧.在屏幕上显示一个运动的小笑脸,而且当它到达屏幕的边缘时会自动弹回来.先在程序定义一个在屏幕中运动的点的结构:
structmove_point
{
};
运动的原理是,先擦去物体先前的轨迹,让物体按其速度移动一段距离,再画出该物体.让我们看到以下代码:
gotoxy,;/*把光标移到指定的坐标*/
printf("");/*输出一个空格,把先前的字符擦去*/
然后我们让物体按其速度运动:
+=;/*水平方向按x轴的速度运动*/
+=;/*垂直方向按y轴的速度运动*/
运动后还要判断物体是否出界,如果出了界,就令物体反弹,即让
它下一刻的速度等于现在的速度的相反数.最后打印出这个笑脸
gotoxy,;
printf("%c\b",2);/*输出ASCII码值为2的"笑脸"字符*/怎么样是不是很有趣呢不过这个笑脸一直是自己运动,能不能让我们来控制它运动呢答案是肯定的,让我们继续往下学吧!
3,交互的实现——让我们来控制笑脸运动这个程序的主要功能是接受按键,如果接收的是方向键,就让笑脸顺着方向移动,如果接收的是ESC键就退出程序,其他按键则忽略处理.接受按键我们用以下两条语句:
while(bioskey
(1)==0);/*等待按键*/
key=bioskey(0);/*把接收的按键的键盘码赋给变量key*/
然后用switch语句来判断按键以及执行相关操作,如下:
switch(key)/*对变量key的值进行判断*/
{
caseUP:
/*如果按的是向上键*/
…break;/*让物体向上运动,并退出switch*/
caseDOWN:
/*如果按的是向下键*/
…break;/*让物体向下运动,并退出switch*/
caseLEFT:
/*向左键*/
…break;;/*向左运动*/
caseRIGHT:
/*向右键*/
…break;/*向右运动*/
2004-9-919:
26回复
c闲人
202位粉丝
2楼
default:
break;/*其他按键则忽略处理*/
}
怎么样,是不是有了玩游戏的感觉了不过这个程序没有什么目的
也没有什么判断胜负的条件.下面我们就利用这个能控制它移动
的笑脸来做一个更有趣的游戏吧
4,在迷宫中探索
小时侯,我常在一些小人书和杂志上看见一些迷宫的游戏,非常喜
欢玩,还常到一些书上找迷宫玩呢.好的,现在我们用C语言来编个迷宫的游戏,重温一下童年的乐趣.
首先,我们定义一个二维数组map,用它来保存迷宫的地图,其中m
ap[x][y]=='#'表示在(x,y)坐标上的点是墙壁.DrawMap函数在屏幕上输出迷宫的地图和一些欢迎信息.
在main函数里,我们定义了”小人"man的坐标和”目的地"des的坐标.在游戏循环中,我们增加了一些用来判断胜负的语句:
if==&&==/*如果人的坐标等于目
的地的坐标*/
gotoxy(35,3);
printf("Ok!
Youwin!
");/*输出胜利信息*/
}
在判断按键时,如果玩家按的是方向键,我们还要先判断前面是不是有"墙壁",如果有的话,就不能往前移动了.好的,我们在判断按键的switch语句的各个分支加上了判断语句,如下:
if(map[…][…]=='#')break;/*如果前面是墙壁,就不执行
下去*/
哇噻!
真棒,我们做出了一个完整的游戏了.当然你还可以通过修改二维数组map来修改迷宫的地图,让它更有挑战性.不过,我们要设计一个更好玩的游戏——
5,聪明的搬运工
大家一定玩过"搬运工"的游戏吧!
这是在电脑和电子字典上较流行的益智游戏,让我们动手做一个属于自己的"搬运工"吧!
程序依然用数组map来保存地图,数组元素如果为空格则表示什么
也没有,'b'表示箱子,'#'表示墙壁,'*'表示目的地,'i
'表示箱子在目的地.我们以后每推一下箱子,不但要改变屏幕的显示,也要改变map相应元素的值.
游戏的主循环依然是接受按键.当接收一个方向键,需要判断小人
前面一格的状态,如果是空地或目的地,则人物可以直接移动;如果是墙壁,则不可移动;如果是箱子或目的地上的箱子,则需要继续判断箱子前面一格的状态:
如果前一格是空地或目的地,则人推箱子前进,否则不可移动.好的,我们在switch中增加了这些判断语句.
程序还有一个重要的功能就是判断胜利.数组Des用来记录全部目的地的坐标,我们每执行一步操作后,程序就要通过Des数组判断这些目的地上是否都有箱子了.
真棒啊!
我们可以做游戏了.而且是一个老少皆宜,趣味十足的游戏呢!
当然,我们可以通过修改map数组来制作不同的游戏地图,我们还可以相互分享好的游戏地图呢.
尾声:
在C++等高级语言还没出来的时候,很多应用程序也是C语言开发的
.C语言在与硬件联系紧密的编程中,也占有重要地位.其实我觉得学习编程,可以通过一些小游戏,实用的例子来学习.象学习音乐的人,不是要等到把全部乐理学完后才演奏一个完整的曲子.而是刚开始学时就有一些简单的曲子让你演奏,让你立刻就有成就感,让你很快就能卖弄出来在别人面前表现自己了.通过编游戏来学习编程,把学习变成游戏,不失为学习计算机的一种好方法.
好了,编游戏就这么简单,希望大家也尝试用C语言或其他的语言
来做几个自己喜欢的小游戏
时间延迟函数函数名:
delay
功能:
将程序的执行暂停一段时间(毫秒)
用法:
voiddelay(unsignedmilliseconds);
重画屏幕区域的函数函数名:
getimage
功能:
将指定区域的一个位图存到主存中
用法:
voidfargetimage(intleft,inttop,intright,intbottom,voidfar*bitmap);
函数名:
putimage
功能:
在屏幕上输出一个位图
int
用法:
voidfarputimage(intx,inty,voidfar*bitmap,op);
图像大小函数
函数名:
imagesize
功能:
返回保存位图像所需的字节数
用法:
unsignedfarimagesize(intleft,inttop,intright,intbottom);
异或模式函数
函数名:
setwritemode
功能:
设置图形方式下画线的输出模式
用法:
voidfarsetwritemode(intmode);
参数MOD可以被设置位COPY_PU或者XOR_PU两种模式。
当mode被设置为XOR_PU,其后的图形操作将都采用异或方式。
此外之前提到的putimage()函数也可以采用异或模式向屏幕复制图像。
检测键盘输入函数
函数名:
kbhit
功能:
检查当前按下的键
用法:
intkbhit(void);
键盘接口函数
函数名:
bioskey
功能:
直接使用BIOS服务的键盘接口
用法:
intbioskey(intcmd);
该函数通过bois中断0x16执行键盘操作,由参数cmd来决定具体的操作。
Cmd具体操作0读取按键的ascii码
1测试是否有按键如果没有按键返回0如果按键为ctrl+brk返回-1如果是其他按键返回按键本身键值(直到此按键被取出后恢复
0)
2返回shiftkey状态
以下是当cmd为2的时候,返回值的具体含义
cmd返回值触发特殊键
0X01Leftctrl
0X02Leftalt
0X04Rightctrl
0X08Rightalt
0X10Scrolllock
0X20Numlock
0X40Capslock
0X80Sysrq
bioskey()函数的优点在于:
1.和kbhit()函数一样可以在不影响主程序运行的情况下检测是否有
按键;
2.可以方便地检测普通键具体ASCII码和扫描码;
3.可以方便地检测功能键具体扫描码;
4.可以检测特殊按键;
5.只需要一个函数就能解决检测按键和读入按键的任务
声音与延迟函数
函数名:
sound
功能:
以指定频率打开PC扬声器
用法:
voidsound(unsignedfrequency);
函数名:
nosound
功能:
关闭PC扬声器
用法:
voidnosound(void);
函数名:
delay
功能:
将程序的执行暂停一段时间(毫秒)
用法:
voiddelay(unsignedmilliseconds);
sound()函数用于让pc喇叭发声,nosound()函数用于使正在发声的pc喇叭静音。
要使程序中的发声的具体方法,是调用sound()函数并延迟一定时间,然后使用nosound()函数静音,具体语句实现方法如下:
sound(100);
delay(100);
nosound();
产生随即数函数
函数名:
rand
功能:
随机数发生器
用法:
voidrand(void);
函数名:
random
功能:
随机数发生器
用法:
intrandom(intnum);
初始化随机数函数
函数名:
randomize
功能:
初始化随机数发生器
用法:
voidrandomize(void);
in86()函数
函数名:
int86
功能:
通用8086软中断接口
用法:
intint86(intintr_num,unionREGS*inregs,unionREGS*outregs);
其中intr_num为软中断号,函数通过inregs寄存器向中断发出具体功能命令,函数将中断调用结果返回寄存器outregs。
memset()函数
函数名:
memset
功能:
设置s中的所有字节为ch,s数组的大小由n给定
用法:
void*memset(void*s,charch,unsignedn);
标准VGA显示模式表
模式(16进制)适配器显示类型颜色字符格式屏幕大小字符大小缓冲区首址属性类型
0/1CGA文本16/1640*25320*2008*8B8000彩色
EGA文本16/6440*25320*3508*14B8000彩色
赞
0
2004-10-2221:
37回复
c闲人
202位粉丝
2楼
VGA文本16/256K40*25360*4009*16B8000彩色
CGA文本16/1680*25640*2008*8B8000彩色
2/3EGA文本16/6480*25640*3508*14B8000彩色
VGA(3+)文本16/256K80*25720*4009*16B8000彩色
CGA图形4/1640*25320*2008*8B8000彩色
4/5EGA图形4/6440*25320*2008*8B8000彩色
VGA图形4/256K40*25320*2008*8B8000彩色
CGA图形2/1640*25640*2008*8B8000单色
6EGA图形2/6440*25640*2008*8B8000单色
VGA图形2/256K40*25640*2008*8B8000单色
7MDA/EGA文本单色80*25720*3509*14B0000单色
VGA(7+)文本单色80*25720*4009*16B0000单色
DEGA图形16/6440*25320*2008*8A0000彩色
VGA图形16/256K40*25320*2008*8A0000彩色
EEGA图形16/6480*25640*2008*8A0000彩色
VGA图形16/256K80*25640*2008*8A0000彩色
FEGA/VGA图形单色80*25640*3508*14A0000单色
10EGA图形16/6480*25640*3508*14A0000彩色
VGA图形16/256K80*25640*3508*14A0000彩色
11VGA图形2/256K80*30640*4808*16A0000彩色
12VGA图形16/256K80*30640*4808*16A0000彩色
13VGA图形256/256K40*25320*2008*8A000彩色
常规内存函数
malloc(),farmalloc(),calloc(),farcalloc(),realloc(),fareall
oc()
函数名:
malloc
功能:
内存分配函数
用法:
void*malloc(unsignedsize);
函数名:
farmalloc
功能:
从远堆中分配存储块
用法:
voidfar*farmalloc(unsignedlongsize);
函数名:
calloc
功能:
分配主存储器
用法:
void*calloc(size_tnelem,size_telsize);
函数名:
farcalloc
功能:
从远堆栈中申请空间
用法:
voidfar*farcalloc(unsignedlongunits,unsignedlingunitsz);
函数名:
realloc
功能:
重新分配主存
用法:
void*realloc(void*ptr,unsignednewsize);
函数名:
farrealloc
功能:
调整远堆中的分配块
用法:
voidfar*farrealloc(voidfar*block,unsignedlongnewsize);
使用函数:
memcpy(),memset(),memmove(),movedata()函数名:
memcpy
功能:
从源source中拷贝n个字节到目标destin中
用法:
void*memcpy(void*destin,void*source,unsignedn);
函数名:
memset
功能:
设置s中的所有字节为ch,s数组的大小由n给定
用法:
void*memset(void*s,charch,unsignedn);
函数名:
memmove
功能:
移动一块字节
用法:
void*memmove(void*destin,void*source,unsignedn);
函数名:
movedata
功能:
拷贝字节
用法:
voidmovedata(intsegsrc,intoffsrc,intsegdest,intoffdest,unsignednumbytes);
释放函数:
free(),farfree()
函数名:
free
功能:
释放已分配的块
用法:
voidfree(void*ptr);
函数名:
farfree
功能:
从远堆中释放一块
用法:
voidfarfree(void);
指针操作函数:
MK_FP(),FP_OFF(),FP_SEG()
函数名:
MK_FP
功能:
设置一个远指针
用法:
voidfar*MK_FP(unsignedseg,unsignedoff);
函数名:
FP_OFF
功能:
获取远地址偏移量
用法:
unsignedFP_OFF(voidfar*farptr);
函数名:
FP_SEG
功能:
获取远地址段值
用法:
unsignedFP_SEG(voidfar*farptr);
XMS功能调用索引表:
功能号功能版本
功能00H功能01H功能02H功能03H功能04H功能05H功能06H功能07H功能08H功能09H功能0AH功能0BH功能0CH功能0DH功能OEH功能OFH功能10H功能11H取XMS版本号请求高内存区
HMA释放高内存区HMA全程启用A20全程停用A20局部启用A20局部停用A20查询A20状态查询自由扩展内存分配扩展内存块释放扩展内存块移动扩展内存块锁住扩展内存块扩展内存块解锁取
EMB句柄信息重新分配扩展内存块请求上位存储块UMB释放上位
范XMS规范XMS规范XMS规范XMS规范XMS规范XMS规范XMS规范XMS规范XMS规范XMS规范XMS规范XMS规范
以下是一个用线和矩形绘制的简单赛车
#include<>
#include<>
voidmain(void){
intgdriver=DETECT,gmode;
initgraph(&gdriver,&gmode,"");
setbkcolor(7);
setwritemode(XOR_PUT);
setcolor(BLUE);
setlinestyle(SOLID_LINE,0,3);
rectangle(280,350,320,390);
rectangle(270,340,330,350);
rectangle(290,320,310,340);
rectangle(270,390,330,400);
setcolor(5);
line(290,350,290,390);
line(300,300,300,320);
line(300,350,300,390);line(310,350,310,390);
line(285,300,315,300);
getch();
closegraph();
}
接下来我们试着绘制赛道,周围的绿化树木和简单的集装箱车代码如下:
#include<>
#include<>
#include<>
#include<>
#include<>constintu=26;inti=2;intj=3;
voidroad(void)
{
inth;
for(h=0;h<4;h++)line(150+h*100,0,150+h*100,472);
for(h=0;h<3;h++)
{setlinestyle(3,0,1);
line(200+h*100,0,200+h*100,472);
settextstyle(1,HORIZ_DIR,3);
}
}
voidtree(void)
{
intw;
intpoly[14];
setcolor(10);
setlinestyle(SOLID_LINE,0,3);
for(w=-3;w<3;w=w+2)
{
line(85,-25+u*15+w*157,85,35+u*15+w*157);line(95,-25+u*15+w*157,95,35+u*15+w*157);line(105,-25+u*15+w*157,105,35+u*15+w*157);line(115,-25+u*15+w*157,115,35+u*15+w*157);line(75,-9+u*15+w*157,75,19+u*15+w*157);line(125,-9+u*15+w*157,125,19+u*15+w*157);}
for(w=-2;w<3;w=w+2)
{
poly[0]=530;
poly[1]=u*15+w*157;
poly[2]=515;
poly[3]=25+u*15+w*157;
poly[4]=485;
poly[5]=25+u*15+w*157;
poly[6]=470;
poly[7]=u*15+w*157;
poly[8]=485;
poly[9]=-25+u*15+w*157;
poly[10]=515;
poly[11]=-25+u*15+w