2014.11.17贪吃蛇------老师的修改而来

本文详细介绍了贪吃蛇游戏的开发过程,包括游戏规则、蛇的移动逻辑、蛋的生成与碰撞检测、游戏界面的设计与实现等核心部分。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  1. <span style="font-size:18px;">package com.lovo;
    /**
     * 方向(枚举类)
     * @author hechao
     *
     */
    public enum Direction {
    	UP, DOWN, LEFT, RIGHT
    }</span>
  2. <span style="font-size:18px;">package com.lovo;
    
    import java.awt.Color;
    import java.awt.Graphics;
    
    public class Egg {
    	private int x, y;
    	private int size = GameContext.EGG_SIZE;
    
    	public Egg() {
    		int minX = GameContext.WALL_X / 20;
    		int maxX = (GameContext.SQUARE_SIZE - GameContext.EGG_SIZE) / 20;
    		x = (int) (Math.random() * maxX + minX) * 20;
    		int minY = GameContext.WALL_Y / 20;
    		int maxY = maxX;
    		y = (int) (Math.random() * maxY + minY) * 20;
    	}
    
    	public int getX() {
    		return x;
    	}
    
    	public int getY() {
    		return y;
    	}
    
    	public void draw(Graphics g) {
    		g.setColor(Color.ORANGE);
    		g.fillOval(x, y, size, size);
    	}
    
    }
    </span>


  3. <span style="font-size:18px;">package com.lovo;
    
    public class GameContext {
    	
    	/**
    	 * 蛇的长度
    	 */
    	public static final int SNAKE_LENGTH = 1;
    	/**
    	 * 蛇头初始位置的横坐标
    	 */
    	public static final int SNAKE_X = 260;
    	/**
    	 * 蛇头初始位置的纵坐标
    	 */
    	public static final int SNAKE_Y = 280;
    	/**
    	 * 蛇节点的大小
    	 */
    	public static final int SNAKE_SIZE = 20;
    	/**
    	 * 游戏窗口的大小
    	 */
    	public static final int GAME_SIZE = 580;
    	/**
    	 * 游戏场地的大小
    	 */
    	public static final int SQUARE_SIZE = 500;
    	/**
    	 * 刷新周期
    	 */
    	public static final int INTERVAL = 200;
    	/**
    	 * 围墙起点的横坐标
    	 */
    	public static final int WALL_X = 40;
    	/**
    	 * 围墙起点的纵坐标
    	 */
    	public static final int WALL_Y = 40;
    	/**
    	 * 围墙厚度
    	 */
    	public static final int WALL_WIDTH = 5;
    	/**
    	 * 蛋的大小
    	 */
    	public static final int EGG_SIZE = SNAKE_SIZE;
    	
    }
    </span>


  4. <pre name="code" class="java">package com.lovo;
    
    import java.awt.BasicStroke;
    import java.awt.Color;
    import java.awt.Graphics;
    import java.awt.Graphics2D;
    import java.awt.Image;
    import java.awt.Stroke;
    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 java.util.LinkedList;
    
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.Timer;
    
    @SuppressWarnings("serial")
    public class GameFrame extends JFrame {
    	private Image offImage = new BufferedImage(GameContext.GAME_SIZE, GameContext.GAME_SIZE, 1);
    	private Timer timer = null;
    	private int score;
    	private Snake snake = new Snake();		// 创建蛇的对象
    	private Egg egg = new Egg();			// 创建蛋的对象
    	private JLabel scoreLable;
    	private LinkedList<SnakeNode> list = snake.getList(); 
    	
    	public GameFrame() {
    		this.setTitle("贪吃蛇");
    		this.setSize(GameContext.GAME_SIZE, GameContext.GAME_SIZE);
    		this.setResizable(false);
    		this.setLocationRelativeTo(null);
    		this.setDefaultCloseOperation(EXIT_ON_CLOSE);
    		this.setLayout(null);
    		
    		this.addKeyListener(new KeyAdapter() {
    
    			@Override
    			public void keyPressed(KeyEvent e) {
    				Direction newDir = snake.getDir();
    				switch(e.getKeyCode()) {
    				case KeyEvent.VK_W:	//上
    					newDir = Direction.UP;
    					break;
    				case KeyEvent.VK_S:	// 下
    					newDir = Direction.DOWN;
    					break;
    				case KeyEvent.VK_A:	// 左
    					newDir = Direction.LEFT;
    					break;
    				case KeyEvent.VK_D:	// 右
    					newDir = Direction.RIGHT;
    					break;
    				case KeyEvent.VK_F2:
    					resetGame();
    					break;
    				}
    				if(snake.getDir() != newDir) {	// 如果新方向不同于蛇原来的方向
    					snake.changeDir(newDir);	// 调用蛇的changeDir方法修改蛇的方向
    				}
    			}
    			/**
    			 * 重置游戏
    			 */
    			public void resetGame(){
    				score = 0;
    				list.clear();
    				snake.resetSnake();
    				timer.start();
    				egg = new Egg();
    				repaint();
    			}
    		});
    		
    		
    		timer = new Timer(GameContext.INTERVAL, new ActionListener() {
    			
    			@Override
    			public void actionPerformed(ActionEvent e) {
    				snake.move();	// 调用蛇的move方法让蛇移动
    				if(snake.eatEgg(egg)) {	// 吃到蛋
    					snake.grow();		// 调用蛇的grow方法让蛇变长
    					score++;
    					egg = new Egg();	// 重新创建一颗蛋
    				}
    				SnakeNode head = snake.getHead();
    				int x = head.getX();
    				int y = head.getY();
    				for(int i = 1; i < list.size(); i++){
    					SnakeNode sn = list.get(i);
    					if(sn.getX() == x && sn.getY() == y){
    						timer.stop();
    					}
    				}
    				if(x < GameContext.WALL_X || 
    						x > GameContext.WALL_X + GameContext.SQUARE_SIZE - GameContext.SNAKE_SIZE ||
    						y < GameContext.WALL_Y || 
    						y > GameContext.WALL_Y + GameContext.SQUARE_SIZE - GameContext.SNAKE_SIZE) {
    					timer.stop();
    				}
    				else {					
    					repaint();
    				}
    			}
    		});
    		scoreLable = new JLabel();
    		scoreLable.setBounds(50, 530, 100, 15);
    		GameFrame.this.add(scoreLable);	
    		timer.start();
    		
    	}
    	
    	@Override
    	public void paint(Graphics g) {	// 使用双缓冲方式消除窗口闪烁(见下面步骤1-2-3)
    		// 1. 获得内存中图像的画笔
    		Graphics offG = offImage.getGraphics();	
    		
    		// 2. 用offG在内存中绘制窗口上的所有内容
    		super.paint(offG);					// 消除残影
    		Graphics2D g2d = (Graphics2D) offG;	// 将Graphics转成其子类型Graphics2D并设置粗细
    		Stroke oldStroke = g2d.getStroke();	// 记录画笔粗细(保存现场)
    		g2d.setStroke(new BasicStroke(GameContext.WALL_WIDTH));	// 将画笔加粗
    		offG.setColor(Color.BLACK);			// 设置画笔为黑色
    		int x = GameContext.WALL_X, y = GameContext.WALL_Y;
    		offG.drawRect(x, y, GameContext.SQUARE_SIZE, GameContext.SQUARE_SIZE);	// 绘制围墙
    		g2d.setStroke(oldStroke);			// 还原画笔粗细(恢复现场)
    		
    		snake.draw(offG);					// 调用蛇的draw方法绘制蛇 
    		egg.draw(offG);						// 调用蛋的draw方法绘制蛋
    		
    		// 3. 将内存中绘制好的图直接画到窗口上(双缓冲)
    		g.drawImage(offImage, 0, 0, null);	// 第二个和第三个参数是绘图的位置
    		scoreLable.setText("得分:" + score);
    	}
    }
    


    
    
  5. <span style="font-size:18px;">package com.lovo;
    
    class GameRunner {
    
    	public static void main(String[] args) {
    		new GameFrame().setVisible(true);
    	}
    }
    </span>


  6. <pre name="code" class="java">package com.lovo;
    
    import java.awt.Graphics;
    import java.util.LinkedList;
    
    /**
     * 蛇
     * @author 何超 
     *
     */
    public class Snake {
    	private Direction dir = Direction.LEFT;								// 方向
    	private LinkedList<SnakeNode> list = new LinkedList<SnakeNode>();	// 装蛇的所有节点的容器(链表)
    	
    	/**
    	 * 构造器
    	 */
    	public Snake() {
    		// 初始化5个节点
    		for (int i = 0; i < GameContext.SNAKE_LENGTH; i++) {
    			list.add(new SnakeNode(GameContext.SNAKE_X + i * GameContext.SNAKE_SIZE, GameContext.SNAKE_Y));
    		}
    	}
    	/**
    	 * 获得蛇结点容器
    	 * @return 蛇结点容器
    	 */
    	public LinkedList<SnakeNode> getList(){
    		return list;
    	}
    	/**
    	 * 改变方向
    	 * @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;
    		}
    	}
    	
    	/**
    	 * 获得蛇前进的方向
    	 */
    	public Direction getDir() {
    		return dir;
    	}
    	
    	/**
    	 * 获得蛇头
    	 */
    	public SnakeNode getHead() {
    		return list.get(0);	// 容器中的第一个节点就是蛇头
    	}
    	
    	/**
    	 * 移动
    	 */
    	public void move() {
    		grow();
    		list.removeLast();			// 尾巴删一个节点
    	}
    	
    	/**
    	 * 吃蛋
    	 * @param egg 蛋
    	 * @return 吃到蛋返回true否则返回false
    	 */
    	public boolean eatEgg(Egg egg) {
    		SnakeNode head = getHead();
    		return head.getX() == egg.getX() && head.getY() == egg.getY();
    	}
    	
    	/**
    	 * 长长一节
    	 */
    	public void grow() {
    		SnakeNode head = getHead();
    		int x = head.getX(), y = head.getY();
    		int size = GameContext.SNAKE_SIZE;
    		switch(dir) {
    		case UP:
    			y -= size;
    			break;
    		case DOWN:
    			y += size;
    			break;
    		case LEFT:
    			x -= size;
    			break;
    		case RIGHT:
    			x += size;
    			break;
    		}
    		SnakeNode newHead = new SnakeNode(x, y);	// 创建新的蛇头节点
    		list.addFirst(newHead);		// 头上加一个节点
    	}
    	/**
    	 * 重置
    	 */
    	public void resetSnake() {
    		// 初始化5个节点
    		for (int i = 0; i < GameContext.SNAKE_LENGTH; i++) {
    			list.add(new SnakeNode(GameContext.SNAKE_X + i * GameContext.SNAKE_SIZE, GameContext.SNAKE_Y));
    		}
    	}
    	/**
    	 * 绘制蛇
    	 */
    	public void draw(Graphics g) {
    		// 绘制蛇身上的每个节点
    		for(SnakeNode node : list) {
    			node.draw(g);
    		}
    	}
    	
    }
    


    
    
  7. <span style="font-size:18px;">package com.lovo;
    
    import java.awt.Color;
    import java.awt.Graphics;
    
    /**
     * 蛇身上的节点
     * @author 骆昊
     *
     */
    public class SnakeNode {
    	private int x, y;
    	private int size = GameContext.SNAKE_SIZE;
    	
    	/**
    	 * 构造器
    	 */
    	public SnakeNode(int x, int y) {
    		this.x = x;
    		this.y = y;
    	}
    	
    	/**
    	 * 蛇节点的横坐标
    	 */
    	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);
    	}
    }
    </span>


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值