基于opengl的2d机器人双人格斗游戏

  1. 2D 项目简介

项目的创意设想、实现功能、项目意义(200字左右)

  作品代表图

 

项目名:机器人双人格斗游戏

 

项目的创意设想:当前ai大火,机器人也是日常生活中的一个热点,自己在小学乃至高中也经常玩格斗游戏。曾经也想过格斗游戏是怎么做的,可是那时候条件有限,而且也没有编程基础。这个想法就一直留到了大学。到大三学习计算机图形学,也有了一定的编程基础,认为这个格斗游戏可以自己完成了。便开始动手,经过几天的努力,终于把这个游戏实现了。

 

实现功能:画了机器人1(乌巢之子),机器人2(关山之月)实现其的技能有:

  1. 上下左右移动:实现了平移
  2. 弹跳:使用了重力加速度实现了起跳落下的算法,
  3. 眼睛发射镭射光线:实现了平移
  4. 肚载大炮发射:实现了平移
  5. 手臂可以伸长:实现了平移
  6. 被炮弹击中会倒退:使用了旋转变换之类函数,实现了旋转
  7. 法天相地(放大):实现了放大 - 经过一段时间也会缩放到原来的大小

 

  1. 计时功能:使用了时间回调函数
  2. 使用了win32API函数,可以插入声音

 

项目意义:自己在开始做这个游戏的时候,也上网百度看是否有类似的格斗游戏,这类型指的是使用opengl库制作的2D无游戏引擎的双人格斗游戏,发现找不到类似的游戏,可以说是网上几乎没人做过类似的2D无游戏引擎的双人格斗游戏。可以说这个游戏填补了当类游戏的空白,也可以给后来者加以参考。

 

作品代表图:

  1. 编程环境(电脑硬件、操作系统和VS平台)说明
  2.  

    电脑硬件:thinkpad x250,

    cpu:i3

    内存:4g

    操作系统:win10

    Vs:vs2017

            

  3. 程序操作说明
  4. 操作如下图:

    编程环境(电脑硬件、操作系统和VS平台)说明

 

电脑硬件:thinkpad x250,

cpu:i3

内存:4g

操作系统:win10

Vs:vs2017

        

  1. 程序操作说明

操作如下图:

按键b:开始游戏

对角色1(乌巢之子)进行操作有:

1、wsad:上下左右移动

2、z:长拳攻击

3、x:从眼部发射镭射光线

4、c:肚载大炮,肚子发射大炮,攻击力强于镭射光线

5、e:法天相地,变大

6、r:弹跳

 

对角色2(关山之月)进行操作有:

  1. ikjl:上下左右移动
  2. n:长拳攻击
  3. m:镭射光线
  4. O:肚载大炮,肚子发射大炮,攻击力强于镭射光线
  5. U:法天相地(变大)
  6. P:弹跳

 

当两者的某一方血条为0时,游戏结束,效果如下:

 

 

  1. 程序实现
  1. 创意详细说明:
    1. 算法类、模拟类: 算法说明,想要实现的效果说明

 

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;

 

  1. 炸弹类的设计:设计炸弹类首先要知道炸弹的坐标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;

}

}

}

}

 

  1. 炸弹爆炸类的设计: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;

}

  • 3
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
作者对游戏的说明: 首先,您应当以一种批判的眼光来看待本程序。这个游戏是我制作 的第一部RPG游戏,无任何经验可谈,完全按照自己对游戏的理解进 行设计的。当我参照了《圣剑英雄2》的源码之后,才体会到专业游 戏引擎的博大精深。 该程序的内核大约有2000余行,能够处理人物的行走、对话、战斗, 等等。由于该程序的结构并不适于这种规模的程序,故不推荐您详 细研究该程序。所附地图编辑器的源程序我已经添加了详细的注释, 其程序结构也比较合理,可以作为初学VC的例子。 该程序在VC的程序向导所生成的SDI框架的基础上修改而成。它没有 使用任何关于VC底层的东西。程序的绝大部分都是在CgameView类中 制作的,只有修改窗口特征的一段代码在CMainFrm类中。其他的类 统统没有用到。另外添加的一个类是CEnemy类。 整个游戏的故事情节分成8段,分别由Para1.h ~ Para8.h八个文件 实现。由于程序仅仅能够被动的处理各种各样的消息,所以情节的 实现也只能根据系统的一些参数来判断当前应当做什么。在程序中 使用了冗长的if……else if……结构来实现这种判断。 当然,在我的记录本上,详细的记录了每个事件的判断条件。这种 笨拙的设计当然是不可取的。成都金点所作《圣剑英雄II》采用了 剧本解读的方式,这才是正统的做法。但这也需要更多的编程经验 和熟练的code功夫。 下面列举的是程序编制过程中总结出来的经验和教训。 第一,对话方式应该采用《圣剑英雄II》的剧本方式。 现在的方式把一个段落中所有的对话都混在一个文件中,然后给每 句话一个号码相对应。这样做虽然降低了引擎的难度,却导致剧情的 编写极其繁琐。 第二,运动和显示应当完全分开。 现在的程序中,运动和显示是完全同步的。即:在定时器中调用所有 敌人的运动函数,然后将主角的动画向前推一帧,接着绘制地图,调 用所有敌人的显示函数、重绘主角。这样的好处是不会掉帧,但带来 的问题是,如果要提高敌人的运动速度,那么帧数也跟着上去了。所 以当DEMO版反馈说速度太慢的时候,我修改起来非常困难。而这个问 题到最后也仅仅是将4步一格该成了2步一格。 第三,VC中数组存在上限。如果用“int aaa[1000000000]”定义一个 数组,编译器肯定不会给分配那么大的内存空间。而在这个程序中, 地图矩阵、NPC矩阵都超过了VC中数组的上限。但这一点知道的太晚了。 在1.0版本中已经发现地图最右端缺少了几行,但不知道是什么原因 造成的。(地图编辑器中未出现此问题,因为地图编辑器是用“序列 化”的方式存盘读盘的。)解决这个问题的方法是用“new”来分配 内存空间。 第四,由于不知道应该如何使用“new”和“delete”,几乎所有的DC 都使用了全局变量。这是完全没有必要的。程序运行期大约会耗用20 多M的内存空间,相当于一个大型游戏所使用的内存空间了。 另外,在游戏的剧情、美工方面也有许多问题,总之一个词“业余”。 我就不总结了。下一部作品,我将争取在程序上有一个质的飞跃。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值