JAVA程序设计(16)----- 贪食蛇游戏制作 LinkedList 初级应用

主要是LinkedList应用,JFrame,HAS-A的组合关系,Timer应用,键盘监听器(适配器)应用,方法的重写 等练习

原始制作顺序为:

面板 1.SnakeFrame  -------> 可动的点 2.Snake ------> 然后在Snake上加入方向3. Dirction --------> Snake 加入LinkedList 做成连续的蛇  并制作单节蛇 4. SnakeNode------------>制作可以吃的5.Egg  ,将游戏中硬代码提出 写成6.SnakeContext 。

1.SnakeFrame部分

package com.lovo.snake;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.Timer;

/**
 * 类:贪食蛇 面板
 * @author Abe
 */
@SuppressWarnings("serial")
public class SnakeFrame extends JFrame {
	private Timer timer;
	private Image offImage = new BufferedImage(SnakeContext.GAME_SIZE,
			SnakeContext.GAME_SIZE, 1);
	private Snake snake = new Snake();
	private Egg egg = new Egg();
	private int counter = 0;
	private JLabel jl;
	private int level = 0;
	private boolean gameOver = false;
	
	/**
	 * 构造器 初始化
	 */
	public SnakeFrame() {
		this.setSize(SnakeContext.GAME_SIZE, SnakeContext.GAME_SIZE);
		this.setResizable(false);
		this.setLocationRelativeTo(null);
		this.setDefaultCloseOperation(EXIT_ON_CLOSE);
		this.setLayout(null);
		
		jl = new JLabel("分数:" + counter + "分");
		jl.setBounds(50, 0, 400, 25);
		this.add(jl);
		/**
		 * 键盘监听器
		 */
		this.addKeyListener(new KeyAdapter() {
			@Override
			public void keyPressed(KeyEvent e) {
				Direction newDir = snake.getDir();
				switch (e.getKeyCode()) {
				case KeyEvent.VK_W:
				case KeyEvent.VK_UP:
					newDir = Direction.UP;
					break;
				case KeyEvent.VK_S:
				case KeyEvent.VK_DOWN:
					newDir = Direction.DOWN;
					break;
				case KeyEvent.VK_A:
				case KeyEvent.VK_LEFT:
					newDir = Direction.LEFT;
					break;
				case KeyEvent.VK_D:
				case KeyEvent.VK_RIGHT:
					newDir = Direction.RIGHT;
					break;
				}
				if (snake.getDir() != newDir) {
					snake.changeDir(newDir);
				}
			}
		});
		/**
		 * F2 重置游戏键盘监听器(可写在上面一起)单独好看点
		 */
		this.addKeyListener(new KeyAdapter() {
			@Override
			public void keyPressed(KeyEvent e) {
				int obj = e.getKeyCode();
				if (obj == KeyEvent.VK_F2) {
					for (int i = 0; i < snake.getLength(); i++) {
						snake.remove();
					}
					snake = new Snake();
					counter = 0;
					timer.start();
					repaint();
					gameOver = false;
				}
			}
		});
		/**
		 * Timer
		 */
		timer = new Timer(SnakeContext.INTERVAL, new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				Object obj = e.getSource();
				if (obj == timer && gameOver == false) {
					snake.move();
					SnakeNode tempHead = snake.getHead();
					if (!snake.eatEgg(egg)) {
						snake.remove();
						jl.setText("分数:" + counter + "分"+ "                  按F2可刷新游戏");
					} else {
						counter += 100;
						do {
							egg = new Egg();
						} while (isRepeat(0,egg.getX(), egg.getY()));
						if (counter % 100 == 0) {
							if (level < 200) {
								level += 20;
							}
							timer.setDelay(SnakeContext.INTERVAL);
						}
					}
					repaint();
					/**
					 * 死亡判定,撞墙 撞自己
					 */
					int x = tempHead.getX();
					int y = tempHead.getY();
					if ((x < SnakeContext.WALL_X)
							|| (x > SnakeContext.WALL_X
									+ SnakeContext.SQUARE_SIZE
									- SnakeContext.SNAKE_SIZE)
							|| (y < SnakeContext.WALL_Y)
							|| (y > SnakeContext.WALL_Y
									+ SnakeContext.SQUARE_SIZE
									- SnakeContext.SNAKE_SIZE)) {
						timer.stop();
						gameOver = true;
					} else if (isRepeat(1,x, y)) {
						timer.stop();
						gameOver = true;
					}
				}
			}
		});
		timer.start();
	}

	/**
	 * 方法:输入坐标筛查重复
	 */
	public boolean isRepeat(int firstIndex,int x, int y) {
		for (int i = firstIndex; i < snake.getList().size(); i++) {
			SnakeNode temp = snake.getList().get(i);
			if (temp.getX() == x && temp.getY() == y) {
				return true;
			}
		}
		return false;
	}

	/**
	 * 重写:绘图方法
	 */
	@Override
	public void paint(Graphics g) {
		Graphics offG = offImage.getGraphics();
		// 所有的画笔换成offG
		super.paint(offG);

		Graphics2D g2d = (Graphics2D) offG;
		offG.setColor(Color.black);
		g2d.setStroke(new BasicStroke(5));
		offG.drawRect(SnakeContext.WALL_X, SnakeContext.WALL_Y,
				SnakeContext.SQUARE_SIZE, SnakeContext.SQUARE_SIZE);
		g2d.setStroke(new BasicStroke(1));
		snake.draw(offG);
		egg.draw(offG);

		g.drawImage(offImage, 0, 0, null);
	}
	
	/**
	 * main方法 窗口可见
	 * @param args
	 */
	public static void main(String[] args) {
		new SnakeFrame().setVisible(true);
	}
}


2.Snake部分

package com.lovo.snake;

import java.awt.Graphics;
import java.util.LinkedList;

/**
 * 类:蛇
 * @author Abe 属性:X Y 坐标
 */
public class Snake {
	private Direction dir = Direction.RIGHT;
	private LinkedList<SnakeNode> list = new LinkedList<SnakeNode>();
	
	/**
	 * 构造器
	 */
	public Snake(){
		for (int i = 0; i < SnakeContext.SNAKE_LENGTH; i++) {
			list.add(new SnakeNode(SnakeContext.SNAKE_X , SnakeContext.SNAKE_Y + i * SnakeContext.SNAKE_SIZE));
		}
	}
	
	/**
	 * 方法:改变方向
	 * @param newDir
	 */
	public void changeDir(Direction newDir) {
		if (!((dir == Direction.LEFT && newDir == Direction.RIGHT)
				|| (dir == Direction.RIGHT && newDir == Direction.LEFT)
				|| (dir == Direction.UP && newDir == Direction.DOWN) 
				|| (dir == Direction.DOWN && newDir == Direction.UP))) {
			dir = newDir;
		}
	}
	/**
	 * 方法:获得现在方向
	 * @return
	 */
	public Direction getDir() {
		return dir;
	}
	/**
	 * 获得蛇头
	 */
	public SnakeNode getHead(){
		return list.get(0);
	}
	/**
	 * 获得长度
	 * @return
	 */
	public int getLength(){
		return list.size();
	}
	/**
	 * 方法:移动
	 */
	public void move() {
		SnakeNode head = getHead();
		int x = head.getX();
		int y = head.getY();
		switch(dir){
		case UP: y -= SnakeContext.SPEED;break;
		case DOWN: y += SnakeContext.SPEED;break;
		case LEFT: x -= SnakeContext.SPEED;break;
		case RIGHT: x += SnakeContext.SPEED;break;
		}
		list.addFirst(new SnakeNode(x, y));
	}
	/**
	 * 方法:移出最后一个
	 */
	public void remove(){
		list.removeLast();
	}
	
	/**
	 * 方法:绘制蛇身上有节点
	 */
	public void draw(Graphics g){
		for(SnakeNode tempNode : list){
			tempNode.draw(g);
		}
	}
	/**
	 * 吃蛋
	 * @return
	 */
	public boolean eatEgg(Egg egg){
		SnakeNode head = getHead();
		return head.getX() == egg.getX() && head.getY() == egg.getY();
	}
	public LinkedList<SnakeNode> getList() {
		return list;
	}
}

3.Dirction方向枚举

package com.lovo.snake;
/**
 * 枚举:上下左右
 * @author Abe
 */
public enum Direction {
	UP,DOWN,LEFT,RIGHT
}

4.
package com.lovo.snake;

import java.awt.Color;
import java.awt.Graphics;
/**
 * 类:单节的蛇
 * @author Abe
 *
 */
public class SnakeNode {
	private int x;
	private int y;
	private int size = SnakeContext.SNAKE_SIZE;
	
	/**
	 * 构造器
	 * @param x
	 * @param y
	 */
	public SnakeNode(int x, int y) {
		this.x = x;
		this.y = y;
	}

	/**
	 * 获得蛇 节点横纵坐标
	 * 
	 * @return
	 */
	public int getX() {
		return x;
	}
	public int getY() {
		return y;
	}

	/**
	 * 方法:绘制蛇身上有节点
	 */
	public void draw(Graphics g) {
		g.setColor(Color.green);
		g.fillRect(x, y, size, size);
		g.setColor(Color.black);
		g.drawRect(x, y, size, size);
	}
}

5.Egg 可以吃的蛋蛋 呵呵

package com.lovo.snake;

import java.awt.Color;
import java.awt.Graphics;
/**
 * 蛋
 * @author Abe
 */
public class Egg {
	private int x, y;
	private int size = SnakeContext.EGG_SIZE;
	
	/**
	 * 构造器:将中间的游戏进行面板等分,在节点上随机位置出现Egg
	 */
	public Egg() {
		x = ((int) (Math.random() * (SnakeContext.SQUARE_SIZE / SnakeContext.SNAKE_SIZE))
				* SnakeContext.SNAKE_SIZE + (SnakeContext.WALL_X));
		y = ((int) (Math.random() * (SnakeContext.SQUARE_SIZE / SnakeContext.SNAKE_SIZE))
				* SnakeContext.SNAKE_SIZE + (SnakeContext.WALL_Y));
	}
	
	/**
	 * 绘制蛋蛋
	 * @param g
	 */
	public void draw(Graphics g) {
		g.setColor(Color.orange);
		g.fillOval(x, y, size, size);
	}

	/**
	 * 获得蛋蛋的横纵坐标
	 * @return
	 */
	public int getX() {
		return x;
	}
	public int getY() {
		return y;
	}
}

6.硬代码的去除

package com.lovo.snake;
/**
 * 类:硬代码数据提出专门编写一类 方便修改
 * @author Abe
 *
 */
public class SnakeContext {
	/**
	 * 蛇的大小
	 */
	public static final int SNAKE_SIZE = 25;
	/**
	 *  蛋的大小
	 */
	public static final int EGG_SIZE = SNAKE_SIZE;
	/**
	 * 蛇的长度
	 */
	public static final int SNAKE_LENGTH = 5;
	/**
	 * 蛇的初始位置
	 * 要人为计算好初始位置,处于节点上,不然没法吃蛋。
	 * 如果愿意,也可以将XY坐标通过运算强制转到节点上,这只是数学问题了,懒得做了。
	 * 具体还是: X / 单份长度 * 单份长度 + 初始位置
	 */
	public static final int SNAKE_X = 250;
	public static final int SNAKE_Y = 250;
	/**
	 * 蛇的初始速度
	 */
	public static final int SPEED = SNAKE_SIZE;
	/**
	 * 游戏窗口大小
	 */
	public static final int  GAME_SIZE = 600;
	/**
	 * 游戏场地大小
	 */
	public static final int SQUARE_SIZE = 500;
	/**
	 * 刷新周期
	 */
	public static final int INTERVAL = 300;
	/**
	 * 围墙起点坐标
	 */
	public static final int WALL_X = 50;
	public static final int WALL_Y = 50;
}

到此为止游戏制作完成,而且能够完美运行。不过尚有一个小BUG 手速快的朋友找找看 呵呵~~O(∩_∩)O~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值