学习笔记14-网络版坦克大战
作业素材
官方Tank Tutourial的素材
实现效果
代码仓库
Gif
演示视频
实现中遇到的问题
本周我的项目中有较多对上一次作业成果的复用,而且坦克大战本质上我们课上的打子弹的Demo的代码逻辑其实也十分相像,都是含有玩家状态同步、联网的子弹发射的内容,所以我这次作业的分享不打算怎么去讲述我的代码,完整的项目也可以在我的Github仓库看到。从分享的角度来说,个人感觉把我开发时遇到的一些问题以及我自己得到我对于其解决方案的过程分享出来更加具有意义。
-
在根据课程网站上的UNet使用的相关知识,给我的坦克大战加上网络对战的功能后,首先我想到要解决的就是在课堂实现中就发现的一个子弹会打到自己的问题
首先,我想到了以下几种解决的方法
- 增加子弹发出时距离玩家的距离,然后减少子弹判断的范围,使得玩家碰不到自己的子弹
- 使用Tag来判断?
- 给子弹增添一个发出者的变量用于判断碰撞。
下面我们分别说说以上的解决办法:
-
增加子弹发出时距离玩家的距离,使得玩家碰不到自己的子弹
这个解决方法是有效果的,但是在网络状况不好时,Client端经常还是会出现自己与子弹碰撞的情况,所以,总的来说,这种方法治标不治本,不是一种好的方法。
-
使用Tag来判断?
一开始傻傻的想着能不能通过OnStartLocalPlayer修改自己的Tag然后在判断时判断tag呢。但是后来一想OnStartLocalPlayer只在本地起作用啊,这样肯定不对的。。而且想了一想觉得使用tag不太现实,所以这方法就被我否决了。
-
给子弹增添一个发出者的变量用于判断碰撞。
这种方法是几种方法里面最现实的,肯定可以实现,而且是一种治本的方法,所以在上面几种方法中,我使用的是第三种方法。 首先,我给子弹加了一个fromID用于记录把它射出的Player的instanceID,在创建子弹时给子弹的Bullet Component附上对应的值,但是后面发现没有达到期望的效果,结果发现,客户端的子弹的fromID并没有改变,其需要变成SyncVar才会在客户端同步,运行,发现结果OK,子弹不会被自己碰到而爆炸,嗯,很好。这样就完成了子弹会打到自己的问题的消除了,这是我对这个问题解决方案的思考,不过感觉这样写还是有点不优雅,不知道有没有更加优雅、更好的解决方案,有的话可以通过github仓库的ISSUE我们探讨一下🙃。
-
爆炸只产生在Server
解决了上面子弹的问题后,美滋滋。。!!!🌚怎么客户端的爆炸没了。。Debug了一下发现子弹在服务端先碰撞先Destroy,所以客户端的子弹被Destroy,无碰撞产生,经过思考我把爆炸效果以及子弹Destroy弄成了一个ClientRpc函数,恰好这样也可以与本地的粒子工厂结合在一起,测试发现效果和预期相符。
ClientRpc的作用恰巧与Command相反,其是服务器执行的代码,调用所有客户端执行函数,而Command则是本地玩家对象执行的代码,调用服务器执行的函数
if (flag == true && this.gameObject.activeSelf) { if (isServer) RpcBulletExplosion (); } ... [ClientRpc] void RpcBulletExplosion() { ParticleSystem explosion = Singleton<PSFactory>.Instance.getPs (); explosion.transform.position = transform.position; //设置粒子系统位置 explosion.Play(); Destroy(this.gameObject); }
3.子弹移动相关
因为在上一个版本中,我的子弹移动是通过施加一个向前的力来实现的,但是这样就会造成在发出后还会持续改变物体的速度,不利于我们联网射击,因为这里涉及到一个发送速率Network Send Rate的问题,如果我们在子弹发出后不去改变其方向或速度,我们的发送速率可以设置为0,不需要发送移动更新,这是比较合理的,我们应该以附加速度的方式去使子弹完成移动,这样就可以把发送速率设置为0。如果使用我们一开始的附加力的方式的话,我们就要把该速率调高,增加了无必要的网络负载。
以上就是我这次实验碰到的比较关键的问题以及思考,因为对于UNet的了解不是很深入,而且临近期末,时间不太充裕无法深入去了解,感觉有的地方还是做的不是很到位,游戏的功能也不是太多,等到考完试了有时间的话会更深入了解一下,增加一些功能。完整的代码在最上面已经给出,有兴趣的可以看下。