在上一节课中,我们对即将要完成的战旗Demo有了一个大概的了解,本节课当中,我们将会学习绘制游戏地图。
自从在JavaFX 2.2中增加了Canvas相关的功能,我们就可以使用Canvas来实现游戏绘制了。
游戏地图绘制主要用到GraphicsContext.drawImage方法。
drawImage(Image image,double sx,double sy,double sw,double sh,double dx,double dy,double dw,double dh);
其中image 表示源图片。
sx,sy,sw,sh表示相对于源图片的x,y坐标和截取的宽度和高度。
dx,dy,dw,dy表示绘制到画布上的x, y坐标和绘制的宽度和高度。
单元图片如下:
地图绘制就是将单元格进行拼接。
通常使用一个二维数组来表示地图数据如下:
int[][] mapIndex = { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 18, 18, 18, 18, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, };
下面来看看我们的游戏地图类:
import javafx.scene.canvas.GraphicsContext; import javafx.scene.image.Image; public class GameMap { private int[][] mapIndex = { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 18, 18, 18, 18, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, }; private int tileWidth; private int tileHeight; private int cols; private Image image; public GameMap(int tileWidth,int tileHeight, Image map){ this.tileWidth = tileWidth; this.tileHeight = tileHeight; this.image = map; cols = (int) (map.getWidth() / tileWidth); } public void drawMap(GraphicsContext gc) { int mapWidth = mapIndex[0].length; int mapHeight = mapIndex.length; for (int y = 0; y < mapHeight; y++) { for (int x = 0; x < mapWidth; x++) { int px = mapIndex[y][x] % cols; int py = mapIndex[y][x] / cols; gc.drawImage(image, px * tileWidth, py * tileHeight, tileWidth, tileHeight, x * tileWidth, y * tileHeight, tileWidth, tileHeight); } } } public int[][] getMapIndex() { return mapIndex; } public void setMapIndex(int[][] mapIndex) { this.mapIndex = mapIndex; } }
在实际游戏开发中,游戏地图数据通常存储在文件中,从文件读取,由于我这只是个Demo,写进来方便大家直观的了解。
首先,我们通过地图贴图的宽度和单元格的宽度来计算地图贴图单元格的列数,然后在绘制的时候,就可以通过地图索引和单元格列数,计算当前绘制的贴图的行和列,通过drawImage绘制出来。
接下来,创建我们的Canvas类:
import javafx.application.Platform; import javafx.scene.canvas.Canvas; import javafx.scene.canvas.GraphicsContext; import javafx.scene.image.Image; public class MainCanvas extends Canvas { // 游戏地图 private GameMap gameMap; private GraphicsContext gContext; private Image map; private int tileWidth = 32; private int tileHeight = 32; private boolean isRunning = true; private long sleep = 100; // 主线程 private Thread thread = new Thread(new Runnable() { @Override public void run() { while (isRunning) { Platform.runLater(new Runnable() { @Override public void run() { draw(); update(); } }); try { Thread.sleep(sleep); } catch (InterruptedException e) { e.printStackTrace(); } } } }); public MainCanvas(double width, double height) { super(width, height); map = new Image(getClass().getResourceAsStream("map0.png")); gContext = getGraphicsContext2D(); // 初始化游戏地图 gameMap = new GameMap(tileWidth, tileHeight, map); thread.start(); } public void draw() { gameMap.drawMap(gContext); } public void update() { } }
MainCanvas类比较简单,创建一个线程,用于执行draw和update方法。然后载入地图贴图,初始化GameMap,并完成绘制工作。
最后,在Main类中,将我们的Canvas加入到布局中。
import javafx.application.Application; import javafx.stage.Stage; import javafx.scene.Scene; import javafx.scene.layout.AnchorPane; public class Main extends Application { @Override public void start(Stage primaryStage) { try { AnchorPane root = new AnchorPane(); Scene scene = new Scene(root,640,480); MainCanvas mainCanvas = new MainCanvas(640, 480); root.getChildren().add(mainCanvas); scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm()); primaryStage.setScene(scene); primaryStage.show(); } catch(Exception e) { e.printStackTrace(); } } public static void main(String[] args) { launch(args); } }
下面看看运行效果:
这样,游戏地图就绘制成功了。有兴趣的朋友也可以自行修改地图索引,来绘制不同的地图。当然在实际开发中,我们还是会用地图编辑器来编辑的。
这一节课就到此结束了,下一节再见。
本文章为个人原创,版权所有,转载请注明出处:http://blog.csdn.net/ml3947。另外我的个人博客:http://www.wjfxgame.com.