您的位置:首页 > 编程语言 > Java开发

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

2014-11-17 23:37 381 查看
主要是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;
/**
* 刷新周期
*/
pub
a170
lic static final int INTERVAL = 300;
/**
* 围墙起点坐标
*/
public static final int WALL_X = 50;
public static final int WALL_Y = 50;
}


到此为止游戏制作完成,而且能够完美运行。不过尚有一个小BUG 手速快的朋友找找看 呵呵~~O(∩_∩)O~
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: