贪吃蛇(图形版)

分析里面的有几个事物:
1. 地图
2. 蛇
3. 食物

了解游戏规则: 
1.蛇初始化的时候是三个节点,而且一开始蛇是出现在地图的中间位置。
2. 蛇吃到东西会长长一节。 
3. 蛇咬到自己会死,蛇撞墙也会死。
4. 食物是随机生成的,食物不能长在石头上,食物可以长在蛇身上。
效果如下:

代码如下:
package com.cn.snake_Version2;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.LinkedList;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import com.cn.utils.FrameUtil;

public class SnakeGame extends JPanel{
	/**
	 * 地图的宽(列数)
	 */
	public static final int WIDTH = 30;
	/**
	 * 地图的高(行数)
	 */
	public static final int HEIGHT = 20;
	/**
	 * 格子的宽
	 */
	public static final int CELLWIDTH = 20;
	/**
	 * 格子的高
	 */
	public static final int CELLHEIGHT = 20;
	/**
	 * 地图
	 */
	private boolean[][] background= new boolean[HEIGHT][WIDTH];
	/**
	 * 使用集合保存蛇节点的所有信息
	 */
	LinkedList<Point> snake = new LinkedList<Point>();
	//使用四个常量表示四个方向
	/**
	 * 蛇向上走
	 */
	public static final int UP_DIRECTION = 1;
	/**
	 * 蛇向下走
	 */
	public static final int DOWN_DIRECTION = -1;
	/**
	 * 蛇向左走
	 */
	public static final int LEFT_DIRECTION = 2;
	/**
	 * 蛇向右走
	 */
	public static final int RIGHT_DIRECTION = -2;
	/**
	 * 蛇当前的移动方向
	 */
	int currentDirection = -2;  //默认蛇向右行走
	
	/**
	 * 蛇能否移动标识
	 */
	static boolean canMoving = true;  //默认蛇能移动
	
	/**
	 * 定义标识,判断游戏是否结束,蛇是否撞到障碍物,或者吃到自己,默认没有死亡
	 */
	static boolean isDead = false;
	/**
	 * 食物(坐标)
	 */
	Point food;
	
	/**
	 * 定义一个方法,初始化地图
	 */
	public void initBackground(){
		//把地图,食物,障碍物等信息储存在二维数组中
		for(int row=0; row<SnakeGame.HEIGHT; row++){
			for(int col=0; col<SnakeGame.WIDTH; col++){
				if(row == 0 || row == SnakeGame.HEIGHT-1 ){//第一行,最后一行
					background[row][col] = true;
				}
			}
		}
	}
	/**
	 *初始化蛇
	 */
	public void initSnake(){
		//蛇开始时候的中心位置
		int x = SnakeGame.WIDTH>>1; //地图的宽度除以2
			int y = SnakeGame.HEIGHT>>1;//地图的高度除以2
			snake.addFirst(new Point(x-1, y)); //蛇尾
			snake.addFirst(new Point(x, y)); //蛇的中心
			snake.addFirst(new Point(x+1, y));//蛇头 
	}
	/**
	 * 改变当前方向的方法
	 * @param newDirection
	 */
	public void changeDirection(int newDirection){
		//判断新方向是否与当前方向是否是相反方向,不相反才允许其改变
		if(newDirection + currentDirection != 0){
			this.currentDirection = newDirection;
			canMoving = true;
		}else{//新方向是否与当前方向相反,蛇不能移动
			canMoving = false;
		}
	}
	
	/**
	 * 蛇吃食物
	 * @return
	 */
	public boolean eatFood(){
		//获取到原来的蛇头
		Point head = snake.getFirst();
		if(head.equals(food)){//蛇头坐标和食物坐标重合,表明吃到了食物	
			return true;
		}
		return false;
	}
	
	/**
	 * 生成食物
	 */
	public void createFood(){
		//创建一个随机数对象
		Random random = new Random();
		while(true){
			int x = random.nextInt(SnakeGame.WIDTH);
			int y = random.nextInt(SnakeGame.HEIGHT);
			if(background[y][x] != true){ //非石头的地方产生食物
				food = new Point(x, y);
				break;
			}
		}
	}
	/**
	 * 蛇移动的方法
	 * @param currentDirection
	 */
	public void move(){
		Point head = snake.getFirst();//取出原来的蛇头
		//蛇是根据当前方向移动的
		switch (currentDirection) {
		case SnakeGame.UP_DIRECTION:
			snake.addFirst(new Point(head.x, head.y-1));//添加新的蛇头
			break;
		case SnakeGame.DOWN_DIRECTION:
			snake.addFirst(new Point(head.x, head.y+1));//添加新的蛇头
			break;
		case SnakeGame.LEFT_DIRECTION:
			if(head.x == 0){
				snake.addFirst(new Point(SnakeGame.WIDTH-1, head.y));//添加新的蛇头
			}else{
				snake.addFirst(new Point(head.x-1, head.y));//添加新的蛇头
			}
			break;
		case SnakeGame.RIGHT_DIRECTION:
			if(head.x == SnakeGame.WIDTH-1){
				snake.addFirst(new Point(0, head.y));//添加新的蛇头
			}else{
				snake.addFirst(new Point(head.x+1, head.y));//添加新的蛇头
			}
			break;
		default:
			break;
		}
		
		if(eatFood()){//吃到了食物
			//重新生成食物
			createFood();
		}else{//如果没有吃到食物,删除蛇尾
			snake.removeLast();//删除蛇尾
		}
	}
	
	
	/**
	 * 判断蛇是否撞到障碍物,或者吃到自己,默认没有死亡
	 * @return
	 */
	public boolean isGameOver(){
		//获取蛇头
		Point head = snake.getFirst();
		//判断蛇头是否撞到障碍物
		if(background[head.y][head.x] == true){
			isDead = true;
		}
		//判断蛇头是否吃到自己,首先获取身体节点,判断头部坐标是否与身体某节点重合
		for(int i=1; i<snake.size(); i++){
			Point body = snake.get(i);
			if(head.equals(body)){
				isDead = true;
			}
		}
		
		return isDead;
	}
	
	@Override
	public void paint(Graphics g) {
		/**
		 * 画地图
		 */
		for(int row=0; row<SnakeGame.HEIGHT; row++){
			for(int col=0; col<SnakeGame.WIDTH; col++){
				if(background[row][col]){//石头
					g.setColor(Color.GRAY);
				}else{//空地
					g.setColor(Color.white);
				}
				//画矩形格子
				g.fill3DRect(col*CELLWIDTH, row*CELLHEIGHT, CELLWIDTH, CELLHEIGHT, true);
			}
		}
		/**
		 * 画蛇
		 */
		//取出蛇头
		Point head = snake.getFirst();
		g.setColor(Color.green);
		//先画蛇身,除了蛇头之外,其余的节点都填充蛇身
		for(int i=1; i<snake.size(); i++){
			Point body = snake.get(i);
			g.fill3DRect(body.x*CELLWIDTH, body.y*CELLHEIGHT, CELLWIDTH, CELLHEIGHT, true);
		}
		//后填蛇头,这样蛇头即使咬到了蛇身也不会覆盖蛇头。
		g.setColor(Color.RED);
		g.fill3DRect(head.x*CELLWIDTH, head.y*CELLHEIGHT, CELLWIDTH, CELLHEIGHT, true);
		
		/**
		 * 画食物
		 */
		g.setColor(Color.YELLOW);
		g.fill3DRect(food.x*CELLWIDTH, food.y*CELLHEIGHT, CELLWIDTH, CELLHEIGHT, true);
		
	}
	public static void main(String[] args) {
		final JFrame frame = new JFrame("贪吃蛇 【木丁西1012421396】");
		final SnakeGame snakeGUI = new SnakeGame();
		snakeGUI.initBackground();
		snakeGUI.initSnake();
		snakeGUI.createFood();
		frame.add(snakeGUI);
		FrameUtil.initFrame(frame, WIDTH*CELLWIDTH+17, HEIGHT*CELLHEIGHT+40);
		//给窗口添加事件监听
		frame.addKeyListener(new KeyAdapter() {
			@Override
			public void keyPressed(KeyEvent e) {
				int code = e.getKeyCode();
				switch (code) {
				case KeyEvent.VK_UP://上
					snakeGUI.changeDirection(SnakeGame.UP_DIRECTION);
					break;
				case KeyEvent.VK_DOWN://下
					snakeGUI.changeDirection(SnakeGame.DOWN_DIRECTION);
					break;
				case KeyEvent.VK_LEFT://左
					snakeGUI.changeDirection(SnakeGame.LEFT_DIRECTION);
					break;
				case KeyEvent.VK_RIGHT://右
					snakeGUI.changeDirection(SnakeGame.RIGHT_DIRECTION);
					break;
				default:
					break;
				}
				if(canMoving)//方向正确能移动
					snakeGUI.move();//移动
				isDead = snakeGUI.isGameOver();//判断游戏是否结束
				snakeGUI.repaint();//刷新,调用repaint方法的时候实际上就是调用了paint方法
				if(isDead){//死亡
					JOptionPane.showMessageDialog(frame, "游戏结束", "游戏结束提示", JOptionPane.ERROR_MESSAGE);
					System.exit(0);//退出JVM
				}
			}
		});
	}
}

游戏中用到的自定义窗体工具类: 
   
   
  1. package com.cn.utils;
  2. import java.awt.Dimension;
  3. import java.awt.Toolkit;
  4. import javax.swing.JFrame;
  5. /**
  6. * 自定义窗体工具
  7. * @author zhiyong
  8. *
  9. */
  10. public class FrameUtil {
  11. public static void initFrame(JFrame frame, int width, int height){
  12. //获取默认工具包。
  13. Toolkit toolkit = Toolkit.getDefaultToolkit();
  14. //获取屏幕大小
  15. Dimension dimension = toolkit.getScreenSize();
  16. int x = dimension.width;
  17. int y = dimension.height;
  18. //窗体位置设置在屏幕中心位置
  19. frame.setBounds((x-width)>>1, (y-height)>>1, width, height);
  20. //设置窗体可见
  21. frame.setVisible(true);
  22. //设置窗体关闭事件
  23. frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  24. }
  25. }
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值