11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 |
package game.mysanek.entities; |
import game.mysanek.listener.SnakeListener; |
import game.mysanek.util.Global; |
import java.awt.Color; |
import java.awt.Graphics; |
import java.awt.Point; |
import java.util.HashSet; |
import java.util.LinkedList; |
import java.util.Set; |
public class Snake { |
public static final int UP= - 1 ; |
public static final int DOWN= 1 ; |
public static final int LEFT= 2 ; |
public static final int RIGHT= - 2 ; |
|
//设置两个变量来存放原来的蛇头坐标--和--键盘输入的最后一次控制蛇的方向 |
private int oldDirection, newDirection; |
//这个变量用来存放蛇的尾部,当蛇吃掉食物后身体边长。则在蛇的身体添加body.addLast(oldTail),节点的位置坐标 |
private Point oldTail; |
|
//存放蛇的节点位置坐标。 |
private LinkedList<Point> body = new LinkedList<Point>(); |
private Set<SnakeListener> listeners = new HashSet<SnakeListener>(); |
|
public boolean life; //这个变量用来判断蛇是否死亡(结速进程) |
|
/** |
* 构造方法初始化蛇的body身体、蛇头oldDirection和newDirection运行的方向 |
*/ |
public Snake(){ |
init(); |
} |
public void init(){ |
//取一个节点作为蛇头的位置坐标 |
int x=Global.WIDTH/ 2 ; |
int y=Global.HEIGHt/ 2 ; |
//蛇的长度初始化为--5个节点的长度 |
for ( int i= 0 ; i< 5 ; i++){ |
body.addLast( new Point(x--, y)); |
} |
oldDirection = newDirection = RIGHT; //蛇头方向初始化 |
life= true ; //蛇是活的, |
} |
|
|
/** |
* 蛇移动 |
*/ |
public void move(){ |
System.out.println( "Snake's move" ); |
|
//1.去尾 |
oldTail=body.removeLast(); //记录每次去尾时,尾巴的x,y坐标 |
|
//获取蛇的蛇头坐标想x,y |
int x = body.getFirst().x; |
int y = body.getFirst().y; |
|
//当蛇的原来方向oldDirection和键盘输入的最后一个方向newDirection不相反时,再传递蛇最新的方式值 |
if (!(oldDirection + newDirection == 0 )){ |
oldDirection = newDirection; |
} |
|
switch (oldDirection){ |
case UP: |
y--; |
if (y < 0 ){ //使蛇在GamePanel的范围内运动 |
y =Global.HEIGHt - 1 ; |
} |
break ; |
case DOWN: |
y++; |
if ( y > Global.HEIGHt- 1 ){ //使蛇在GamePanel的范围内运动 |
y = 0 ; |
} |
break ; |
case LEFT: |
x--; |
if ( x< 0 ){ //使蛇在GamePanel的范围内运动 |
x=Global.WIDTH- 1 ; |
} |
break ; |
case RIGHT: |
x++; |
if (x> Global.WIDTH- 1 ){ //使蛇在GamePanel的范围内运动 |
x= 0 ; |
} |
break ; |
} |
//蛇变化方向后,蛇头的坐标位置 |
Point newHead = new Point(x, y); |
|
//2.加头 |
body.addFirst(newHead); |
|
} |
|
/** |
* 蛇改变方向 |
* @param direction |
*/ |
public void changeDirection( int direction){ |
newDirection=direction; |
} |
|
/** |
* 蛇吃食物 |
* 蛇吃到食物后身体变长 |
*/ |
public void eatFood(){ |
System.out.println( "Snake's eatFood" ); |
|
body.addLast(oldTail); //蛇吃到食物后身体变长 |
|
} |
|
/** |
* 判断蛇是否吃到了自己的身体,吃到身体蛇死亡(即结束SankeDriver线程) |
* @return |
*/ |
public boolean isEatBody(){ |
System.out.println( "Sanek's isEatBody" ); |
|
//i=0表示蛇头,所以i要从1,2,3。。。开始 |
for ( int i= 1 ; i<body.size(); i++){ |
//判断蛇头与身体的其中一个坐标是否重贴 |
if (body.get(i).equals( this .getHead())){ |
return true ; |
} |
} |
return false ; |
} |
|
|
/** |
* 绘制蛇的图像 |
* @param g |
*/ |
public void drawMe(Graphics g){ |
System.out.println( "Snake's drawMe" ); |
|
g.setColor(Color.BLUE); //设置蛇头颜色 |
for (Point p :body){ |
g.fill3DRect(p.x * Global.cell_size, p.y * Global.cell_size, |
Global.cell_size, Global.cell_size, true ); |
|
if (p==body.getFirst()){ //设置蛇的身体颜色 |
g.setColor(Color.MAGENTA); |
} |
} |
} |
|
//获取蛇头方向 |
public Point getHead(){ |
return body.getFirst(); |
|
} |
|
/** |
* 蛇死亡,即结束进程的方法 |
*/ |
public void die(){ |
life= false ; |
} |
|
|
|
/** |
* SnakeDirver类,控制蛇的进程 |
* @author Administrator |
* |
*/ |
public class SnakeDriver implements Runnable{ |
@Override |
public void run() { |
// TODO 自动生成的方法存根 |
while (life){ |
move(); //蛇运动 |
//绘制图像--图像显示 |
for (SnakeListener l : listeners){ |
l.snakeMoved(); |
} |
try { |
//设置线程休息时间 |
Thread.sleep( 200 ); |
} catch (InterruptedException e) { |
// TODO 自动生成的 catch 块 |
e.printStackTrace(); |
} |
System.out.println( "##########################################" ); |
} |
} |
|
} |
|
/** |
* start()方法是启动线程的方法 |
*/ |
public void start(){ |
new Thread( new SnakeDriver()).start(); |
} |
|
/** |
* 往listens中添加 Snake类、Food类、Ground类、GamePnael类的-------类地址 |
* @param l |
*/ |
public void addSnakeListener(SnakeListener l){ |
if (l != null ){ |
this .listeners.add(l); |
} |
} |
|
} |
2222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222 |
package game.mysanek.entities; |
import game.mysanek.util.Global; |
import java.awt.Color; |
import java.awt.Graphics; |
import java.awt.Point; |
public class Food extends Point{ |
|
//设置食物的x,y坐标 |
public void newFood(Point p){ //生成食物 |
this .setLocation(p); //设置食物的坐标 |
System.out.println( "-------------" +p); |
} |
|
//比坐标---当蛇头的坐标与食物的坐标重合,则表示食物被蛇吃掉了 |
public boolean isSnakeEatFood(Snake snake){ |
System.out.println( "Food's isSnakeEatFood" ); |
return this .equals(snake.getHead()); |
// return false; |
} |
|
|
/** |
* 绘制食物的图像 |
* @param g |
*/ |
public void drawMe(Graphics g){ |
System.out.println( "Food's drawMe" ); |
|
g.setColor(Color.CYAN); |
g.fill3DRect(x*Global.cell_size, y*Global.cell_size, |
Global.cell_size, Global.cell_size, true ); |
} |
} |
333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333 |
package game.mysanek.entities; |
import java.awt.Color; |
import java.awt.Graphics; |
import java.awt.Point; |
import java.util.Random; |
import game.mysanek.util.Global; |
public class Ground { |
//用一个二维数组来存放rocks(障碍物)的坐标 |
//大小为GamePanel的长宽的小格子数WIDTH和HEIGHT; |
private int [][] rocks= new int [Global.WIDTH][Global.HEIGHt]; |
|
public Ground(){ |
for ( int x= 0 ; x<Global.WIDTH; x++){ |
//第一行和最后一行---为rocks(障碍物) |
rocks[x][ 0 ]= 1 ; |
rocks[x][Global.HEIGHt- 1 ]= 1 ; |
} |
} |
|
//随机生成---newFood()食物的x,y坐标 |
//而且不能使newFood(食物)的坐标和rocks(障碍物)坐标重合 |
public Point getPoint(){ |
Random random = new Random(); |
int x,y; |
//newFood的坐标和rocks坐标重叠,则继续生成新的坐标---直到不重合 |
do { |
x=random.nextInt(Global.WIDTH); |
y=random.nextInt(Global.HEIGHt); |
} while (rocks[x][y]== 1 ); |
return new Point(x,y); |
|
} |
|
/** |
* 蛇是否吃到石头(障碍物) |
* @param snake |
* @return |
*/ |
public boolean isSnakeEatRock(Snake snake){ |
System.out.println( "Ground's isSnakeEatRock" ); |
|
//判断snake(蛇)是否吃到了rocks(障碍物) |
for ( int x= 0 ; x<Global.WIDTH; x++){ |
for ( int y= 0 ; y<Global.HEIGHt; y++){ |
if (rocks[x][y]== 1 && |
(x==snake.getHead().x && y==snake.getHead().y) ){ //getHead()方法可以获得蛇头的坐标 |
return true ; |
} |
} |
} |
|
return false ; |
} |
|
|
/** |
* 当rocks[x][y]==1时,绘制石头(障碍物) |
* @param g |
*/ |
public void drawMe(Graphics g){ |
System.out.println( "Ground's drawMe" ); |
|
g.setColor(Color.gray); |
for ( int x= 0 ; x<Global.WIDTH; x++){ |
for ( int y= 0 ; y<Global.HEIGHt; y++){ |
if (rocks[x][y] == 1 ){ |
g.fill3DRect(x*Global.cell_size, y*Global.cell_size, |
Global.cell_size, Global.cell_size, true ); |
} |
} |
} |
|
} |
} |
1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 |
package game.mysanek.view; |
import game.mysanek.entities.Food; |
import game.mysanek.entities.Ground; |
import game.mysanek.entities.Snake; |
import game.mysanek.util.Global; |
import java.awt.Color; |
import java.awt.Graphics; |
import javax.swing.JPanel; |
public class GamePanel extends JPanel{ |
private Snake snake; |
private Food food; |
private Ground ground; |
|
|
/** |
* 将蛇、食物、石头(障碍物)显示出来 |
*snake、food、ground---传递的都是Snaek类、Food类、Ground类的***地址。 |
* @param snake 传递地址 |
* @param food |
* @param ground |
*/ |
public void display(Snake snake, Food food, Ground ground){ //传递各个class的地址 |
System.out.println( "GamePanel's display" ); |
this .snake=snake; |
this .food=food; |
this .ground=ground; |
|
//绘图----调用下方的--画图功能 |
this .repaint(); |
} |
@Override |
protected void paintComponent(Graphics g) { |
// TODO 自动生成的方法存根 |
//显示 |
g.setColor( new Color( 0xcfcfcf )); |
//绘制一个GamePnanl大小的--矩形--遮盖掉前一个时间的蛇、食物、石头(障碍物),---相当于橡皮差 |
g.fillRect( 0 , 0 , Global.WIDTH * Global.cell_size, |
Global.HEIGHt *Global.cell_size); |
|
//当snake、food、ground字段----都有对应的Snake类、Food类、Ground类的地址时---画图 |
if (snake != null && food != null && ground != null ){ |
this .ground.drawMe(g); |
this .snake.drawMe(g); |
this .food.drawMe(g); |
} |
|
} |
} |
1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 |
package game.mysanek.controller; |
import game.mysanek.entities.Food; |
import game.mysanek.entities.Ground; |
import game.mysanek.entities.Snake; |
import game.mysanek.listener.SnakeListener; |
import game.mysanek.util.Global; |
import game.mysanek.view.GamePanel; |
import java.awt.Point; |
import java.awt.event.KeyAdapter; |
import java.awt.event.KeyEvent; |
import java.util.Random; |
public class Controller extends KeyAdapter implements SnakeListener{ |
|
//------这时的snake只是个字段,它的值为--null。 没有Snake类的地址 |
private Snake snake; |
private Food food; |
private Ground ground; |
private GamePanel gamePanel; |
|
|
/** |
* Controller 构造方法----传递Snaek类、Food类、Ground类、GamePanel类--的***地址。 |
* @param snake |
* @param food |
* @param ground |
* @param gamePanel |
*/ |
public Controller(Snake snake, Food food, Ground ground, GamePanel gamePanel) { |
//传递各个class的地址 |
this .snake = snake; |
this .food = food; |
this .ground = ground; |
this .gamePanel = gamePanel; |
} |
|
/** |
* 键盘控制-------实现键盘控制-蛇-的方向移动。 |
*/ |
@Override |
public void keyPressed(KeyEvent e) { |
// TODO 自动生成的方法存根 |
switch (e.getKeyCode()){ |
case KeyEvent.VK_UP: |
snake.changeDirection(Snake.UP); |
break ; |
case KeyEvent.VK_DOWN: |
snake.changeDirection(Snake.DOWN); |
break ; |
case KeyEvent.VK_LEFT: |
snake.changeDirection(Snake.LEFT); |
break ; |
case KeyEvent.VK_RIGHT: |
snake.changeDirection(Snake.RIGHT); |
break ; |
} |
} |
|
/** |
* 实现SnakeLisener接口中的方法。 |
*/ |
@Override |
public void snakeMoved() { |
|
//判断食物是否被蛇吃掉,吃掉后产生新的---新食物 |
if (food.isSnakeEatFood(snake)){ |
snake.eatFood(); //蛇吃掉食物 |
food.newFood(ground.getPoint()); //产生新的食物 |
} |
|
//判断蛇头的位置与石头的位置是否重合---蛇是否吃到石头 |
if (ground.isSnakeEatRock(snake)){ |
snake.die(); //蛇蛇死亡---结束SnakeDriver线程 |
} |
|
//判断蛇是否吃到了自己的身体 |
if (snake.isEatBody()){ |
snake.die(); //蛇蛇死亡---结束SnakeDriver线程 |
} |
|
|
//绘图-------在GamePanel的面板上绘制蛇、食物、石头(障碍物)。 |
//snake、food、ground---传递的都是Snaek类、Food类、Ground类的***地址。 |
gamePanel.display(snake, food, ground); //传递各个class的地址 |
|
} |
|
// //随机生成---食物的x,y坐标 |
// public Point getPoint(){ |
// Random random =new Random(); |
// int x=random.nextInt(Global.WIDTH); |
// int y=random.nextInt(Global.HEIGHt); |
// return new Point(x,y); |
// } |
/** |
* 将Snake类中的start()方法,放在在Controller中 |
* 逻辑控制 |
*/ |
public void newGame(){ |
snake.start(); |
food.newFood(ground.getPoint()); |
} |
} |
1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 |
package game.mysanek.listener; |
/** |
* 设置一个借口----用来存放(Snake snake, Food food, Ground ground) 的类的地址 |
* @author Administrator |
* |
*/ |
public interface SnakeListener { |
|
public void snakeMoved(); |
} |
111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 |
package game.mysanek.util; |
public class Global { |
//贪吃蛇中的每个小方格的边长--20 |
public static final int cell_size= 20 ; |
//设置游戏界面GameJPanel的大小 |
public static final int WIDTH= 40 ; //宽度为40个小方格 |
public static final int HEIGHt = 25 ; //高度为25个小方格 |
} |
11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 |
package game.mysanek.game; |
import java.awt.BorderLayout; |
import game.mysanek.controller.Controller; |
import game.mysanek.entities.Food; |
import game.mysanek.entities.Ground; |
import game.mysanek.entities.Snake; |
import game.mysanek.util.Global; |
import game.mysanek.view.GamePanel; |
import javax.swing.JFrame; |
public class Game { |
|
public static void main(String[] args) { |
Snake snake = new Snake(); |
Food food = new Food(); |
Ground ground = new Ground(); |
GamePanel gamePanel = new GamePanel(); |
|
//传递各个class的地址 |
Controller controller = new Controller(snake, food, ground, gamePanel); |
|
JFrame frame = new JFrame( "贪吃蛇游戏" ); |
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); |
gamePanel.setSize(Global.WIDTH * Global.cell_size, |
Global.HEIGHt * Global.cell_size); |
frame.setSize(Global.WIDTH * Global.cell_size + 10 , |
Global.HEIGHt * Global.cell_size+ 35 ); |
frame.add(gamePanel, BorderLayout.CENTER); |
frame.setLocationRelativeTo( null ); |
|
gamePanel.addKeyListener(controller); |
snake.addSnakeListener(controller); |
|
frame.addKeyListener(controller); |
|
frame.setVisible( true ); |
controller.newGame(); |
} |
} |
中级程序员
by: 陆痴 发表于:2017-03-11 18:13:42 顶(3) | 踩(0) 回复
回复评论