贪吃蛇详解

知识点

1.JFrame类
JFrame 是带有标题和边界的顶层窗口,JFrame 的大小包括边界指定的所有区域,JFrame 的默认布局为 BorderLayout。
如前所述,与AWT组件不同,Swing组件不能直接添加到顶层容器中,它必须添加到一个与Swing顶层容器相关联的内容面板上。对JFrame添加组件有两种方式:
(1) 使用getContentPane( )方法获得JFrame的内容面板,再对其加入组件:frame.getContentPane().add(childComponent);
其中“childComponent”为基本组件。
(2) 构造一个Jpanel或 JDesktopPane之类的中间容器,把组件添加到容器中,用setContentPane()方法把该容器置为JFrame的内容面板:

Jpanel pnlMain=new Jpanel( ); //构造一个面板为中间容器
…… //把其它组件添加到Jpanel中;
frame.setContentPane(pnlMain); //把contentPane对象设置成为frame的内容面板
JFrame的构造方法如表5-1所示。
在这里插入图片描述

方法名 方法功能
JFrame() 构造 Frame 的一个新实例(初始时不可见)
JFrame(GraphicsConfiguration gc) 使用屏幕设备的指定 GraphicsConfiguration 创建一个 Frame。
JFrame(String title) 构造一个新的、初始不可见的、具有指定标题的 Frame 对象。
JFrame(String title,
GraphicsConfiguration gc) 构造一个新的、初始不可见的、具有指定标题和 GraphicsConfiguration 的 Frame 对象。

JFrame的常用方法如表5-2所示。
在这里插入图片描述
方法名 方法功能
boolean isResizable() 指示 frame 是否可由用户调整大小
remove(MenuComponent m) 从 frame 移除指定的菜单栏
setIconImage(Image image) 设置 frame 显示在最小化图标中的图像
setJMenuBar(MenuBar mb) 将 frame 的菜单栏设置为指定的菜单栏
setResizable(boolean resizable) 设置 frame 是否可由用户调整大小
setTitle(String title) 将 frame 的标题设置为指定的字符串
setSize(int width,int height) 设置frame大小
setLocation(int x,int y) 设置frame位置,其中(x,y)为左上角坐标
setDefaultCloseOperation(int operation) 设置点击关闭按钮时的默认操作
DO_NOTHING_ON_CLOSE:屏蔽关闭按钮
HIDE_ON_CLOSE:隐藏框架
DISPOSE_ON_CLOSE:隐藏和释放框架
EXIT_ON_CLOSE:退出应用程序

参考步骤

(1) 打开Eclipse,新建一个.java文件,并保存为GreedSnake.java.
(2)向GreedSnake.java文件中输入
import java.awt.;
import java.awt.event.
;
import javax.swing.;
import java.util.
;

//Main Class

public class GreedSnake extends KeyAdapter {

JFrame mainFrame;

Canvas paintCanvas;

JLabel labelScore;// 计分牌

SnakeModel snakeModel = null;// 蛇

public static final int DEFAULT_WIDTH = 500;

public static final int DEFAULT_HEIGHT = 300;

public static final int nodeWidth = 10;

public static final int nodeHeight = 10;

// GreedSnake():初始化游戏界面

public GreedSnake() {

	// 设置界面元素
	mainFrame = new JFrame("贪吃蛇游戏");
	Container cp = mainFrame.getContentPane();
	labelScore = new JLabel("所得分数为:", JLabel.CENTER);
	cp.add(labelScore, BorderLayout.NORTH);
	paintCanvas = new Canvas();
	paintCanvas.setSize(DEFAULT_WIDTH + 1, DEFAULT_HEIGHT + 1);
	paintCanvas.addKeyListener(this);
	cp.add(paintCanvas, BorderLayout.CENTER);
	JPanel panelButtom = new JPanel();
	panelButtom.setLayout(new BorderLayout());
	JLabel labelHelp;// 帮助信息
	labelHelp = new JLabel("按 PageUP 或 PageDown 键改变速度", JLabel.CENTER);
	panelButtom.add(labelHelp, BorderLayout.NORTH);
	labelHelp = new JLabel("按 Enter 或 S 键重新开始游戏", JLabel.CENTER);
	panelButtom.add(labelHelp, BorderLayout.CENTER);
	labelHelp = new JLabel("按 SPACE 键或 P 键暂停游戏", JLabel.CENTER);
	panelButtom.add(labelHelp, BorderLayout.SOUTH);
	cp.add(panelButtom, BorderLayout.SOUTH);
	mainFrame.addKeyListener(this);
	mainFrame.pack();
	mainFrame.setResizable(false);// 设置窗口大小不能变化
	mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
	mainFrame.setVisible(true);
	begin();
}

// keyPressed():按键检测

public void keyPressed(KeyEvent e) {

	int keyCode = e.getKeyCode();
	if (snakeModel.running)
		switch (keyCode) {
		case KeyEvent.VK_UP:
			snakeModel.changeDirection(SnakeModel.UP);
			break;
		case KeyEvent.VK_DOWN:
			snakeModel.changeDirection(SnakeModel.DOWN);
			break;
		case KeyEvent.VK_LEFT:
			snakeModel.changeDirection(SnakeModel.LEFT);
			break;
		case KeyEvent.VK_RIGHT:
			snakeModel.changeDirection(SnakeModel.RIGHT);
			break;
		case KeyEvent.VK_ADD:
		case KeyEvent.VK_PAGE_UP:
			snakeModel.speedUp();// 加速
			break;
		case KeyEvent.VK_SUBTRACT:
		case KeyEvent.VK_PAGE_DOWN:
			snakeModel.speedDown();// 减速
			break;
		case KeyEvent.VK_SPACE:
		case KeyEvent.VK_P:
			snakeModel.changePauseState();// 暂停或继续
			break;
		default:
		}
	// 重新开始
	if (keyCode == KeyEvent.VK_S || keyCode == KeyEvent.VK_ENTER) {
		snakeModel.running = false;
		begin();
	}
}

// repaint():绘制游戏界面(包括蛇和食物)

void repaint() {
	Graphics g = paintCanvas.getGraphics();
	// draw background
	g.setColor(Color.LIGHT_GRAY);
	g.fillRect(0, 0, DEFAULT_WIDTH, DEFAULT_HEIGHT);
	// draw the snake
	g.setColor(Color.BLACK);
	LinkedList na = snakeModel.nodeArray;
	Iterator it = na.iterator();
	while (it.hasNext()) {

		Node n = (Node) it.next();
		drawNode(g, n);
	}
	// draw the food
	g.setColor(Color.RED);
	Node n = snakeModel.food;
	drawNode(g, n);
	updateScore();
}

// drawNode():绘画某一结点(蛇身或食物)

private void drawNode(Graphics g, Node n) {
	g.fillRect(n.x * nodeWidth, n.y * nodeHeight, nodeWidth - 1, nodeHeight - 1);
}

// updateScore():改变计分牌

public void updateScore() {
	String s = "所得分数为: " + snakeModel.score;
	labelScore.setText(s);
}

// begin():游戏开始,放置贪吃蛇

void begin() {

	if (snakeModel == null || !snakeModel.running) {
		snakeModel = new SnakeModel(this, DEFAULT_WIDTH / nodeWidth, DEFAULT_HEIGHT / nodeHeight);
		(new Thread(snakeModel)).start();
	}
}

// main():主函数

public static void main(String[] args) {

	GreedSnake gs = new GreedSnake();
}

}

// Node:结点类

class Node {
int x;

int y;

Node(int x, int y) {
	this.x = x;
	this.y = y;
}

}

// SnakeModel:贪吃蛇模型

class SnakeModel implements Runnable {

GreedSnake gs;

boolean[][] matrix;// 界面数据保存在数组里

LinkedList nodeArray = new LinkedList();

Node food;

int maxX;// 最大宽度

int maxY;// 最大长度

int direction = 2;// 方向

boolean running = false;

int timeInterval = 200;// 间隔时间(速度)

double speedChangeRate = 0.75;// 速度改变程度

boolean paused = false;// 游戏状态

int score = 0;

int countMove = 0;

// UP和DOWN是偶数,RIGHT和LEFT是奇数
public static final int UP = 2;

public static final int DOWN = 4;

public static final int LEFT = 1;

public static final int RIGHT = 3;

// GreedModel():初始化界面

public SnakeModel(GreedSnake gs, int maxX, int maxY) {

	this.gs = gs;
	this.maxX = maxX;
	this.maxY = maxY;
	matrix = new boolean[maxX][];
	for (int i = 0; i < maxX; ++i) {
		matrix[i] = new boolean[maxY];
		Arrays.fill(matrix[i], false);// 没有蛇和食物的地区置false
	}
	// 初始化贪吃蛇
	int initArrayLength = maxX > 20 ? 10 : maxX / 2;
	for (int i = 0; i < initArrayLength; ++i) {
		int x = maxX / 2 + i;
		int y = maxY / 2;
		nodeArray.addLast(new Node(x, y));
		matrix[x][y] = true;// 蛇身处置true
	}
	food = createFood();
	matrix[food.x][food.y] = true;// 食物处置true
}

// changeDirection():改变运动方向

public void changeDirection(int newDirection) {

	if (direction % 2 != newDirection % 2) {// 避免冲突
		direction = newDirection;
	}
}

// moveOn():贪吃蛇运动函数

public boolean moveOn() {

	Node n = (Node) nodeArray.getFirst();
	int x = n.x;
	int y = n.y;
	switch (direction) {
	case UP:
		y--;
		break;
	case DOWN:
		y++;
		break;
	case LEFT:
		x--;
		break;
	case RIGHT:
		x++;
		break;
	}
	if ((0 <= x && x < maxX) && (0 <= y && y < maxY)) {

		if (matrix[x][y]) {// 吃到食物或者撞到身体

			if (x == food.x && y == food.y) {// 吃到食物

				nodeArray.addFirst(food);// 在头部加上一结点
				// 计分规则与移动长度和速度有关
				int scoreGet = (10000 - 200 * countMove) / timeInterval;
				score += scoreGet > 0 ? scoreGet : 10;
				countMove = 0;
				food = createFood();
				matrix[food.x][food.y] = true;
				return true;
			} else
				return false;// 撞到身体
		} else {// 什么都没有碰到
			nodeArray.addFirst(new Node(x, y));// 加上头部
			matrix[x][y] = true;
			n = (Node) nodeArray.removeLast();// 去掉尾部
			matrix[n.x][n.y] = false;
			countMove++;
			return true;
		}
	}
	return false;// 越界(撞到墙壁)
}

// run():贪吃蛇运动线程

public void run() {
	running = true;
	while (running) {
		try {
			Thread.sleep(timeInterval);
		} catch (Exception e) {
			break;
		}
		if (!paused) {

			if (moveOn()) {// 未结束
				gs.repaint();
			} else {// 游戏结束
				JOptionPane.showMessageDialog(null, "GAME OVER", "Game Over", JOptionPane.INFORMATION_MESSAGE);
				break;
			}
		}
	}
	running = false;
}

// createFood():生成食物及放置地点

private Node createFood() {

	int x = 0;
	int y = 0;
	do {
		Random r = new Random();
		x = r.nextInt(maxX);
		y = r.nextInt(maxY);
	} while (matrix[x][y]);
	return new Node(x, y);
}

// speedUp():加快蛇运动速度

public void speedUp() {
	timeInterval *= speedChangeRate;
}

// speedDown():放慢蛇运动速度

public void speedDown() {

	timeInterval /= speedChangeRate;
}

// changePauseState(): 改变游戏状态(暂停或继续)

public void changePauseState() {

	paused = !paused;
}

}

执行结果

在这里插入图片描述

实现移动,吃食变长游戏把子上下左右控制蛇的方向,寻找吃的东西,每吃一口就能得到一定的积分,而且蛇的身子会越吃越长,身子越长玩的难度就越大,不能碰墙,不能咬到自己的身体,更不能咬自己的尾巴,等到了一定的分数,就能过关,然后继续玩下一关。[3] 二、“贪吃蛇”游戏的发展编辑 改变此款游戏的特别多。比如在蛋的方面,可能放上带道具的蛋,使蛇吃完后具有保护,穿墙等特种功能,而且难度逐渐变难,游戏制作的精细度和画面的质量也随着版本的提高而不断提高,且有单人及团队联机对战版本陆续推出。 参考资料游戏把子上下左右控制蛇的方向,寻找吃的东西,每吃一口就能得到一定的积分,而且蛇的身子会越吃越长,身子越长玩的难度就越大,不能碰墙,不能咬到自己的身体,更不能咬自己的尾巴,等到了一定的分数,就能过关,然后继续玩下一关。[3] 二、“贪吃蛇”游戏的发展编辑 改变此款游戏的特别多。比如在蛋的方面,可能放上带道具的蛋,使蛇吃完后具有保护,穿墙等特种功能,而且难度逐渐变难,游戏制作的精细度和画面的质量也随着版本的提高而不断提高,且有单人及团队联机对战版本陆续推出。 游戏把子上下左右控制蛇的方向,寻找吃的东西,每吃一口就能得到一定的积分,而且蛇的身子会越吃越长,身子越长玩的难度就越大,不能碰墙,不能咬到自己的身体,更不能咬自己的尾巴,等到了一定的分数,就能过关,然后继续玩下一关。[3] 二、“贪吃蛇”游戏的发展编辑 改变此款游戏的特别多。比如在蛋的方面,可能放上带道具的蛋,使蛇吃完后具有保护,穿墙等特种功能,而且难度逐渐变难,游戏制作的精细度和画面的质量也随着版本的提高而不断提高,且有单人及团队联机对战版本陆续推出。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

学习Java的小余

万物皆有时,比如你我相遇!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值