Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android游戲 >> Android游戲開發 >> Android游戲引擎libgdx使用教程14:TiledMap中視角完善與障礙物處理

Android游戲引擎libgdx使用教程14:TiledMap中視角完善與障礙物處理

編輯:Android游戲開發

上文TiledMap中的角色和角色移動說到繪制了Map,然後我們的主角也可以四處活動了,但是仍有一些不完善的地方。

1.地圖的邊界沒有控制。Camera的位置其實是viewport的位置,不是屏幕邊界,所以如果直接按照上文的做法做的話主角走到屏幕邊緣的時候就有問題了。

Android游戲引擎libgdx使用教程14:TiledMap中視角完善與障礙物處理

2.沒有障礙,主角的行動沒有約束。

現在先來解決第一個問題。

解決方案很簡單,我們時刻注意viewport的位置,根據viewport計算Screen的邊界,讓其不超過地圖。

代碼如下:

Java代碼
  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. }  

運行一下,恩,感覺還行。但是又有一個問題出現了…當地圖達到邊界時地圖不能滾動了,但是主角應該還是可以前進的。

Android游戲引擎libgdx使用教程14:TiledMap中視角完善與障礙物處理

處理方法我采用的是將Camera和主角分開處理,還是判斷一下,主角如果移動後不超出屏幕,就繼續移動。

Java代碼
  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.    
  12. Vector3 v3 = new Vector3(mainActor.x, mainActor.y, 0);   
  13. stage.getCamera().project(v3);   
  14. Vector3 a = v3.cpy().add(vector3);   
  15. if (a.x > width || a.y > height) {   
  16. isActorMove = false;   
  17. }   
  18. if (a.x < 0 || a.y < 0) {   
  19. isActorMove = false;   
  20. }  
  21.    
  22. if (isCameraMove) {   
  23. stage.getCamera().position.add(vector3);   
  24. for (Actor actor : stage.getActors()) {   
  25. if (!actor.equals(player)) {   
  26. actor.x += vector3.x;   
  27. actor.y += vector3.y;   
  28. }   
  29. }   
  30. }   
  31. if (isActorMove) {   
  32. player.x += vector3.x;   
  33. player.y += vector3.y;   
  34. }  

Android游戲引擎libgdx使用教程14:TiledMap中視角完善與障礙物處理

第一個問題基本解決,為什麼說是基本解決?因為主角和Camera的位置可能會變動。造成主角在屏幕一角行走的問題。我一般是判斷主角位置,當位於中心區域時在讓二者聯動。

現在來解決第二個問題,障礙物的問題。

重新編輯我們的TMX文件。添加一個新圖塊:

Android游戲引擎libgdx使用教程14:TiledMap中視角完善與障礙物處理

大小還是32*32.

Android游戲引擎libgdx使用教程14:TiledMap中視角完善與障礙物處理

然後新建一個圖層,將地圖中不能穿越的部分用紅色的方塊填充。

Android游戲引擎libgdx使用教程14:TiledMap中視角完善與障礙物處理

編輯紅色塊的屬性,添加一個Pass-False鍵值(這個值是隨意的,只要你能懂就行)

Android游戲引擎libgdx使用教程14:TiledMap中視角完善與障礙物處理

最後隱藏該圖層,保存文件。(我在Editor裡面確實隱藏了這個層,但是libgdx還是繪制了,只有自己處理一下了)

Java代碼
  1. map = TiledLoader.createMap(mapHandle);  
  2.    
  3. for (int i = 0; i < map.layers.size(); i++) {   
  4. if ("NoPass".equals(map.layers.get(i).name)) {   
  5. nopassLayer = map.layers.get(i);   
  6. map.layers.remove(i);   
  7. break;   
  8. }   
  9. }  

map實例化以後,先尋找我們的障礙層,將其從map中移除。為了方便調試,暫時沒有移除它。

在主角每次移動時我們就檢查主角移動後的位置是在哪塊裡面,這塊是不是不能通過的,如果不能就不移動,否則就移動。

先遍歷所有tiles,看一下pass=false的是多少ID的那塊。

Java代碼
  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. }  

然後推算移動後會處於哪塊中,哪一塊是不是不能通過的。

Java代碼
  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. }  

在移動時先判斷一下,如果會達到不能到達的塊就直接退出。

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

完整代碼:(代碼有點亂…)

Java代碼
  1. package com.cnblogs.htynkn.game;  
  2.    
  3. import javax.swing.text.ZoneView;   
  4. import javax.swing.text.html.MinimalHTMLWriter;  
  5.    
  6. import com.badlogic.gdx.ApplicationListener;   
  7. import com.badlogic.gdx.Gdx;   
  8. import com.badlogic.gdx.InputMultiplexer;   
  9. import com.badlogic.gdx.InputProcessor;   
  10. import com.badlogic.gdx.files.FileHandle;   
  11. import com.badlogic.gdx.graphics.Color;   
  12. import com.badlogic.gdx.graphics.GL10;   
  13. import com.badlogic.gdx.graphics.OrthographicCamera;   
  14. import com.badlogic.gdx.graphics.Texture;   
  15. import com.badlogic.gdx.graphics.g2d.BitmapFont;   
  16. import com.badlogic.gdx.graphics.g2d.SpriteBatch;   
  17. import com.badlogic.gdx.graphics.g2d.TextureRegion;   
  18. import com.badlogic.gdx.graphics.g2d.tiled.TileAtlas;   
  19. import com.badlogic.gdx.graphics.g2d.tiled.TileMapRenderer;   
  20. import com.badlogic.gdx.graphics.g2d.tiled.TileSet;   
  21. import com.badlogic.gdx.graphics.g2d.tiled.TiledLayer;   
  22. import com.badlogic.gdx.graphics.g2d.tiled.TiledLoader;   
  23. import com.badlogic.gdx.graphics.g2d.tiled.TiledMap;   
  24. import com.badlogic.gdx.graphics.g2d.tiled.TiledObject;   
  25. import com.badlogic.gdx.graphics.g2d.tiled.TiledObjectGroup;   
  26. import com.badlogic.gdx.graphics.glutils.ShaderProgram;   
  27. import com.badlogic.gdx.math.MathUtils;   
  28. import com.badlogic.gdx.math.Vector2;   
  29. import com.badlogic.gdx.math.Vector3;   
  30. import com.badlogic.gdx.scenes.scene2d.Actor;   
  31. import com.badlogic.gdx.scenes.scene2d.Stage;   
  32. import com.badlogic.gdx.scenes.scene2d.ui.Image;   
  33. import com.badlogic.gdx.scenes.scene2d.ui.Label;   
  34. import com.badlogic.gdx.scenes.scene2d.ui.Label.LabelStyle;  
  35.    
  36. public class JavaGame implements ApplicationListener, InputProcessor {  
  37.    
  38. Stage stage;   
  39. float width;   
  40. float height;   
  41. private TiledMap map;   
  42. private TileAtlas atlas;   
  43. private TileMapRenderer tileMapRenderer;   
  44. Image player;   
  45. Vector3 camDirection = new Vector3(1, 1, 0);   
  46. Vector2 maxCamPosition = new Vector2(0, 0);   
  47. Vector3 moveVector = new Vector3(0, 0, 0);   
  48. boolean isPress;   
  49. TiledLayer nopassLayer;  
  50.    
  51. // Image image;  
  52.    
  53. @Override   
  54. public void create() {   
  55. final String path = "map/";   
  56. final String mapname = "tilemap";   
  57. FileHandle mapHandle = Gdx.files.internal(path + mapname + ".tmx");   
  58. map = TiledLoader.createMap(mapHandle);  
  59.    
  60. for (int i = 0; i < map.layers.size(); i++) {   
  61. if ("NoPass".equals(map.layers.get(i).name)) {   
  62. nopassLayer = map.layers.get(i);   
  63. // map.layers.remove(i);   
  64. break;   
  65. }   
  66. }  
  67.    
  68. atlas = new TileAtlas(map, new FileHandle("map/"));   
  69. tileMapRenderer = new TileMapRenderer(map, atlas, 10, 10);   
  70. maxCamPosition.set(tileMapRenderer.getMapWidthUnits(), tileMapRenderer   
  71. .getMapHeightUnits());  
  72.    
  73. width = Gdx.graphics.getWidth();   
  74. height = Gdx.graphics.getHeight();   
  75. stage = new Stage(width, height, true);   
  76. Label label = new Label("FPS:", new LabelStyle(new BitmapFont(Gdx.files   
  77. .internal("font/blue.fnt"),   
  78. Gdx.files.internal("font/blue.png"), false), Color.WHITE),   
  79. "fpsLabel");   
  80. label.y = height - label.getPrefHeight();   
  81. label.x = 0;   
  82. stage.addActor(label);  
  83.    
  84. for (TiledObjectGroup group : map.objectGroups) {   
  85. for (TiledObject object : group.objects) {   
  86. if ("play1".equals(object.name)) {   
  87. player = new Image(new TextureRegion(new Texture(Gdx.files   
  88. .internal("map/player.png")), 0, 0, 27, 40));   
  89. player.x = object.x;   
  90. player.y = tileMapRenderer.getMapHeightUnits() - object.y; // map是左上角,Stage是左下角   
  91. stage.addActor(player);   
  92. }   
  93. }   
  94. }  
  95.    
  96. InputMultiplexer inputMultiplexer = new InputMultiplexer();   
  97. inputMultiplexer.addProcessor(this);   
  98. inputMultiplexer.addProcessor(stage);   
  99. Gdx.input.setInputProcessor(inputMultiplexer);   
  100. }  
  101.    
  102. @Override   
  103. public void dispose() {   
  104. // TODO Auto-generated method stub  
  105.    
  106. }  
  107.    
  108. @Override   
  109. public void pause() {   
  110. // TODO Auto-generated method stub  
  111.    
  112. }  
  113.    
  114. @Override   
  115. public void render() {   
  116. Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);   
  117. OrthographicCamera c = (OrthographicCamera) stage.getCamera();   
  118. if (isPress) {   
  119. CameraMove(moveVector, player);   
  120. }   
  121. ((Label) stage.findActor("fpsLabel")).setText("FPS: "   
  122. + Gdx.graphics.getFramesPerSecond());   
  123. stage.act(Gdx.graphics.getDeltaTime());   
  124. tileMapRenderer.render(c);   
  125. stage.draw();   
  126. }  
  127.    
  128. private void CameraMove(Vector3 vector3, Actor mainActor) {   
  129. boolean isCameraMove = true;   
  130. boolean isActorMove = true;  
  131.    
  132. Vector2 pos = new Vector2(mainActor.x, mainActor.y);   
  133. if (CheckMoveable(map, nopassLayer, vector3, pos)) {   
  134. return;   
  135. }   
  136. if (CheckMoveable(map, nopassLayer, vector3, pos.cpy().add(   
  137. mainActor.width, 0))) {   
  138. return;   
  139. }   
  140. if (CheckMoveable(map, nopassLayer, vector3, pos.cpy().add(   
  141. mainActor.width, mainActor.height))) {   
  142. return;   
  143. }   
  144. if (CheckMoveable(map, nopassLayer, vector3, pos.cpy().add(0,   
  145. mainActor.height))) {   
  146. return;   
  147. }  
  148.    
  149. Vector3 viewport = stage.getCamera().position.cpy();   
  150. viewport = viewport.add(vector3);   
  151. Vector3 zbound = new Vector3(width / 2, height / 2, 0).add(viewport);   
  152. if (zbound.x > maxCamPosition.x || zbound.y > maxCamPosition.y) {   
  153. isCameraMove = false;   
  154. }   
  155. Vector3 fbound = new Vector3(-width / 2, -height / 2, 0).add(viewport);   
  156. if (fbound.x < 0 || fbound.y < 0) {   
  157. isCameraMove = false;   
  158. }  
  159.    
  160. Vector3 v3 = new Vector3(mainActor.x, mainActor.y, 0);   
  161. stage.getCamera().project(v3);   
  162. Vector3 a = v3.cpy().add(vector3);   
  163. if (a.x > width || a.y > height) {   
  164. isActorMove = false;   
  165. }   
  166. if (a.x < 0 || a.y < 0) {   
  167. isActorMove = false;   
  168. }  
  169.    
  170. if (isCameraMove) {   
  171. stage.getCamera().position.add(vector3);   
  172. for (Actor actor : stage.getActors()) {   
  173. if (!actor.equals(player)) {   
  174. actor.x += vector3.x;   
  175. actor.y += vector3.y;   
  176. }   
  177. }   
  178. }   
  179. if (isActorMove) {   
  180. player.x += vector3.x;   
  181. player.y += vector3.y;   
  182. }   
  183. }  
  184.    
  185. private boolean CheckMoveable(TiledMap map, TiledLayer layer,   
  186. Vector3 vector3, Vector2 playpos) {   
  187. Vector3 pos = new Vector3(playpos.x, playpos.y, 0).add(vector3);   
  188. int nopassId = 0;   
  189. TileSet set = map.tileSets.get(map.tileSets.size() - 1);   
  190. int masSize = set.firstgid + layer.tiles.length;   
  191. for (int i = 0; i < masSize; i++) {   
  192. if ("False".equals(map.getTileProperty(i, "Pass"))) {   
  193. nopassId = i;   
  194. Gdx.app.log("Find!", i + " ");   
  195. break;   
  196. }   
  197. }   
  198. int xid = MathUtils.ceilPositive(pos.x / map.tileWidth);   
  199. int yid = MathUtils.ceilPositive(pos.y / map.tileWidth);   
  200. if (layer.tiles[layer.tiles.length - yid][xid - 1] == nopassId) {   
  201. return true;   
  202. } else {   
  203. return false;   
  204. }   
  205. }  
  206.    
  207. @Override   
  208. public void resize(int width, int height) {   
  209. // TODO Auto-generated method stub  
  210.    
  211. }  
  212.    
  213. @Override   
  214. public void resume() {   
  215. // TODO Auto-generated method stub  
  216.    
  217. }  
  218.    
  219. @Override   
  220. public boolean keyDown(int keycode) {  
  221.    
  222. return false;   
  223. }  
  224.    
  225. @Override   
  226. public boolean keyTyped(char character) {   
  227. // TODO Auto-generated method stub   
  228. return false;   
  229. }  
  230.    
  231. @Override   
  232. public boolean keyUp(int keycode) {   
  233. // TODO Auto-generated method stub   
  234. return false;   
  235. }  
  236.    
  237. @Override   
  238. public boolean scrolled(int amount) {   
  239. // TODO Auto-generated method stub   
  240. return false;   
  241. }  
  242.    
  243. private void ChangeDirect(int typeId) {   
  244. switch (typeId) {   
  245. case 1:   
  246. moveVector.set(0, 1, 0);   
  247. Gdx.app.log("方向變動", "向上");   
  248. break;   
  249. case 2:   
  250. moveVector.set(0, -1, 0);   
  251. Gdx.app.log("方向變動", "向下");   
  252. break;   
  253. case 3:   
  254. moveVector.set(-1, 0, 0);   
  255. Gdx.app.log("方向變動", "向左");   
  256. break;   
  257. case 4:   
  258. moveVector.set(1, 0, 0);   
  259. Gdx.app.log("方向變動", "向右");   
  260. break;   
  261. }   
  262. }  
  263.    
  264. @Override   
  265. public boolean touchDown(int x, int y, int pointer, int button) {   
  266. Vector3 tmp = new Vector3(x, y, 0);   
  267. stage.getCamera().unproject(tmp);   
  268. float newx = tmp.x - player.x;   
  269. float newy = tmp.y - player.y;   
  270. if (newx > 0 && newy > 0) {   
  271. if (newx > newy) {   
  272. ChangeDirect(4);   
  273. } else {   
  274. ChangeDirect(1);   
  275. }   
  276. } else if (newx > 0 && newy < 0) {   
  277. if (newx > -newy) {   
  278. ChangeDirect(4);   
  279. } else {   
  280. ChangeDirect(2);   
  281. }   
  282. } else if (newx < 0 && newy > 0) {   
  283. if (-newx > newy) {   
  284. ChangeDirect(3);   
  285. } else {   
  286. ChangeDirect(1);   
  287. }   
  288. } else {   
  289. if (-newx > -newy) {   
  290. ChangeDirect(3);   
  291. } else {   
  292. ChangeDirect(2);   
  293. }   
  294. }   
  295. isPress = true;   
  296. return false;   
  297. }  
  298.    
  299. @Override   
  300. public boolean touchDragged(int x, int y, int pointer) {   
  301. // TODO Auto-generated method stub   
  302. return false;   
  303. }  
  304.    
  305. @Override   
  306. public boolean touchMoved(int x, int y) {   
  307. // TODO Auto-generated method stub   
  308. return false;   
  309. }  
  310.    
  311. @Override   
  312. public boolean touchUp(int x, int y, int pointer, int button) {   
  313. isPress = false;   
  314. Gdx.app.log("Info", "touchUp: x:" + x + " y: " + y + " pointer: "   
  315. + pointer + " button: " + button);   
  316. return false;   
  317. }   
  318. }  

最終效果:

Android游戲引擎libgdx使用教程14:TiledMap中視角完善與障礙物處理

寫在最後:

1.調試好了就要在繪制前把障礙層刪除。

2.注意各種坐標轉化。

3.如果需要變化地圖,直接操作Layer裡面的那個二維數組。

本文用的檢測方法只是一種可行方案而已,也可以直接看角色占的塊數。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved