历时一个星期,Web应用课的中期项目----拳皇,终于按照y总的课程写出了简单的初级版本,后续等放假还会进行一定程度的补充和完善。对目前的开发的心得与收获做一个总结
当前实现的情况如下:
初始状态:
双方平局情况:
一方ko一方的情况
下面是分割线:
基础的游戏开发知识如下:
前传:
初始化人物角色
用方块做遮罩,并在遮罩上设定人物的运动、攻击、死亡的各种状态
1.游戏的物体移动
1).核心:requestAnimationFrame
指路MDN:ttps://developer.mozilla.org/zh-CN/docs/Web/API/Window/requestAnimationFrame
通过使用requestAnimationFrame对人物进行动画的重绘,人眼是一秒眨一下的,因此画60次,就能组成一组运动
2).多种运动方式:前后左右跳与下降
对于沿x轴运动的情况,设置一个人物对象长x,高:h,沿x轴方向运动速度:vx,沿y轴方向运动速度:vy,
对于沿不同方向运动的公式如下:x方向:x=x0+vxt
y方向:y=y-1/2g*t^2
对于整个移动过程,逐步更新,并且不断更新渲染刷新人物角色动作
整个开发项目过程的逻辑点
2.整个项目框架
面向对象:
css用来设置样式,主要是负责整个游戏的背景,血条的变化情况以及计时器
js中:ac_game_object用来对整个对象编写动画渲染情况
controller用来通过使用canvas,读取整个键盘的输入情况,来执行动作
game_map:整个地图操作,用来控制整个地图层以及在地图层中的血条
player:
base.js用作模拟编写整个人物的运动、击打、死亡的各种速度、运动方位、状态、帧率控制等情况
kyo.js用作初始化该人物以及各张人物照片的帧率初始情况
gif.js是从stackoverflow中给引入的,用作渲染gif图片的每一帧
base.js用来初始化对战双方的高度位置长度等数据的
3.具体对象运动逻辑编写
在游戏中,位置、速度、方向是三个独立的变量,不同的动画需要手动做出区分
1)如何控制速度
整个人物的连贯动作其实是由许多张gif图片所组成的,要控制整个动画的速度,就需要对gif图片的每一帧去做渲染
查找:stackoverflow即可
2).实现攻击效果
this.obj.frame_rate*(obj.frame_cnt-1)
以实现播放完攻击的gif时,立即停止,恢复到上一帧的静止状态
否则会出现人物动作会闪一帧,原因在于当frame_current_cnt==obj.frame_cnt时,会多播一次,而本质上让其播完最后一帧停下来就不会闪
3).让人物对象照片相对,而不是相向------实现翻转
把宽度改为负坐标,整个坐标相对于y轴对称过去
this.ctx.scale(-1,1);
this.ctx.translate(-this.root.game_map.$canvas.width(),0);
let k=parseInt(this.frame_current_cnt/obj.frame_rate)%obj.frame_cnt;
let image=obj.gif.frames[k].image;
this.ctx.drawImage(image,this.root.game_map.$canvas.width()-this.x-this.width,this.y+obj.offset_y,image.width*obj.scale,image.height*obj.scale);
同时要注意在坐标改变后,两个人物的相对方位也发生改变
update_direction(){
//对于死去的玩家做特判不调整方向
if(this.status===6){
return;
}
let players=this.root.players;
if(players[0]&&players[1])
{
let me=this,you=players[1-this.id];
if(me.x<you.x)me.direction=1;
else
me.direction=-1;
}
}
4.如何判断人物攻击
通过一个简单的2d方块,标注处人物挥拳时,拳头会能够触及到的方位与范围,当与对方的人物方块产生交集,则说明攻击到对方
转换为算法题:判断两个矩阵是否有交集
有交集的情况:如果x方向、y方向有交集,那么两个区间就有交集,否则没有交集,因此转换成了一维问题
也就是说min(d,b)>max(a,c)
```
is_collision(r1,r2){
//水平
if(Math.max(r1.x1, r2.x1)>Math.min(r1.x2, r2.x2))
return false;
//竖直方向
if(Math.max(r1.y1, r2.y1)>Math.min(r1.y2, r2.y2))
return false;
else
return true;
}
```
如果为true,则将其调整为被打状态,同数动画帧率为0保持静止
5.细节特判
1).倒地不起而不是倒地后站起来:
让倒地后,动画停止,帧率前后抵消,以实现保持静止
2).活着的角色前后移动时,死了的角色不应该也调用方向:
在status==6时不做方位移动的调整即可
3).人死了之后,还会”鞭尸”
同样的方法,不做return调整即可
6.bug
1).空中被攻击到,掉落速度会变慢
解决:给全部的操作都施加重力,只对跳跃操作施加会出现重力为0的特判
2).不允许两个角色重叠
解决:当出现重叠时,撤销当前操作即可
3).如果出现推人效果:
解决:自己不动让对方动即可
let[a,b]=this.root.players;
if(a!==this)[a,b]=[b,a];//发生碰撞自己不动让对方动,交换对象即可
let r1={
x1:a.x,
y1:a.y,
x2:a.x+a.width,
y2:a.y+a.height,
};
let r2={
x1:b.x,
y1:b.y,
x2:b.x+b.width,
y2:b.y+b.height,
};
//两个角色重叠取消当前操作
if(this.is_collision(r1,r2)){
this.x-=this.vx*this.timedelta/1000/2;
this.y-=this.vy*this.timedelta/1000/2;
//推人效果
b.x+=this.vx*this.timedelta/1000/2;
b.y+=this.vy*this.timedelta/1000/2;
if(this.status===3)this.status=0;
}
if(this.y>450){
this.y=450;
this.vy=0;
if(this.status===3)this.status=0;
7.实现血条与计时器功能
该部分主要还是依靠css来实现
但有几个点需要注意:
1).calc里面必须让数字和符号之间空格才能让值有效
2).默认的div是盒子模型,盒子模型会加上边框的宽度,将box-sizing改成border-box即可
3).血槽按照百分比缩小
让按照父元素宽度比例对血量百分比减小
this.$hp.width(this.$hp.parent().width()*this.hp/60)
要让血条有渐变效果可以用jquert的animate来控制速度
4).让血条有红色残影
再搞一个div,让内部div变成血条颜色,外部为拖影色,同时修改血条的索引情况。这样就会形成内层血条在减少时(主),外层拖影血条不断露出(跟随),让V主>v拖就会有效果
5).时间设定
这个要写在主要的地图层,game_map中,定义time-left-=timedelta,timedelta是帧率时间,由于是以毫秒级计时,因此要记得转换为秒
6).计时结束全部死亡:
在time-left<=0时,将status设定为6,同时帧率设定为0,双方速度为0,这样设定为死亡
在整个开发过程中遇到的问题
1.参数、变量等等,这些的大小写问题,由于一个项目会引入其他的js文件,一个大小写混乱都会导致出错
2.细节问题,为了保证整个项目的运行不粗糙,有些细节需要修正
3.js、css的预防还是不熟,需要常写常查
后续完善
1.增加其他人物,增加开始游戏、退出游戏、结束游戏等界面入口,让整个项目丰满起来,不单一
2.等后端框架学完之后,尝试接入后端