-
2D 项目简介
项目的创意设想、实现功能、项目意义(200字左右)
作品代表图
项目名:
机器人双人格斗游戏
项目的创意设想:
当前ai大火,机器人也是日常生活中的一个热点,自己在小学乃至高中也经常玩格斗游戏。曾经也想过格斗游戏是怎么做的,可是那时候条件有限,而且也没有编程基础。这个想法就一直留到了大学。到大三学习计算机图形学,也有了一定的编程基础,认为这个格斗游戏可以自己完成了。便开始动手,经过几天的努力,终于把这个游戏实现了。
实现功能:
画了机器人1(乌巢之子),机器人2(关山之月)实现其的技能有:
- 上下左右移动:实现了平移
- 弹跳:使用了重力加速度实现了起跳落下的算法,
- 眼睛发射镭射光线:实现了平移
- 肚载大炮发射:实现了平移
- 手臂可以伸长:实现了平移
- 被炮弹击中会倒退:使用了旋转变换之类函数,实现了旋转
- 法天相地(放大):实现了放大 – 经过一段时间也会缩放到原来的大小
- 计时功能:使用了时间回调函数
- 使用了win32API函数,可以插入声音
项目意义:
自己在开始做这个游戏的时候,也上网百度看是否有类似的格斗游戏,这类型指的是使用opengl库制作的2D无游戏引擎的双人格斗游戏,发现找不到类似的游戏,可以说是网上几乎没人做过类似的2D无游戏引擎的双人格斗游戏。可以说这个游戏填补了当类游戏的空白,也可以给后来者加以参考。
作品代表图:
-
编程环境(电脑硬件、操作系统和VS平台)说明
-
电脑硬件:thinkpad x250,
cpu:i3
内存:4g
操作系统:win10
Vs:vs2017
-
程序操作说明
-
操作如下图:
编程环境(电脑硬件、操作系统和VS平台)说明
电脑硬件:thinkpad x250,
cpu:i3
内存:4g
操作系统:win10
Vs:vs2017
-
程序操作说明
操作如下图:
按键b:开始游戏
对角色1(乌巢之子)进行操作有:
1、wsad:上下左右移动
2、z:长拳攻击
3、x:从眼部发射镭射光线
4、c:肚载大炮,肚子发射大炮,攻击力强于镭射光线
5、e:法天相地,变大
6、r:弹跳
对角色2(关山之月)进行操作有:
- ikjl:上下左右移动
- n:长拳攻击
- m:镭射光线
- O:肚载大炮,肚子发射大炮,攻击力强于镭射光线
- U:法天相地(变大)
- P:弹跳
当两者的某一方血条为0时,游戏结束,效果如下:
-
程序实现
-
创意详细说明:
- 算法类、模拟类: 算法说明,想要实现的效果说明
1、注册这几个函数,才可以使窗口不断回画,并计时,也是基于这几个注册函数才仿佛实现了同步,而不必使用多线程。
glutTimerFunc(1000, mytime, 10);
//注册闲时函数
glutDisplayFunc(&Display);
//在程序运行时是自动调用的,即程序会自动调用display函数重绘窗口
glutMainLoop();
//进入事件处理循环
2、使用了重力加速度公式设计的弹跳-起跳落下的模拟
在机器人1里写了一个弹跳函数(机器人2类似)
类成员:
jumpTime = 0;
jflag = 0;
h = 5.0;
函数
void
Robot1
::skillr()
//跳高
{
jumpTime++;
float
g = 0.00005;
if
(jflag == 1)
{
float
addh = 1.0 / 2.0 * g * jumpTime * jumpTime;
this
->y += addh;
this
->h -= addh;
if
(
this
->h <= 0)
{
jflag = 2;
jumpTime = 0;
}
}
else
if
(jflag == 2)
{
float
addh = 1.0 / 2.0 * g * jumpTime * jumpTime;
this
->y -= addh;
this
->h += addh;
if
(
this
->h >= 5.0)
{
jflag = 0;
jumpTime = 0;
}
}
}
主页面交互(键盘点击):
case
‘R’
:
case
‘r’
:
//robot1跳高
if
(rb1->jflag == 0)
{
rb1->jflag = 1;
rb1->skillr();
}
break
;
-
炸弹类的设计:设计炸弹类首先要知道炸弹的坐标x,y,因为这个才可以在界面上绘出炸弹,炸弹的朝向goAhead,有了这个才可以知道炸弹的移动方向,炸弹生命live是否存活,存活才画此炸弹,
Who(谁的炸弹),因为这个炸弹类不止一个人使用,robot1和robot2都使用,zy第三参数,这个参数的作用是记录发送炸弹的机器人的中心坐标
注:在这里说明一下,因为当前游戏是使用2D制作,两个机器人在一条有长有宽的道路上打斗,如果只有长,就只要直接有炸弹的x,y和敌方机器人作边界检测就行了,可是这道路有宽,就要设计看炸弹射出的轨迹是否与敌人在一条轴线上,所以我用zy保存发出炸弹机器人的y坐标,引入了第三个参数,这时就可以把这个界面看出了三维,到时再使用敌方机器人的x,y坐标和己方炸弹的x,zy作边界检测,就可以看炸弹是否击中敌人了。
#pragma
once
#pragma
once
#include
<glut.h>
//robot1子弹类
class
myBullet
{
public
:
float
x;
float
y;
bool
live;
int
goAhead;
//子弹朝向
float
mBsize;
//子弹大小
int
who;
//谁的子弹
float
zy;
//第三参数
float
zx;
//第四参数
myBullet();
~myBullet();
void
init(
float
x
,
float
y
,
float
size
,
int
who
,
float
zx
,
float
zy
);
void
die();
};
void
drawMyBullet(
float
x
,
float
y
,
int
goAhead
,
int
size
,
int
mBsize
)
{
//绘制点
glColor3f(1, 0, 0);
//设置蓝色绘制颜色
//glPointSize(2.0);//点的像素大小,默认值为1.0
if
(
goAhead
== 0)
{
glRectf(
x
– 1 *
size
,
y
– 0.05 *
size
*
mBsize
,
x
,
y
+ 0.05 *
size
*
mBsize
);
}
else
if
(
goAhead
== 1)
{
glRectf(
x
,
y
– 0.05 *
size
*
mBsize
,
x
+ 1 *
size
,
y
+ 0.05 *
size
*
mBsize
);
}
//glBegin(GL_POINTS);
//glVertex2f(x, y);
//glVertex2f(x+1, y+0.1);
//glEnd();
}
myBullet
::myBullet()
{
x = -23;
y = 23;
live =
false
;
goAhead = -1;
mBsize = 1;
who = -1;
zx = -99;
zy = -99;
}
void
myBullet
::init(
float
x
,
float
y
,
float
size
,
int
who
,
float
zx
,
float
zy
)
{
this
->x =
x
;
this
->y =
y
;
this
->mBsize =
size
;
live =
true
;
this
->who =
who
;
this
->zx =
zx
;
this
->zy =
zy
;
}
myBullet
::~myBullet()
{
}
void
myBullet
::die()
{
live =
false
;
}
炸弹是否击中敌人的边界检测函数:
//子弹边界检测函数
void
checkBulletSide()
{
for
(
int
i = 0; i <
MAXRB1BULLET
; i++)
{
if
(mb[i].live ==
true
)
{
if
(mb[i].x > -22.0 && mb[i].x < 22.0 && mb[i].y > -12.0 && mb[i].y < 12.0)
{
if
(mb[i].who == 1)
//机器人1的子弹
{
if
(abs(mb[i].x – rb2->x) < 0.6 * rb2->size && abs(mb[i].zy – rb2->y) < 0.7 * rb2->size)
//机器人1的子弹击中机器人2
{
for
(
int
j = 0; j <
MAXBOMB
; j++)
{
if
(bomb[j].live ==
false
)
{
bomb[j].init(mb[i].x, mb[i].y, mb[i].mBsize);
rb2->valueOfLife -= 20 * mb[i].mBsize;
if
(mb[i].mBsize == 1)
{
PlaySound
(
L”midb.wav”
,
NULL
,
SND_FILENAME
|
SND_ASYNC
);
//PlaySound(L”background.wav”, NULL, SND_FILENAME | SND_ASYNC);
}
else
{
PlaySound
(
L”bigb.wav”
,
NULL
,
SND_FILENAME
|
SND_ASYNC
);
//PlaySound(L”background.wav”, NULL, SND_FILENAME | SND_ASYNC);
}
break
;
}
}
if
(mb[i].goAhead == 0)
//子弹朝向左
{
//机器人robot2被左击中
rb2->beated = -1;
}
else
if
(mb[i].goAhead == 1)
//子弹朝向右
{
//机器人robot2被右击中
rb2->beated = 1;
}
mb[i].die();
}
}
else
if
(mb[i].who == 2)
//机器人2的子弹
{
if
(abs(mb[i].x – rb1->x) < 0.6 * rb1->size && abs(mb[i].zy – rb1->y) < 0.7 * rb1->size)
//机器人2的子弹击中机器人1
{
for
(
int
j = 0; j <
MAXBOMB
; j++)
{
if
(bomb[j].live ==
false
)
{
bomb[j].init(mb[i].x, mb[i].y, mb[i].mBsize);
rb1->valueOfLife -= 20 * mb[i].mBsize;
if
(mb[i].mBsize == 1)
{
PlaySound
(
L”midb.wav”
,
NULL
,
SND_FILENAME
|
SND_ASYNC
);
//PlaySound(L”background.wav”, NULL, SND_FILENAME | SND_ASYNC);
}
else
{
PlaySound
(
L”bigb.wav”
,
NULL
,
SND_FILENAME
|
SND_ASYNC
);
//PlaySound(L”background.wav”, NULL, SND_FILENAME | SND_ASYNC);
}
break
;
}
}
if
(mb[i].goAhead == 0)
//子弹朝向左
{
//机器人robot1被左击中
rb1->beated = -1;
}
else
if
(mb[i].goAhead == 1)
//子弹朝向右
{
//机器人robot1被右击中
rb1->beated = 1;
}
mb[i].die();
}
}
}
else
//子弹已到边界
{
mb[i].live =
false
;
}
}
}
}
-
炸弹爆炸类的设计:x,y确定爆炸的位置,size确定爆炸的范围,强度,live是否存活,livelong存活的时间
#pragma
once
#include
<glut.h>
#include
<math.h>
#include
<stdlib.h>
#define
MAXPOINTSIZE
200
class
Bomb
{
public
:
float
x;
float
y;
float
size;
bool
live;
int
liveLong;
Bomb()
{
x = -99;
y = -99;
size = 1;
live =
false
;
liveLong = 40;
}
void
init(
float
x
,
float
y
,
float
size
)
{
this
->x =
x
;
this
->y =
y
;
this
->size =
size
;
live =
true
;
liveLong = 160;
}
void
setLiveLong(
int
liveLong
)
{
this
->liveLong =
liveLong
;
}
void
die()
{
live =
false
;
}