已实现内容:根据贝塞尔曲线绘制出抛物线
问题:贝塞尔曲线创建的时候是完整的曲线,无法画出虚线绘制部分线段。而且速度向下时不符合客观事实。
需求:绘制出符合地球物理的抛物线,虚线
早期的代码,用过百度百科的斜抛公式,和二次函数交点式解法求函数,但是效果都不理想。后来发现自己对于游戏的理解太过浅薄,在程序员创造的游戏世界中,用上帝世界的公式显然是不太合理的。程序员的世界是离散的,上帝的世界是连续的。
要真正地理解这个游戏,首先看update中的代码,每帧判断人物位置,每帧人物的坐标+=速度。
1 if(this._isMoveing && !this._isStandFloor){ 2 this.speed.y += this.gravity; 3 this.player.y += this.speed.y; 4 this.player.x += this.speed.x; 5 }
将斜抛运动分解为水平方向的匀速直线运动和垂直方向的上抛运动。
因为斜抛运动,物体的运动时间也就是物体在空中停留的时间。先求出抛到最高点的时间也就是当y方向的速度等于0的时候的时间,因为Vy每帧减少gravity,可得Vy等于0的时间为Vy/gravity。再由上抛运动的对称性可知斜抛的运动时间为2*Vy/gravity,下面代码:
1 var fallTime = Math.abs((2*this.speed.y)/this.gravity);
知道运动时间就能求落地点了,因为水平方向上可以理解为匀速直线运动,简单的s=vt。落地点代码:
1 var dropPointX = this.speed.x * fallTime;
经过验证,这是可以准确画出落地点的,但是写的当时因为对游戏和世界的理解不完全,在这里卡了很久,在百度上找到斜抛公式直接代入,发现效果非常不理想。
前段时间实在想不出好的结局办法,用了贝塞尔曲线简单粗暴地勉强解决了,但这是不合理的,如果人物速度向下的时候,辅助线会呈现开口向上的抛物线,不符合客观事实,用二次函数来解决这个问题同理。下面代码:
1 var fallTime = Math.abs((2*this.speed.y)/this.gravity);//每帧vy减少g,vy/g则是y=0的时间 2 var dropPointX = this.speed.x * fallTime;//落地点 3 var heightPointY = this.speed.y * 0.5*fallTime;//最高点(其实这里算错了,实际效果看不出来) 4 //贝塞尔曲线 5 drawLine.moveTo(0,0); 6 drawLine.quadraticCurveTo(0.5*dropPointX, heightPointY, dropPointX, 0); 7 drawLine.stroke();
用完整的斜抛公式是十分不明智的选择。涉及到各种三角函数合速度的计算,难以阅读和理解。
因为在这个世界中我们已经有了水平分速度和垂直分速度还有加速度,完全能用这些条件计算出某个时刻某一点的坐标。还是要用到分解运动的思想,把斜抛分解成一个水平方向的匀速直线运动和垂直方向的上抛运动,水平方向坐标与时间的关系为s = vx * t,垂直方向坐标与时间的关系为s = vy * t + 0.5 * g * t^2,用for循环遍历这段时间,然后每隔一段距离连接两点,就能绘制出这条抛物线的。
1 //物理斜抛 2 //x坐标 s = vx * t, y坐标 s = vy * t + 0.5 * g * t^2 3 for(var time=0; time<fallTime; time+=2){ 4 var parabolaXMove = time*this.speed.x; 5 var parabolaYMove = time*this.speed.y + 0.5*this.gravity*time*time; 6 7 var parabolaXLine = (time+1)*this.speed.x; 8 var parabolaYLine = (time+1)*this.speed.y + 0.5*this.gravity*(time+1)*(time+1); 9 10 drawLine.moveTo(parabolaXMove, parabolaYMove); 11 drawLine.lineTo(parabolaXLine, parabolaYLine); 12 }
最后实现效果: