仿造slither.io第一步:先画条蛇 #1
Open
Comments
我做的方式也和楼主一样的思路,蛋疼的是当我开始写服务端,这样的蛇身数据在同步的时候数据量非常庞大。感觉很头疼。 |
@Gaubee 是的,我之前也尝试了一下这样写服务器,发现有问题,所以服务器层面一直没写好,最近比较忙,所以也好段时间没动了,之前研究了一下slither的客户端代码,我发现我的实现似乎跟他们是有点不同,之后会考虑换个思路来实现。 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
前言
最近 slither.io 貌似特别火,中午的时候,同事们都在玩,包括我自己也是玩的不亦乐乎。
好久好久没折腾过canvas相关的我也是觉得是时候再折腾一番啦,所以就试着仿造一下吧。楼主也没写过网络游戏,所以实现逻辑完全靠自己YY。
而且楼主心里也有点发虚,因为有些逻辑还是不知道怎么实现呀,所以不立flag,实话实说:不一定会更新下去,如果写到不会写了,就不一定写了哈~
为啥取名叫先画条蛇,毕竟是做个游戏,功能还是蛮多蛮复杂的,一口气是肯定搞不完的,所以得一步一步来,第一步就是先造条蛇!!
预览效果
当前项目最新效果:http://whxaxes.github.io/slither/ (由于代码一直在更新,效果会比本文所述的更多)
实现基类
在这个游戏里,需要一个基类,也就是地图上的所有元素都会继承这个基类:
Base
也就是地图上的元素,都会有几个基本属性:水平坐标x,垂直坐标y,宽度width,高度height,水平绘制坐标paintX,垂直绘制坐标paintY,在视窗内是否可见visible。
其中绘制坐标和视窗相关参数这一篇先不用管,这两个是涉及到地图的,会在下一篇文章再作解释。
蛇的构成
不像常见的那种以方格为运动单位的贪吃蛇,slither里的蛇动的动的更自由,先不说怎么动,先说一下蛇体的构成。
这构造很显然易见,其实就是由一个又一个的圆构成的,可以分为构成身体的圆,以及构成头部的圆。所以,实现蛇这个类的时候,可以进行拆分,拆分成蛇的基类
SnakeBase
,继承蛇基类的蛇头类SnakeHeader
,以及继承蛇基类的蛇身类SnakeBody
,还有一个蛇类Snake
用于组合蛇头和蛇身。实现蛇基类
为什么要实现一个蛇基类,因为蛇头和蛇身其实是有很多相似的地方,也会有很多相同属性,所以实现一个蛇基类会方便方法的复用的。
蛇基类我命名为
SnakeBase
,继承基类Base
:简单说明一下各个属性的意义:
x,y
基类的坐标r
为基类的半径,因为这个蛇是由圆组成的,所以r就是圆的半径color、color_2
用于着色vx,vy
为基类的水平方向的速度,以及垂直方向的速度再说明一下几个方法:
createImage
方法:用于创建基类的镜像,虽然基类只是画个圆,但是绘制操作还是不少,所以最好还是先创建镜像,之后每次绘制的时候就只需要调用一次drawImage
即可,对提升性能还是有效的update
方法:每次的动画循环都会调用的方法,根据基类的速度来更新其位置render
方法:基类的绘制自身的方法,里面就只有一个绘制镜像的操作,不过会判断一下当前这个实例有无angle属性,如果有angle则需要用canvas的rotate方法进行转向后再绘制。实现蛇头类
再接下来就是蛇头
SnakeHeader
类,蛇头类会继承蛇基类,而且,由于蛇的运动就是蛇头的运动,所以蛇头是运动的核心,而蛇身是跟着蛇头动而动。蛇头怎么动呢,我代码里写的是,蛇会朝着鼠标移动,但是蛇的运动是不会停的,所以不以鼠标位置为终点来计算蛇的运动,而是以鼠标相对于蛇头的角度来计算蛇的运动方向,然后让蛇持续的往那个方向运动即可。
所以在蛇头类里,会新增两个属性:
angle
以及toAngle
,angle是蛇头角度,toAngle是蛇头要转向的角度,请看蛇头的构造函数代码:初始角度为一个基础角度加上90度,因为画布的rotate是从x轴正向开始的,而我想把y轴正向作为0度,那么就得加上90度,而基础角度BASE_ANGLE是一个很大的数值,但是都是360度的倍数:
目的是保证蛇的运动角度一直是正数。
其次,蛇头需要眼睛,所以在蛇头的绘制镜像方法中,加入了绘制眼睛的方法:
再者就是蛇头的运动,蛇头会根据鼠标与蛇头的角度来运动,所以需要一个derectTo方法来调整蛇头角度:
如果单纯根据鼠标与蛇头的角度,来给予蛇头运动方向,会有问题,因为计算出来的目标角度都是0-360的,也就是,当我的鼠标从340度,右划挪到10度。会出现蛇头变成左转弯,因为目标度数比蛇头度数小。
所以就引入了圈数
rounds
来计算蛇真正要去到的角度。还是当我的鼠标从340度右划到10度的时候,经过计算,我会认为蛇头的目标度数就是360度 + 10度
。就能保证蛇头的转向是符合常识的。计算出目标角度,就根据目标角度来算出蛇头的水平速度vx,以及垂直速度vy:
之后再在每一次的重绘中进行转向的计算,以及移动的计算即可:
实现蛇身类
蛇头类写好了,就可以写蛇身类
SnakeBody
了,蛇身需要跟着前面一截的蛇身或者蛇头运动,所以又新增了几个属性,先看部分代码:新增了一个
tracer
跟踪者属性,也就是前一截的蛇头或者蛇身实例,蛇身和前一截实例会有一些位置差距,所以有个distance属性是用于此,还有就是计算蛇身的目标位置,也就是前一截蛇身的运动方向往后平移distance距离的点。让蛇身朝着这个方向移动,就可以有跟着动的效果了。还有tracerDis是用于计算tracer的移动长度,this.savex和this.savey是用于保存tracer的运动轨迹坐标
再来就是计算水平速度,以及垂直速度,还有每一帧的更新逻辑了:
上面代码中,update方法,会计算tracer移动距离,当超过distance的时候,就让蛇身根据此前保存的运动轨迹,计算相应的速度,然后进行移动。这样就可以实现蛇身会跟着tracer的移动轨迹行动。
组合成蛇
蛇头、蛇身都写完了,是时候把两者组合起来了,所以再创建一个蛇类
Snake
。先看构造函数,在创建实例的时候,实例化一个蛇头,再根据入参的长度,来增加蛇身的实例,并且把蛇身的tracer指向前一截蛇身或者蛇头实例。
还有就是鼠标事件绑定,包括根据鼠标位置,来调整蛇的运动方向,还有按下鼠标的时候,蛇会进行加速,松开鼠标则不加速的逻辑:
当然,最终还需要一个渲染方法,逐个渲染即可:
最后
至此,整个蛇类都写完了,再写一下动画循环逻辑即可:
这一块的代码就很简单了,生成蛇的实例,通过
requestAnimationFrame
方法进行动画循环,并且在每次循环中进行画布的重绘即可。里面有个叫timeout的参数,用于降低游戏fps,用来debug的。这个项目目前还是单机的,所以我放在了github,之后加上网络功能的话,估计就无法预览了。
github地址:https://github.com/whxaxes/slither
The text was updated successfully, but these errors were encountered: