android游戏开发框架libgdx的使用(十四)—TiledMap中视角完善和障碍物处理

转自:http://www.apkbus.com/forum.php?mod=viewthread&tid=19773&extra=page%3D1%26filter%3Dauthor%26orderby%3Ddateline%26orderby%3Ddateline

 

本文紧跟上文:http://www.apkbus.com/android-19771-1-1.html


 

上文说到绘制了Map,然后我们的主角也可以四处活动了,但是仍有一些不完善的地方。

1.地图的边界没有控制。Camera的位置其实是viewport的位置,不是屏幕边界,所以如果直接按照上文的做法做的话主角走到屏幕边缘的时候就有问题了。


1.png

 

2012-1-18 00:01 上传
下载附件(9.1 KB)


 

2.没有障碍,主角的行动没有约束。

现在先来解决第一个问题。

解决方案很简单,我们时刻注意viewport的位置,根据viewport计算Screen的边界,让其不超过地图。

代码如下:


 

  1. private void CameraMove(Vector3 vector3, Actor mainActor) {
  2. Vector3 viewport = stage.getCamera().position.cpy();
  3. viewport = viewport.add(vector3);
  4. Vector3 zbound = new Vector3(width / 2, height / 2, 0).add(viewport);
  5. if (zbound.x > maxCamPosition.x || zbound.y > maxCamPosition.y) {
  6. return;
  7. }
  8. Vector3 fbound = new Vector3(-width / 2, -height / 2, 0).add(viewport);
  9. if (fbound.x < 0 || fbound.y < 0) {
  10. return;
  11. }
  12. stage.getCamera().position.add(vector3);
  13. for (Actor actor : stage.getActors()) {
  14. actor.x += vector3.x;
  15. actor.y += vector3.y;
  16. }
  17. }
复制代码

运行一下,恩,感觉还行。但是又有一个问题出现了…当地图达到边界时地图不能滚动了,但是主角应该还是可以前进的。
2.jpg

2012-1-18 00:01 上传
下载附件(86.41 KB)



处理方法我采用的是将Camera和主角分开处理,还是判断一下,主角如果移动后不超出屏幕,就继续移动。

  1. Vector3 viewport = stage.getCamera().position.cpy();
  2. viewport = viewport.add(vector3);
  3. Vector3 zbound = new Vector3(width / 2, height / 2, 0).add(viewport);
  4. if (zbound.x > maxCamPosition.x || zbound.y > maxCamPosition.y) {
  5. isCameraMove = false;
  6. }
  7. Vector3 fbound = new Vector3(-width / 2, -height / 2, 0).add(viewport);
  8. if (fbound.x < 0 || fbound.y < 0) {
  9. isCameraMove = false;
  10. }

  11. Vector3 v3 = new Vector3(mainActor.x, mainActor.y, 0);
  12. stage.getCamera().project(v3);
  13. Vector3 a = v3.cpy().add(vector3);
  14. if (a.x > width || a.y > height) {
  15. isActorMove = false;
  16. }
  17. if (a.x < 0 || a.y < 0) {
  18. isActorMove = false;
  19. }

  20. if (isCameraMove) {
  21. stage.getCamera().position.add(vector3);
  22. for (Actor actor : stage.getActors()) {
  23. if (!actor.equals(player)) {
  24. actor.x += vector3.x;
  25. actor.y += vector3.y;
  26. }
  27. }
  28. }
  29. if (isActorMove) {
  30. player.x += vector3.x;
  31. player.y += vector3.y;
  32. }
复制代码

3.jpg

2012-1-18 00:02 上传
下载附件(85.04 KB)



第一个问题基本解决,为什么说是基本解决?因为主角和Camera的位置可能会变动。造成主角在屏幕一角行走的问题。我一般是判断主角位置,当位于中心区域时在让二者联动。现在来解决第二个问题,障碍物的问题。重新编辑我们的TMX文件。添加一个新图块:
4.png

2012-1-18 00:01 上传
下载附件(1.9 KB)



大小还是32*32.
5.jpg

2012-1-18 00:01 上传
下载附件(44.1 KB)



然后新建一个图层,将地图中不能穿越的部分用红色的方块填充。
6.png

2012-1-18 00:01 上传
下载附件(236.55 KB)




编辑红色块的属性,添加一个Pass-False键值(这个值是随意的,只要你能懂就行)
7.jpg

2012-1-18 00:01 上传
下载附件(22.98 KB)



最后隐藏该图层,保存文件。(我在Editor里面确实隐藏了这个层,但是libgdx还是绘制了,只有自己处理一下了)

  1. map = TiledLoader.createMap(mapHandle);

  2. for (int i = 0; i < map.layers.size(); i++) {
  3. if ("NoPass".equals(map.layers.get(i).name)) {
  4. nopassLayer = map.layers.get(i);
  5. map.layers.remove(i);
  6. break;
  7. }
  8. }
复制代码

map实例化以后,先寻找我们的障碍层,将其从map中移除。为了方便调试,暂时没有移除它。在主角每次移动时我们就检查主角移动后的位置是在哪块里面,这块是不是不能通过的,如果不能就不移动,否则就移动。先遍历所有tiles,看一下pass=false的是多少ID的那块。

  1. int nopassId = 0;
  2. TileSet set = map.tileSets.get(map.tileSets.size() - 1);
  3. int masSize = set.firstgid + layer.tiles.length;
  4. for (int i = 0; i < masSize; i++) {
  5. if ("False".equals(map.getTileProperty(i, "Pass"))) {
  6. nopassId = i;
  7. Gdx.app.log("Find!", i + " ");
  8. break;
  9. }
  10. }
复制代码

然后推算移动后会处于哪块中,哪一块是不是不能通过的。

  1. int xid = MathUtils.ceilPositive(pos.x / map.tileWidth);
  2. int yid = MathUtils.ceilPositive(pos.y / map.tileWidth);
  3. if (layer.tiles[layer.tiles.length - yid][xid - 1] == nopassId) {
  4. return true;
  5. } else {
  6. return false;
  7. }
复制代码

在移动时先判断一下,如果会达到不能到达的块就直接退出。

  1. Vector2 pos = new Vector2(mainActor.x, mainActor.y);
  2. if (CheckMoveable(map, nopassLayer, vector3, pos)) {
  3. return;
  4. }
复制代码

完整代码:

  1. package com.cnblogs.htynkn.game;

  2. import javax.swing.text.ZoneView;
  3. import javax.swing.text.html.MinimalHTMLWriter;

  4. import com.badlogic.gdx.ApplicationListener;
  5. import com.badlogic.gdx.Gdx;
  6. import com.badlogic.gdx.InputMultiplexer;
  7. import com.badlogic.gdx.InputProcessor;
  8. import com.badlogic.gdx.files.FileHandle;
  9. import com.badlogic.gdx.graphics.Color;
  10. import com.badlogic.gdx.graphics.GL10;
  11. import com.badlogic.gdx.graphics.OrthographicCamera;
  12. import com.badlogic.gdx.graphics.Texture;
  13. import com.badlogic.gdx.graphics.g2d.BitmapFont;
  14. import com.badlogic.gdx.graphics.g2d.SpriteBatch;
  15. import com.badlogic.gdx.graphics.g2d.TextureRegion;
  16. import com.badlogic.gdx.graphics.g2d.tiled.TileAtlas;
  17. import com.badlogic.gdx.graphics.g2d.tiled.TileMapRenderer;
  18. import com.badlogic.gdx.graphics.g2d.tiled.TileSet;
  19. import com.badlogic.gdx.graphics.g2d.tiled.TiledLayer;
  20. import com.badlogic.gdx.graphics.g2d.tiled.TiledLoader;
  21. import com.badlogic.gdx.graphics.g2d.tiled.TiledMap;
  22. import com.badlogic.gdx.graphics.g2d.tiled.TiledObject;
  23. import com.badlogic.gdx.graphics.g2d.tiled.TiledObjectGroup;
  24. import com.badlogic.gdx.graphics.glutils.ShaderProgram;
  25. import com.badlogic.gdx.math.MathUtils;
  26. import com.badlogic.gdx.math.Vector2;
  27. import com.badlogic.gdx.math.Vector3;
  28. import com.badlogic.gdx.scenes.scene2d.Actor;
  29. import com.badlogic.gdx.scenes.scene2d.Stage;
  30. import com.badlogic.gdx.scenes.scene2d.ui.Image;
  31. import com.badlogic.gdx.scenes.scene2d.ui.Label;
  32. import com.badlogic.gdx.scenes.scene2d.ui.Label.LabelStyle;

  33. public class JavaGame implements ApplicationListener, InputProcessor {

  34. Stage stage;
  35. float width;
  36. float height;
  37. private TiledMap map;
  38. private TileAtlas atlas;
  39. private TileMapRenderer tileMapRenderer;
  40. Image player;
  41. Vector3 camDirection = new Vector3(1, 1, 0);
  42. Vector2 maxCamPosition = new Vector2(0, 0);
  43. Vector3 moveVector = new Vector3(0, 0, 0);
  44. boolean isPress;
  45. TiledLayer nopassLayer;

  46. // Image image;

  47. @Override
  48. public void create() {
  49. final String path = "map/";
  50. final String mapname = "tilemap";
  51. FileHandle mapHandle = Gdx.files.internal(path + mapname + ".tmx");
  52. map = TiledLoader.createMap(mapHandle);

  53. for (int i = 0; i < map.layers.size(); i++) {
  54. if ("NoPass".equals(map.layers.get(i).name)) {
  55. nopassLayer = map.layers.get(i);
  56. // map.layers.remove(i);
  57. break;
  58. }
  59. }

  60. atlas = new TileAtlas(map, new FileHandle("map/"));
  61. tileMapRenderer = new TileMapRenderer(map, atlas, 10, 10);
  62. maxCamPosition.set(tileMapRenderer.getMapWidthUnits(), tileMapRenderer
  63. .getMapHeightUnits());

  64. width = Gdx.graphics.getWidth();
  65. height = Gdx.graphics.getHeight();
  66. stage = new Stage(width, height, true);
  67. Label label = new Label("FPS:", new LabelStyle(new BitmapFont(Gdx.files
  68. .internal("font/blue.fnt"),
  69. Gdx.files.internal("font/blue.png"), false), Color.WHITE),
  70. "fpsLabel");
  71. label.y = height - label.getPrefHeight();
  72. label.x = 0;
  73. stage.addActor(label);

  74. for (TiledObjectGroup group : map.objectGroups) {
  75. for (TiledObject object : group.objects) {
  76. if ("play1".equals(object.name)) {
  77. player = new Image(new TextureRegion(new Texture(Gdx.files
  78. .internal("map/player.png")), 0, 0, 27, 40));
  79. player.x = object.x;
  80. player.y = tileMapRenderer.getMapHeightUnits() - object.y; // map是左上角,Stage是左下角
  81. stage.addActor(player);
  82. }
  83. }
  84. }

  85. InputMultiplexer inputMultiplexer = new InputMultiplexer();
  86. inputMultiplexer.addProcessor(this);
  87. inputMultiplexer.addProcessor(stage);
  88. Gdx.input.setInputProcessor(inputMultiplexer);
  89. }

  90. @Override
  91. public void dispose() {
  92. // TODO Auto-generated method stub

  93. }

  94. @Override
  95. public void pause() {
  96. // TODO Auto-generated method stub

  97. }

  98. @Override
  99. public void render() {
  100. Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
  101. OrthographicCamera c = (OrthographicCamera) stage.getCamera();
  102. if (isPress) {
  103. CameraMove(moveVector, player);
  104. }
  105. ((Label) stage.findActor("fpsLabel")).setText("FPS: "
  106. + Gdx.graphics.getFramesPerSecond());
  107. stage.act(Gdx.graphics.getDeltaTime());
  108. tileMapRenderer.render(c);
  109. stage.draw();
  110. }

  111. private void CameraMove(Vector3 vector3, Actor mainActor) {
  112. boolean isCameraMove = true;
  113. boolean isActorMove = true;

  114. Vector2 pos = new Vector2(mainActor.x, mainActor.y);
  115. if (CheckMoveable(map, nopassLayer, vector3, pos)) {
  116. return;
  117. }
  118. if (CheckMoveable(map, nopassLayer, vector3, pos.cpy().add(
  119. mainActor.width, 0))) {
  120. return;
  121. }
  122. if (CheckMoveable(map, nopassLayer, vector3, pos.cpy().add(
  123. mainActor.width, mainActor.height))) {
  124. return;
  125. }
  126. if (CheckMoveable(map, nopassLayer, vector3, pos.cpy().add(0,
  127. mainActor.height))) {
  128. return;
  129. }

  130. Vector3 viewport = stage.getCamera().position.cpy();
  131. viewport = viewport.add(vector3);
  132. Vector3 zbound = new Vector3(width / 2, height / 2, 0).add(viewport);
  133. if (zbound.x > maxCamPosition.x || zbound.y > maxCamPosition.y) {
  134. isCameraMove = false;
  135. }
  136. Vector3 fbound = new Vector3(-width / 2, -height / 2, 0).add(viewport);
  137. if (fbound.x < 0 || fbound.y < 0) {
  138. isCameraMove = false;
  139. }

  140. Vector3 v3 = new Vector3(mainActor.x, mainActor.y, 0);
  141. stage.getCamera().project(v3);
  142. Vector3 a = v3.cpy().add(vector3);
  143. if (a.x > width || a.y > height) {
  144. isActorMove = false;
  145. }
  146. if (a.x < 0 || a.y < 0) {
  147. isActorMove = false;
  148. }

  149. if (isCameraMove) {
  150. stage.getCamera().position.add(vector3);
  151. for (Actor actor : stage.getActors()) {
  152. if (!actor.equals(player)) {
  153. actor.x += vector3.x;
  154. actor.y += vector3.y;
  155. }
  156. }
  157. }
  158. if (isActorMove) {
  159. player.x += vector3.x;
  160. player.y += vector3.y;
  161. }
  162. }

  163. private boolean CheckMoveable(TiledMap map, TiledLayer layer,
  164. Vector3 vector3, Vector2 playpos) {
  165. Vector3 pos = new Vector3(playpos.x, playpos.y, 0).add(vector3);
  166. int nopassId = 0;
  167. TileSet set = map.tileSets.get(map.tileSets.size() - 1);
  168. int masSize = set.firstgid + layer.tiles.length;
  169. for (int i = 0; i < masSize; i++) {
  170. if ("False".equals(map.getTileProperty(i, "Pass"))) {
  171. nopassId = i;
  172. Gdx.app.log("Find!", i + " ");
  173. break;
  174. }
  175. }
  176. int xid = MathUtils.ceilPositive(pos.x / map.tileWidth);
  177. int yid = MathUtils.ceilPositive(pos.y / map.tileWidth);
  178. if (layer.tiles[layer.tiles.length - yid][xid - 1] == nopassId) {
  179. return true;
  180. } else {
  181. return false;
  182. }
  183. }

  184. @Override
  185. public void resize(int width, int height) {
  186. // TODO Auto-generated method stub

  187. }

  188. @Override
  189. public void resume() {
  190. // TODO Auto-generated method stub

  191. }

  192. @Override
  193. public boolean keyDown(int keycode) {

  194. return false;
  195. }

  196. @Override
  197. public boolean keyTyped(char character) {
  198. // TODO Auto-generated method stub
  199. return false;
  200. }

  201. @Override
  202. public boolean keyUp(int keycode) {
  203. // TODO Auto-generated method stub
  204. return false;
  205. }

  206. @Override
  207. public boolean scrolled(int amount) {
  208. // TODO Auto-generated method stub
  209. return false;
  210. }

  211. private void ChangeDirect(int typeId) {
  212. switch (typeId) {
  213. case 1:
  214. moveVector.set(0, 1, 0);
  215. Gdx.app.log("方向变动", "向上");
  216. break;
  217. case 2:
  218. moveVector.set(0, -1, 0);
  219. Gdx.app.log("方向变动", "向下");
  220. break;
  221. case 3:
  222. moveVector.set(-1, 0, 0);
  223. Gdx.app.log("方向变动", "向左");
  224. break;
  225. case 4:
  226. moveVector.set(1, 0, 0);
  227. Gdx.app.log("方向变动", "向右");
  228. break;
  229. }
  230. }

  231. @Override
  232. public boolean touchDown(int x, int y, int pointer, int button) {
  233. Vector3 tmp = new Vector3(x, y, 0);
  234. stage.getCamera().unproject(tmp);
  235. float newx = tmp.x - player.x;
  236. float newy = tmp.y - player.y;
  237. if (newx > 0 && newy > 0) {
  238. if (newx > newy) {
  239. ChangeDirect(4);
  240. } else {
  241. ChangeDirect(1);
  242. }
  243. } else if (newx > 0 && newy < 0) {
  244. if (newx > -newy) {
  245. ChangeDirect(4);
  246. } else {
  247. ChangeDirect(2);
  248. }
  249. } else if (newx < 0 && newy > 0) {
  250. if (-newx > newy) {
  251. ChangeDirect(3);
  252. } else {
  253. ChangeDirect(1);
  254. }
  255. } else {
  256. if (-newx > -newy) {
  257. ChangeDirect(3);
  258. } else {
  259. ChangeDirect(2);
  260. }
  261. }
  262. isPress = true;
  263. return false;
  264. }

  265. @Override
  266. public boolean touchDragged(int x, int y, int pointer) {
  267. // TODO Auto-generated method stub
  268. return false;
  269. }

  270. @Override
  271. public boolean touchMoved(int x, int y) {
  272. // TODO Auto-generated method stub
  273. return false;
  274. }

  275. @Override
  276. public boolean touchUp(int x, int y, int pointer, int button) {
  277. isPress = false;
  278. Gdx.app.log("Info", "touchUp: x:" + x + " y: " + y + " pointer: "
  279. + pointer + " button: " + button);
  280. return false;
  281. }
  282. }
复制代码

最终效果:
8.jpg

2012-1-18 00:01 上传
下载附件(81.77 KB)






写在最后:
1.调试好了就要在绘制前把障碍层删除。
2.注意各种坐标转化。
3.如果需要变化地图,直接操作Layer里面的那个二维数组。


本文用的检测方法只是一种可行方案而已,也可以直接看角色占的块数。
本文参考了:http://geekanddad.wordpress.com/2010/06/22/enemies-and-combat-how-to-make-a-tile-based-game-with-cocos2d-part-3/

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值