这篇我们的主要实现控制蛇的移动和加速效果
首先我们看看实现的效果图吧
设计思路
要控制蛇的转向 首先要定义蛇当前的角度和需要转向的角度,然后计算蛇是向顺时针还是逆时针转弯。
2d 游戏要实现平滑转向移动需要使用三角函数
首先我们的坐标系,坐下角为原点坐标(0,0) 右边为x的正半轴 向上为y的正半轴 运动可以通过角度计算x和y方向的加速度 这里就要用到高中时候的三角函数了
1 2
| vx = sin(angle); vy = cos(angle);
|
我们来看下三角函数的正弦和余弦波
有没有很熟悉。
要实现蛇的转向问题,我们需要了解如何从A角度到B角度的最快转向,逆时针还是顺时针。
顺时针从角度A到角度B
逆时针从角度A到角度B
顺时针: 旋转角度为A-B(A>B时,如从180到90度 需要顺时针旋转90度)或者360+A-B(A<B时,如30度到270度 需要顺时针旋转120度)
逆时针:旋转角度为B-A(B>A时,如从50度到80度为 逆时针旋转30度)或者360+B-A(B<A时,如从315度到90度时逆时针旋转135度)
所以不论如何,角度A到角度B 顺时针旋转角度为C或者逆时针旋转角度为D ,都有C+D=360度。
所以我们计算|A-B|,如果当|A-B|<180时可以分为两种情况
- A<B 时,逆时针旋转B-A度
- A>B 时,顺时针旋转A-B度
如果|A-B|>180度,我们也可以分为两种情况
- A<B 时,顺时针旋转360+A-B
- A>B 时, 逆是在旋转360+B-A
如果是|A-B|=180度 那么逆时针和顺时针都一样,都是180度
代码实现
首先我们需要修改Snake.java
添加以下三个属性
1 2 3
| private double angle; private double toAngle; private double turnSpeed = Math.toRadians(2);
|
然后修改init()
方法
1 2 3 4 5 6 7 8 9 10 11 12
| private void init() { dimension.set(20, 20); origin.set(dimension.x / 2, dimension.y / 2); terminalVelocity.set(100, 100); position.set(50, 120); rotation = -90; scale.set(0.7f, 0.7f); bounds.set(0, 0, dimension.x, dimension.y); movements = new Array<Movement>(); angle = 0; toAngle = angle; }
|
然后修改update()
方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| @Override public void update(float deltaTime) { movements.add(new Movement(new Vector2(position), speed)); if (movements.size > length) { movements.removeValue(movements.first(), true); } angle = (Math.PI * 2 + angle) % (Math.PI * 2); if (Math.abs(angle - toAngle) <= turnSpeed) { toAngle = angle = toAngle % (Math.PI * 2); } else { if (Math.abs(angle - toAngle) < Math.PI) { if (angle < toAngle) { angle += turnSpeed; } else { angle -= turnSpeed; } } else { if (angle < toAngle) { angle -= turnSpeed; } else { angle += turnSpeed; } }
} angle = angle % (Math.PI * 2); float vx = (float) (speed * Math.cos(angle)); float vy = (float) (speed * Math.sin(angle)); velocity.set(vx, vy); rotation = (float) (360 + Math.atan2(velocity.y, velocity.x)/ (Math.PI / 180 - 90); super.update(deltaTime); }
|
然后需要控制方向 添加方法
1 2 3
| public void setDirection(double angle) { toAngle = angle; }
|
Snake.java
基本已经完成了
然后我们修改WorldController.java
添加方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| private void handleInput(float deltaTime) { if (Gdx.app.getType() != Application.ApplicationType.Desktop) return; int[][] angleArray = new int[][]{ {-1, 270, 90}, {180, 225, 135}, {0, 315, 45} }; int i = 0, j = 0; if (Gdx.input.isKeyPressed(Input.Keys.LEFT)) { i = 1; } else if (Gdx.input.isKeyPressed(Input.Keys.RIGHT)) { i = 2; }
if (Gdx.input.isKeyPressed(Input.Keys.UP)) { j = 2; } else if (Gdx.input.isKeyPressed(Input.Keys.DOWN)) { j = 1; } double angle = angleArray[i][j]; if (angle == -1) { return; } snake.setDirection(Math.toRadians(angle)); }
|
然后我们修改WorldController中的update()
方法
1 2 3 4
| public void update(float deltaTime) { handleInput(deltaTime); snake.update(deltaTime); }
|
##实现加速
在Snake.java
添加两个属性
1 2
| private boolean isSpeedUp; private float oldSpeed;
|
然后添加加速方法和减速方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
public void speedUp() { if (isSpeedUp) return; isSpeedUp = true; oldSpeed = speed; speed *= 2; }
public void speedDown() { if (!isSpeedUp) return; isSpeedUp = false; this.speed = oldSpeed; }
|
然后修改WorldController.java
添加空格键监听 点击空格键加速,放开减速
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| @Override public boolean keyDown(int keycode) { switch (keycode) { case Input.Keys.SPACE: snake.speedUp(); break; } return true; }
@Override public boolean keyUp(int keycode) { switch (keycode) { case Input.Keys.SPACE: snake.speedDown(); break; } return true; }
|
然后就可以运行查看效果了。
代码已经放在GITHUB
可以切换到tag2
来查看本篇文章代码
使用 git checkout tag2