手把手教你写蛇蛇大作战(二)

这篇我们主要实现游戏的主要框架 并且绘制一条蛇 让它动起来

首先我们看看那本篇完成的最终效果图吧

snakeIo

配置工程

如果你没有配置运行工程的话,会报错。

配置destop工程

在菜单栏找到Run 选择 Edit Configurations 然后配置Working directory 配置工作区域选择 android 工程下的assets 目录 重新运行,OK!

编写代码框架

core工程下的src 目录下新建 WorldController.java(控制游戏)和WorldRenderer.java(渲染游戏)

WorldController.java 添加update 方法

1
2
3
public void update(float deltaTime) {
//用于更新 游戏对象
}

WorldRenderer.java 添加 render方法

1
2
3
public void render() {
//绘制游戏对象
}

WorldRenderer.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
26
27
public class WorldRenderer implements Disposable {

private WorldController worldController;
private SpriteBatch spriteBatch;


public WorldRenderer(WorldController worldController) {
this.worldController = worldController;
init();
}

private void init() {
spriteBatch = new SpriteBatch();
}

public void render() {
spriteBatch.begin();
//绘制对象
spriteBatch.end();
}


@Override
public void dispose() {
spriteBatch.dispose();
}
}

然后修改SnakeIo.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
public class SnakeIo extends ApplicationAdapter {
private WorldController worldController;
private WorldRenderer worldRenderer;

@Override
public void create() {
worldController = new WorldController();
worldRenderer = new WorldRenderer(worldController);
}

@Override
public void render() {
worldController.update(Gdx.graphics.getDeltaTime());//更新worldController
Gdx.gl.glClearColor(1, 1, 1, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
worldRenderer.render();//绘制
}

@Override
public void dispose() {
worldRenderer.dispose();
worldController.dispose();
}
}

这个很简单 将WorldControllerWorldRenderer 实例化
然后在render 方法里面调用更新和绘制方法

编写蛇对象

在这之前我们需要准备两张图片
eyes

body

一张是眼睛图片,一张是身体的图片 将图片copy 进destop工程
目录下的images下

我们先把图片打包
DesktopLauncher.java 添加如下代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public static void main(String[] arg) {
if (true) {
TexturePacker.Settings settings = new TexturePacker.Settings();
settings.maxHeight = 1024;
settings.maxWidth = 1024;
settings.duplicatePadding = false;
settings.debug = false;
TexturePacker.process(settings, "../../desktop/images",
"../../android/assets/images", "snake");
}
LwjglApplicationConfiguration config = new LwjglApplicationConfiguration();
config.width = 800;
config.height = 480;
config.samples = 3;
new LwjglApplication(new SnakeIo(), config);
}

运行下工程 就会在android 工程下的 assets/images 目录下生成 snake.pngsnake.atlas 把两张图打包成一张图片

我们在core工程的src 目录下新建objects
然后新建AbstractGameObject.javaSnake.java
AbstractGameObject 为 基础的抽象游戏对象
具体实现

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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
public abstract class AbstractGameObject {
public Vector2 position;
public Vector2 dimension;
public Vector2 origin;
public Vector2 scale;
public float rotation;

public Vector2 velocity;//This is the object's current speed in m/s.
//This is the object's positive and negative maximum speed in m/s.
public Vector2 terminalVelocity;
public Vector2 friction;

public Vector2 acceleration;//This is the object's constant acceleration in m/s2.
public Rectangle bounds;

public Body body;

public float stateTime;
public Animation<TextureRegion> animation;

public AbstractGameObject() {
position = new Vector2();
dimension = new Vector2(1, 1);
origin = new Vector2();
scale = new Vector2(1, 1);
rotation = 0;

velocity = new Vector2();
terminalVelocity = new Vector2();
friction = new Vector2();
acceleration = new Vector2();
bounds = new Rectangle();
}

public void update(float deltaTime) {
stateTime += deltaTime;
if (body == null) {
updateMotionX(deltaTime);
updateMotionY(deltaTime);
//move to new position
position.x += velocity.x * deltaTime;
position.y += velocity.y * deltaTime;
} else {
position.set(body.getPosition());
rotation = body.getAngle() * MathUtils.radiansToDegrees;
}
}

protected void updateMotionX(float deltaTime) {
if (velocity.x != 0) {
//Apply friction
if (velocity.x > 0) {
velocity.x = Math.max(velocity.x - friction.x * deltaTime, 0);
} else {
velocity.x = Math.min(velocity.x + friction.x * deltaTime, 0);
}
}
//Apply acceleration
velocity.x += acceleration.x * deltaTime;
// Make sure the object's velocity does not exceed the
// positive or negative terminal velocity
velocity.x = MathUtils.clamp(velocity.x, -terminalVelocity.x, terminalVelocity.x);
}

protected void updateMotionY(float deltaTime) {
if (velocity.y != 0) {
//Apply friction
if (velocity.y > 0) {
velocity.y = Math.max(velocity.y - friction.y * deltaTime, 0);
} else {
velocity.y = Math.min(velocity.y + friction.y * deltaTime, 0);
}
}
//Apply acceleration
velocity.y += acceleration.y * deltaTime;
// Make sure the object's velocity does not exceed the
// positive or negative terminal velocity
velocity.y = MathUtils.clamp(velocity.y, -terminalVelocity.y, terminalVelocity.y);
}

public void setAnimation(Animation<TextureRegion> animation) {
this.animation = animation;
stateTime = 0;
}

public abstract void render(SpriteBatch batch);
}

Snake.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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
public class Snake extends AbstractGameObject implements Disposable {
private static final String TAG = Snake.class.getSimpleName();
TextureRegion eyes;//眼睛
TextureRegion body;//身体
private AssetManager assetManager;

private int length = 100 * 80;//长度
private float speed = 8 * 10;//速度
public Array<Movement> movements;//运动path


public Snake() {
initRegion();
init();
}

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>();
velocity.set(speed, 0);
}

private void initRegion() {
assetManager = new AssetManager();
assetManager.setErrorListener(new AssetErrorListener() {
@Override
public void error(AssetDescriptor asset, Throwable throwable) {
Gdx.app.error(TAG, "Couldn't load asset '"
+ asset.fileName + "'", throwable);
}
});
assetManager.load("images/snake.atlas", TextureAtlas.class);

assetManager.finishLoading();
TextureAtlas atlas = assetManager.get("images/snake.atlas");
// enable texture filtering for pixel smoothing;
for (Texture texture : atlas.getTextures()) {
texture.setFilter(Texture.TextureFilter.Linear, Texture.TextureFilter.Linear);
}
eyes = atlas.findRegion("eyes");
body = atlas.findRegion("body");
}

@Override
public void render(SpriteBatch batch) {
float snakeLength = this.length;
for (int i = movements.size - 1; i >= 0; i--) {
Movement movement = movements.get(i);
float x = movement.position.x;
float y = movement.position.y;
if (snakeLength > 0 && snakeLength < movement.speed) {
if (i != movements.size - 1) {
Movement lm = movements.get(i + 1);
float ratio = snakeLength / movement.speed;
x = lm.position.x - (lm.position.x - x) * ratio;
y = lm.position.y - (lm.position.y - y) * ratio;
}
} else if (snakeLength < 0) {
break;
}
snakeLength -= movement.speed;
TextureRegion reg = body;
batch.setColor(Color.valueOf("#F65454"));//set snake body color
batch.draw(reg.getTexture(), x,
y, origin.x, origin.y, dimension.x,
dimension.y, scale.x, scale.y, rotation, reg.getRegionX(),
reg.getRegionY(), reg.getRegionWidth(), reg.getRegionHeight(),
false, false);
}
TextureRegion reg = eyes;
batch.setColor(Color.WHITE.toFloatBits());//reset color
batch.draw(reg.getTexture(), position.x,
position.y, origin.x, origin.y, dimension.x - 0.1f,
dimension.y - 0.1f, scale.x, scale.y, rotation, reg.getRegionX(),
reg.getRegionY(), reg.getRegionWidth(), reg.getRegionHeight(),
false, false);
}

@Override
public void update(float deltaTime) {
movements.add(new Movement(new Vector2(position), speed));
if (movements.size > length) {
movements.removeValue(movements.first(), true);
}
super.update(deltaTime);
}

@Override
public void dispose() {
assetManager.dispose();
}

public class Movement {
public Vector2 position;
public float speed;

public Movement(Vector2 position, float speed) {
this.position = position;
this.speed = speed;
}
}
}

WorldController.java 添加Snake属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class WorldController extends InputAdapter implements Disposable {

Snake snake;

public WorldController() {
snake = new Snake();
}

public void update(float deltaTime) {
snake.update(deltaTime);
}

@Override
public void dispose() {
snake.dispose();
}
}

运行工程 就可以看到结果了

代码已经放在GITHUB
可以切换到tag1 来查看本篇文章代码

使用 git checkout tag1

文章作者: zhangman523
文章链接: http://blog.zhangman523.cn/2018/09/20/snake_second/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 zhangman523
支付宝打赏
微信打赏