Java 采钻游戏

概要:

本实例将演示一个有趣的采钻游戏,采钻游戏的游戏规则是对钻石进行消除,最终目标是将所有钻石全部消掉,如果两个或两个以上的钻石在同一水平线,游戏便会结束。

| |目录

技术要点

  1. 实现采钻游戏的技术要点如下:

  • keyDown事件的应用。

  • ImageFilter类的使用。

  • MediaTracker类的使用。

准备工作

将图片放在src目录下。

图片:

代码实现

package net.xsoftlab.baike;
import java.applet.Applet;
import java.awt.BorderLayout;
import java.awt.Button;
import java.awt.Color;
import java.awt.Event;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.MediaTracker;
import java.awt.Panel;
import java.awt.TextField;
import java.awt.image.CropImageFilter;
import java.awt.image.FilteredImageSource;
import java.awt.image.ImageFilter;
import java.awt.image.ImageProducer;
import java.net.URL;
public class Mining extends Applet implements Runnable {
	static int MAX_X = 12, MAX_Y = 12, MAX_LVL = 100, MAX_IMG = 11,
			MAX_HIST = 100;
	static int X_0 = 5, Y_0 = 5; // 静态变量说明
	Thread thread = null;
	private Image[] sImage = new Image[MAX_IMG + 1];
	private int xPos, yPos, gLevel, mvPos, maxMove;
	private byte[][] MinCanvas = new byte[MAX_Y + 1][MAX_X + 1];
	private byte[] xMove = new byte[MAX_HIST];
	private byte one_Time;
	private Button btnR = new Button("返回");
	private Button btnN = new Button("下一级");
	private Button btnP = new Button("上一级");
	// 定义按钮
	private static String stGame = " [GAME over]";
	private static String stLost = " [YOU LOST]";
	// 定义游戏状态
	private static String widthe = " #    *.oO@+,123456789abcdefghij";
	private static int xCoord[][] = {
			{ 0, 0, 20, 20 },
			{ 20, 0, 20, 20 },// 截取图像时所需要的图素
			{ 40, 0, 20, 20 }, { 60, 0, 20, 20 }, { 80, 0, 20, 20 },
			{ 100, 0, 20, 20 }, { 100, 20, 20, 20 }, { 0, 20, 20, 20 },
			{ 20, 20, 20, 20 }, { 40, 20, 20, 20 }, { 60, 20, 20, 20 },
			{ 80, 20, 20, 20 } };
	private static String data_grade[] = {// 定义游戏的级数
			", #7, #o.o.o.#, # 5#, # # # #1, # # 3#, # 4#1, #6,",
			",, 1#5, 1#.* 1#, 1# 3#, 1#. 2#, 1# 1.#1, 1#5,",
			", 2#3, 1#1 .#1, 1# 3#, 1#. o #, 1# 1# #, 1# 1. #, 1#1o #1, 2#3,",
			", 1#2, #1 #2, # . 1#1, #* . 1#1, # 1* . #, # # 1#2, #5,",
			", 4#2, #4.#1, #. 4#, #1 2* #, 1#1 # #1, 2# #2, 2# 1.#, 2#4,",
			", #6, # 4#, #1 .* #, #. 3#, #* 2.#, # 2* #, #6,",
			" #7, # 1. 2#,#1 1*# 1#,# 2.# 1#,#1 #1 2#, # 1* 2#, # 1. 2#, # 5#, # 5#, #7,",
			", #6, # .# o#1, #1 3o#, 1# 3#1, 1#* 2.#, 1#.o 1#1, 1#5,",
			", 2#4, 1#1 O #, #1 3#1,#1.O 3#,# 2o 1#1,# 1#2.#,# O o 1#,#7,",
			" #2,#1 #4,#. 2O #,# 2#1.#1,# 1Oo# 1#,# o# 2#1,# 2. o #,#O 1#1 #1,#7,",
			" 1#2, 1# #2, 1# 1o#1, 1#*. o#1, 1# #O o#, #1 2# #, # . 2O#, #1O 2#1, 1#5,",
			"#8,# Oo.oO #,# 2o 2#,# 2O 2#,# 2o 2#,# o . O #,#1 1# 1#1, #6,",
			"1#4, #1 # #1, # .# 1#1, #1 #. 1#, # 5#, #1 * 1.#, 1#1 2#1, 2#1 #1, 3#2,",
			" 1#5, #1 1# #1, #.*o.*.#1, # 6#, # #1 # 1#,#1 2#1 1#,# o 4#1,#1 4#1, #6,",
			" #3,#1 1#3,# 2. 1#,#1 .#.#1, # 4#, # #o#o#, #1 1o #, 1#1 2#, 2#1 #1, 3#2,",
			", #5, # 1o.#1, # . #o#1, # * 3#, #o 4#, #1 2.#1, 1#1 1#1, 2#3,",
			", #5, # 1o #1, # O# o#, #o 1O.#1, # 5#, #1. 2O#, 1#6,",
			" #5, # O .#1, #1 2O#1, 1# o#. #, #1 3o#, #O #O 1#, # o 3#, #1 #4, 1#2,",
			" 1#4, #1O 1#, # o 1#1, #1. 2#, # O.o*#, #1 2.#1, 1# 2o #, 1#1 3#, 2#5,",
			" #7,#1 o 1O #,# 4o#1,#1 5#,# 1O 1.#1,#1. 2*#, #1o 2#, # . 1O#, #6,", };
	private static int aMove[] = { 4, 4, 4, 4, 6, 6, 6, 6, // 移动的像素
			7, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 10, };
	private Image mainImg;
	private Graphics g;
	private TextField txt1;
	public void init() {// Applect初始化
		String param;
		int i;
		if (g == null)
			g = getGraphics();
		URL url = getCodeBase();
		MediaTracker tracker = new MediaTracker(this);// 创建媒体跟踪器tracker
		mainImg = getImage(url, "zuan.gif");// 获取指定路径下的图像
		tracker.addImage(mainImg, 0);// 将该图片加载到tracker中
		for (i = 0; i <= MAX_IMG; i++) {
			sImage[i] = splitImage(xCoord[i]);// 根据像素截取相应的图像
			tracker.addImage(sImage[i], i + 1);// 将截取的图像载入到tracker指定的位置
		}
		try {
			tracker.waitForAll();// 等待此媒体跟踪器跟踪加载所有的图像
		} catch (InterruptedException e) {
		}
		// 设置布局
		setLayout(new BorderLayout());
		txt1 = new TextField(17);
		txt1.setForeground(new Color(255, 255, 204));// 设置前景色
		txt1.setBackground(new Color(102, 51, 51));// 设置背景色
		txt1.setEditable(false);// 设置文本输入框为不可编辑
		Panel p = new Panel();// 创建面板容器
		// 将组件加入到面板中
		p.add(txt1);
		p.add(btnP);
		p.add(btnN);
		p.add(btnR);
		add("South", p);// 布局格式
		gLevel = 0;
		dat2Canvas(0);// 调用自定义方法
		one_Time = 1;
		this.resize(310, 250);
	}
	public void start() // 启动线程
	{
		if (thread == null) {
			thread = new Thread(this);
			thread.start();
		}
	}
	public void stop() {// 终止线程
		if (thread != null) {
			thread.stop();
			thread = null;
		}
	}
	public void run() {
	}
	public boolean dat2Canvas(int dlvl) {
		int i = 0, x, y, tmp0;
		byte z = 0, oz = 0;
		String param = null;
		try {
			gLevel += dlvl;
			if (gLevel < 0)
				gLevel = 0;
			if (i > 0)
				maxMove = i;
			if (param == null || i <= 0) {
				param = data_grade[gLevel];
				maxMove = aMove[gLevel];
			}
		} catch (ArrayIndexOutOfBoundsException exc) {
			gLevel -= dlvl;
			return false;
		}
		for (y = 0; y <= MAX_Y; y++) {
			for (x = 0; x <= MAX_X; x++) {
				MinCanvas[y][x] = 0;
			}
		}
		x = y = 0;
		for (i = 0; i < param.length(); i++) {
			z = (byte) (widthe.indexOf(param.charAt(i)));
			if (z > MAX_IMG) {
				if ((tmp0 = (z - MAX_IMG - 1)) > 0) {
					for (int j = 0; j < tmp0; j++) {
						try {
							MinCanvas[y][x++] = oz;
						} catch (ArrayIndexOutOfBoundsException exc) {
							j = tmp0;
						}
					}
				} else {
					x = 0;
					y++;
					if (y > MAX_Y)
						break;
				}
			} else if (x <= MAX_X) {
				if (z < 0)
					z = 0;
				MinCanvas[y][x++] = z;
				oz = z;
			}
		}
		for (i = 0; i < MAX_HIST; i++) {
			xMove[i] = 0;
		}
		mvPos = 0;
		txt1.setText("Level " + gLevel + "(最多可移动" + maxMove + "步)");
		if (one_Time == 1)
			one_Time = 0;
		return true;
	}
	public boolean action(Event e, Object arg) {// button的动作处理
		int h = -1;
		if (e.target == btnP)// 判断事件目标是否为btnP
			h = 44;
		else if (e.target == btnN)// 判断事件目标是否为btnN
			h = 46;
		else if (e.target == btnR)// 判断事件目标是否为btnR
			h = 27;
		if (h > 0)
			keyDown(e, h);// 调用keyDown方法
		return true;
	}
	public boolean keyDown(Event e, int c)// 键盘动作处理
	{
		int dx = 0;
		int dy = 0;
		int ch = 0;
		int h = 0;
		switch (c) {
		case Event.UP: // UP:方向键上
			dy = -1;
			h = 1;
			break;
		case Event.DOWN:// DOWN:方向键下
			dy = 1;
			h = 3;
			break;
		case Event.LEFT:// LEFT:方向键左
			dx = -1;
			h = 5;
			break;
		case Event.RIGHT:// RIGHT:方向键右
			dx = 1;
			h = 7;
			break;
		case 27:
			if (mvPos == 0 && one_Time == 0) {
				one_Time = 1;
				paint(null);
				return true;
			}
			h = -100;
			break;
		case 44:
			h = -101;
			break;
		case 46:
			h = -99;
			break;
		case 14:
			h = -90;
			break;
		case 16:
			h = -110;
			break;
		default:
			txt1.setText(" Use ^P,<,>,^N,^R, or BS key.");
			break;
		}
		if (dx == 0 && dy == 0) {
			if (h < 0) {
				if (dat2Canvas(h + 100))
					paint(null);
			}
			return true;
		}
		if (mvPos >= maxMove) {
			txt1.setText(stLost);
			return true;
		}
		h = 1;
		ch = 0;
		while (h > 0) {
			ch = 0;
			if ((h = moveBall(dx, dy)) > 0) {
				ch = 1;
				h = checkBoard();
			}
		}
		if (ch == 1) {
			mvPos++;
			txt1.setText("还剩" + (maxMove - mvPos) + "步哦!");// maxMove最多可以走的步数,mvPos已经走过的步数
		} else
			return true;
		h = GameEnd();
		if (h == 1) {
			txt1.setText(stGame);
			h = -98;
		} else if (h == -1 || mvPos >= maxMove) {
			txt1.setText(stLost);
			h = -99;
		}
		if (h <= -98) {
			try {
				thread.sleep(1500);
			} catch (InterruptedException exc) {
			}
			if (dat2Canvas(h + 99))
				paint(null);
		}
		return true;
	}
	public int moveBall(int dx, int dy) {//
		int x, y, lx, ly, x2, y2;
		byte z0, z1;
		int h = 0;
		if (dx != 0) {
			ly = Y_0;
			for (y = 0; y <= MAX_Y; y++) {
				if (dx == 1)
					x = MAX_X - 1;
				else
					x = 1;
				while (x > 0 && x < MAX_X) {
					if ((z0 = MinCanvas[y][x]) >= 6) {
						x2 = x;
						lx = X_0 + 20 * x;
						while (x2 > 0 && x2 < MAX_X
								&& (z1 = MinCanvas[y][x2 + dx]) == 0) {
							try {
								thread.sleep(10);
							} catch (InterruptedException e) {
							}
							h++;
							MinCanvas[y][x2] = 0;
							g.drawImage(sImage[0], lx, ly, this);
							x2 += dx;
							lx += 20 * dx;
							MinCanvas[y][x2] = z0;
							g.drawImage(sImage[z0], lx, ly, this);
						}
					}
					x -= dx;
				}
				ly += 20;
			}
		}
		if (dy != 0) {
			lx = X_0;
			for (x = 0; x <= MAX_X; x++) {
				if (dy == 1)
					y = MAX_Y - 1;
				else
					y = 1;
				while (y > 0 && y < MAX_Y) {
					if ((z0 = MinCanvas[y][x]) >= 6) {
						y2 = y;
						ly = Y_0 + 20 * y;
						while (y2 > 0 && y2 < MAX_Y
								&& (z1 = MinCanvas[y2 + dy][x]) == 0) {
							try {
								thread.sleep(10);
							} catch (InterruptedException e) {
							}
							h++;
							MinCanvas[y2][x] = 0;
							g.drawImage(sImage[0], lx, ly, this);
							y2 += dy;
							ly += 20 * dy;
							MinCanvas[y2][x] = z0;
							g.drawImage(sImage[z0], lx, ly, this);
						}
					}
					y -= dy;
				}
				lx += 20;
			}
		}
		return h;
	}
	public int checkBoard() {
		byte z0, z1, z2;
		int h = 0;
		int h2 = 0;
		z1 = 100;
		for (int y = 0; y < MAX_Y; y++) {
			for (int x = 0; x < MAX_X; x++) {
				z0 = (byte) (MinCanvas[y][x] % z1);
				if (z0 >= 7) {
					z2 = (byte) (z0 + z1);
					if (z0 == (byte) (MinCanvas[y][x + 1] % z1)) {
						MinCanvas[y][x] = MinCanvas[y][x + 1] = z2;
						h++;
					}
					if (z0 == (byte) (MinCanvas[y + 1][x] % z1)) {
						MinCanvas[y][x] = MinCanvas[y + 1][x] = z2;
						h++;
					}
				}
			}
		}
		if (h == 0)
			return 0;
		for (int z = 2; z <= 6; z++) {
			try {
				thread.sleep(100);
			} catch (InterruptedException e) {
			}
			int ly = Y_0;
			for (int y = 0; y < MAX_Y; y++) {
				int lx = X_0;
				for (int x = 0; x < MAX_X; x++) {
					if ((z0 = MinCanvas[y][x]) > MAX_IMG) {
						if (z < 6)
							g.drawImage(sImage[z], lx, ly, this);
						else {
							MinCanvas[y][x] = 0;
							g.drawImage(sImage[0], lx, ly, this);
						}
					}
					lx += 20;
				}
				ly += 20;
			}
		}
		return h;
	}
	public int GameEnd() {
		int x, y;
		int h = 1;
		int h0[] = new int[MAX_IMG + 1];
		for (y = 0; y <= MAX_IMG; y++)
			h0[y] = 0;
		for (y = 0; y <= MAX_Y; y++) {
			for (x = 0; x <= MAX_X; x++) {
				h0[MinCanvas[y][x]]++;
			}
		}
		y = 7;
		while (y <= MAX_IMG) {
			x = h0[y];
			if (x == 1) {
				h = -1;
				y = MAX_IMG + 1;
			} else if (h == 1 && x > 1)
				h = 0;
			y++;
		}
		return h;
	}
	private Image splitImage(int[] xyCoord) {
		Image newImage;
		ImageFilter filter;
		ImageProducer producer;
		filter = new CropImageFilter(xyCoord[0], xyCoord[1], xyCoord[2],
				xyCoord[3]);
		producer = new FilteredImageSource(mainImg.getSource(), filter);
		newImage = createImage(producer);
		return newImage;
	}
	public void paint(Graphics g) {
		if (g == null)
			g = getGraphics();
		int y2 = Y_0;
		for (int y = 0; y <= MAX_Y; y++) {
			int x2 = X_0;
			for (int x = 0; x <= MAX_X; x++) {
				byte z = MinCanvas[y][x];
				if (one_Time == 1 || z > MAX_IMG)
					z = 0;
				g.drawImage(sImage[z], x2, y2, this);
				x2 += 20;
			}
			y2 += 20;
		}
		if (one_Time == 1)
			Description();
	}
	public void Description()// 进入游戏时设置,说明规则
	{
		int y = 30, x = 15;
		g.setColor(new Color(255, 69, 0));
		String str = "* 采钻游戏 *";
		g.drawString(str, x, y);
		txt1.setText(str);
		y += 10;
		g.drawString("", x, y);
		y += 10;
		g.drawString("游戏目标:采走所有的钻石", x, y);
		y += x;
		g.drawString("", x, y);
		y += x;
		g.drawString("移动方式:方向键", x, y);
		y += x;
		g.drawString("", x, y);
		y += x;
		g.drawString("采钻规则:水平或竖直方向两个以上的钻", x, y);
		y += x;
		g.drawString("", x, y);
		y += x;
		g.drawString("", x, y);
		y += x;
		g.drawString("WIN:所有钻消失", x, y);
		y += 20;
		g.drawString("", x, y);
		y += x;
		g.drawString("LOST:钻石有剩余", x, y);
		y += x;
		g.drawString("", x, y);
	}
}

程序解读

  1. init()方法Applet初始化,创建媒体跟踪器MediaTracker,getImage()方法获取指定路径下的图像;调用addImage()方法将指定的图片加载到tracker中;调用splitImage()方法为sImage数组赋值,sImage数组是一个Image类型的;再次调用addImage()方法依次将sImage数组中的值加载到tracker中;调用waitForAll()让线程处于休眠状态,一直等待此媒体跟踪器跟踪加载完所有图像。接着对Applet程序的外观进行设置。

  2. start()方法启动线程。

  3. stop()方法终止线程。

  4. dat2Canvas()方法的具体作用是根据传入的游戏级别,将data_grade数组中定义好的游戏数据依次取出放入MinCanvas数组中。

  5. keyDown()方法的作用是对键盘中上、下、左、右键的处理,每个按键下都隐含一个int型数字,根据这些数字来计算钻石在每走一步后的位置。

  6. moveBall()方法的作用是根据传进来的两个参数值,规定通过键盘按键后,钻石出现的位置。

  7. splitImage()方法的作用是根据xyCoord数组提供的图像的坐标和起始位置对指定的图片进行分隔,也就是一个图片上取下一部分。


评论关闭
评论 还能输入200
评论关闭
评论 还能输入200
  • 全部评论(0)
资料加载中...
已关注 , 取消