任务12主要利用二维数组实现坦克游戏的地图设计,并通过绘制方法绘制出地图,地图效果如图12-1所示。
相对于一维数组只有一个下标维度,二维数组具有两个下标维度,分表表示数组的行和列,图12-2描述了一维数组和二维数组的维度。
从维度的观点可以看出,一维数组仅仅通过列下标获取数组元素:array[col],而二维数组多了一个行维度,因此,获取数组元素需要行下标和列下标:array[row][col]。
二维数组的创建与一维数组的创建类似:
//创建二维数组,大小为3行6列
int[][] array = new int[3][6];
其中第一个数字表示行数,第二个数字表示列数。上面的语句表示创建了一个3行6列的二维数组,数组元素的默认值为0,如图12-3所示。
通过行和列的下标,我们可以对指定的二维数组元素进行访问或赋值:
//对指定元素进行赋值与访问
System.out.println(array[1][2]);//赋值前
array[1][2] = 10;
System.out.println(array[1][2]);//赋值后
赋值后,数组第1行第2列的元素值为10,如图12-4所示。
在一维数组中,遍历数组中的元素是一个重复的过程,改变的仅仅是数组的列下标,因此,通过一个for循环以及循环变量i可以达到遍历数组的效果。
二维数组多了一个行维度,因此需要两个for循环,第一个for循环负责行数,第二个for循环负责列数。
int[][] array = new int[3][6];
//循环行数
for (int row = 0; row < 3; row++) {
//循环列数
for (int col = 0; col < 6; col++) {
System.out.print(array[row][col] + " ");
}
//打印完一行换行
System.out.println();
}
从对象的观点来看,二维数组本质是一个一维数组中存放的元素是一维数组:
//定义一维数组,存放元素为整数
int[] array01 = new int[2];
//以对象德观点理解二维数组
//首先创建一个大小为3的一维数组,存放元素是大小为2的一维数组
int[][] array02 = new int[3][2];
一维数组与二维数组的比较以及元素存储如图12-5所示。
用对象的观点遍历二维数组:
int[] array01 = new int[2];
System.out.println("打印一维数组:" + array01);
int[][] array = new int[3][2];
System.out.println("遍历二维数组");
for (int i = 0; i < array.length; i++) {
//打印一维数组中存放的元素:一维数组
System.out.println("第" + i + "个元素:" + array[i]);
}
此时,在控制台将会打印出如下信息:
打印一维数组:[I@21e8bf76
遍历二维数组
第0个元素:[I@3771ed5e
第1个元素:[I@1896d2c2
第2个元素:[I@55e6cb2a
array[i]打印出来不是一个数值,而是一堆符号,这些符号表示array[i]中存放的是一个对象(一维数组)。要想遍历这些数组中的元素,必须再次使用循环遍历:
int[][] array = new int[3][2];
//遍历一维数组array
for (int i = 0; i < array.length; i++) {
//遍历一维数组array中的数组元素(一维数组)
for (int j = 0; j < array[i].length; j++) {
System.out.print(array[i][j] + " ");
}
System.out.println();
}
新建Java项目【Project12】,在【Project12/img】文件夹中放入墙壁图片。
坦克类具有位置、图片、速度属性,四个方向的移动方法,如代码 清单12-1所示。
代码清单12-1:【Project/src/Tank.java】
public class Tank {
int x;
int y;
int speed = 20;
String url = "img/p1tankU.gif";
//构造方法,初始化坦克位置
public Tank(int x, int y) {
this.x = x;
this.y = y;
}
//四个方向移动方法
public void moveUp() {
url = "img/p1tankU.gif";
this.y = this.y - speed;
}
public void moveDown() {
url = "img/p1tankD.gif";
this.y = this.y + speed;
}
public void moveLeft() {
url = "img/p1tankL.gif";
this.x = this.x - speed;
}
public void moveRight() {
url = "img/p1tankR.gif";
this.x = this.x + speed;
}
}
地图类仅仅描述地图的结构,在地图类中使用二维数组walls表示地图的结构,数组中德元素值为1表示墙壁,为0表示空地,地图类如代码清单12-2所示。
代码清单12-2:【Project/src/Map.java】
public class Map {
//创建地图
int[][] walls = {
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
{1, 0, 0, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 0, 0, 1},
{1, 1, 1, 0, 0, 0, 1, 1, 0, 1},
{1, 0, 1, 1, 0, 0, 1, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 1, 0, 0, 1},
{1, 0, 0, 1, 1, 1, 1, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 0, 0, 1},
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
};
//判断位置是否墙壁,是墙壁返回true,否则返回false
public boolean isWall(int row, int col) {
if(walls[row][col] == 1){
return true;
}else{
return false;
}
}
}
面板类主要负责绘制地图,如果二维数组中的元素为1,则绘制,如代码清单12-3所示。
代码清单12-3:【Project/src/GamePanel.java】
mport java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import javax.swing.ImageIcon;
import javax.swing.JPanel;
public class GamePanel extends JPanel{
//创建地图
Map map = new Map();
//绘制地图大小
int size = 20;
@Override
public void paint(Graphics g) {
// TODO Auto-generated method stub
super.paint(g);
this.setBackground(Color.BLACK);
//获取墙壁图片资源
ImageIcon icon = new ImageIcon("img/wall.gif");
//将图片资源转换为g能够处理的信息
Image image = icon.getImage();
//循环遍历地图对象中的walls数组
for (int row = 0; row < map.walls.length; row++) {
for (int col = 0; col < map.walls[row].length; col++) {
if(map.isWall(row, col)){
//绘制墙壁,数组列col对应x轴,行row对应y轴
g.drawImage(image, col * size, row * size, size, size, this);
}
}
}
}
}
测试类负责创建框架和GamePanel面板,并将面板加入框架中进行显示,如代码清单12-4所示。
代码清单12-4:【Project/src/Test.java】
import javax.swing.JFrame;
public class Test {
public static void main(String[] args) {
JFrame frame = new JFrame("TankGame");
GamePanel gamePanel = new GamePanel();
frame.add(gamePanel);
frame.setSize(220, 240);
frame.setVisible(true);
}
}