欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

JAVA学习,2个小时写了个简单的贪吃蛇

程序员文章站 2022-04-09 10:51:27
...

一个非常简单的贪吃蛇

 

共4个类:

Main---------------入口类

GameCanvas----主体类

Snake-------------蛇

Food--------------食物

 

截图:


JAVA学习,2个小时写了个简单的贪吃蛇
            
    
    博客分类: JAVA

 


代码:

类Main:

/**
 * 入口类
 * @author kyda
 */
public class Main {
	
	public Main() {
	}
	
	public static void main(String[] args) {
		new GameCanvas();
	}
	
}

 

 

类GameCanvas:

import java.awt.*;
import java.awt.event.*;

import javax.swing.*;
import java.util.*;

/**
 * 游戏主体类
 * @author kyda
 */
public class GameCanvas extends JFrame implements Runnable {

	//public static final int UP_BORDER = 30, LEFT_BORDER = 10;
	public static final int FRAME_WIDTH = 800, FRAME_HEIGHT = 600; //游戏界面大小
	
	private Random rand = new Random();
	private Thread thread;
	private Snake snake;
	private Food food;
	private boolean isGameOver = false;
	
	// 双缓冲的成员变量
	private Image offScreenImage = null;
	private Graphics offScreen = null;

	public GameCanvas() {
		super("贪吃蛇游戏");
		setSize(FRAME_WIDTH, FRAME_HEIGHT);
		setLocationRelativeTo(null);
		setVisible(true);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		addKeyListener(new GameKeyListener());

		init();
		repaint();
		thread = new Thread(this);
		thread.start();
	}

	/**
	 * 游戏初始化
	 */
	public void init() {
		snake = new Snake();
		createFood();
	}

	/**
	 * 随机位置创建食物
	 */
	public void createFood() {
		int x = rand.nextInt(FRAME_WIDTH / Food.FOOD_WIDTH) * Food.FOOD_WIDTH;
		int y = rand.nextInt(FRAME_HEIGHT / Food.FOOD_HEIGHT) * Food.FOOD_HEIGHT;
		food = new Food(x, y);
	}

	/**
	 * 绘制游戏物体
	 * 使用双缓冲防止闪烁
	 */
	@Override
	public void paint(Graphics g) {
		if (offScreenImage == null) {
			offScreenImage = this.createImage(FRAME_WIDTH, FRAME_HEIGHT);
		}
		if (offScreen == null)
			offScreen = offScreenImage.getGraphics();
		super.paint(offScreen);
		
		Color c = offScreen.getColor();
		
		offScreen.setColor(Color.WHITE);
		offScreen.fillRect(0, 0, FRAME_WIDTH, FRAME_HEIGHT);
		offScreen.setColor(c);
		
		snake.drawSnake(offScreen);
		food.drawFood(offScreen);
		offScreen.drawString("Total length: " + snake.body.size(), 10, 50);
		
		if (isGameOver) {
			offScreen.setColor(Color.RED);
			offScreen.drawString("GameOver! press enter retry!", FRAME_WIDTH / 2 - 70, FRAME_HEIGHT / 2);
		}
		offScreen.setColor(c);
		
		g.drawImage(offScreenImage, 0, 0, null);
	}

	/**
	 * 线程200ms检测碰撞并重画
	 */
	@Override
	public void run() {
		while (true) {
			if (!isGameOver) {
				if (snake.snakeMove(food)) { // 行动中吃到食物
					createFood();
				}
				if (snake.collidedWallOrSelf()) {
					isGameOver = true;
				}
				repaint();
			}
			try {
				Thread.sleep(200);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}

	/**
	 * 内部类,按键监听
	 * @author kyda
	 */
	private class GameKeyListener extends KeyAdapter {

		@Override
		public void keyPressed(KeyEvent e) {
			switch (e.getKeyCode()) {
				case KeyEvent.VK_LEFT:
					if (snake.direct != Snake.RIGHT)
						snake.direct = Snake.LEFT;
					break;
				case KeyEvent.VK_RIGHT:
					if (snake.direct != Snake.LEFT)
						snake.direct = Snake.RIGHT;
					break;
				case KeyEvent.VK_UP:
					if (snake.direct != Snake.DOWN)
						snake.direct = Snake.UP;
					break;
				case KeyEvent.VK_DOWN:
					if (snake.direct != Snake.UP)
						snake.direct = Snake.DOWN;
					break;
				case KeyEvent.VK_ENTER: // gameover后按enter重来
					if (isGameOver) {
						isGameOver = false;
						init();
					}
					break;
				default:
					break;
			}
		}

	}

}

 

 

类Snake:

import java.util.*;
import java.awt.Graphics;

/**
 * 蛇的类
 * @author kyda
 */
public class Snake {

	// 四个方向
	public static final int LEFT = 0, UP = 1, RIGHT = 2, DOWN = 3;

	// 链表储存身体的每个部分,各个部分用Food表示
	public List<Food> body = new LinkedList<Food>();
	// 蛇行进方向
	public int direct;

	/**
	 * 初始化蛇,默认方向向右
	 */
	public Snake() {
		for (int i = 0; i < 3; ++i) {
			body.add(new Food((21 - i) * Food.FOOD_WIDTH, 15 * Food.FOOD_HEIGHT));
		}
		direct = RIGHT;
	}

	/**
	 * 画整条蛇,通过依次画出身体每个部分
	 * @param g
	 */
	public void drawSnake(Graphics g) {
		for (Food food : body) {
			food.drawFood(g);
		}
	}

	/**
	 * 蛇的行走,并判断是否碰到食物
	 * @param food
	 * @return 是否吃下食物
	 */
	public boolean snakeMove(Food food) {
		int desx = body.get(0).x;
		int desy = body.get(0).y;

		switch (direct) {
			case LEFT:
				desx = body.get(0).x - Food.FOOD_WIDTH;
				break;
			case RIGHT:
				desx = body.get(0).x + Food.FOOD_WIDTH;
				break;
			case UP:
				desy = body.get(0).y - Food.FOOD_HEIGHT;
				break;
			case DOWN:
				desy = body.get(0).y + Food.FOOD_HEIGHT;
				break;
		}
		// 吃下食物则整体不动
		if (desx == food.x && desy == food.y) {
			eatFood(food);
			return true;
		}
		// 将身体前一部分位置赋给后一部分
		for (int i = body.size() - 1; i > 0; --i) {
			body.get(i).x = body.get(i - 1).x;
			body.get(i).y = body.get(i - 1).y;
		}
		body.get(0).x = desx;
		body.get(0).y = desy;
		return false;
	}

	/**
	 * 吃下食物,插入链表开头
	 * @param food
	 */
	public void eatFood(Food food) {
		body.add(0, food);
	}

	/**
	 * 判断是否撞墙或吃到自己
	 * @return 是否撞墙或吃到自己
	 */
	public boolean collidedWallOrSelf() {
		Food head = body.get(0);
		
		if (head.x < 0 || head.x >= GameCanvas.FRAME_WIDTH || head.y < 0
				|| head.y >= GameCanvas.FRAME_HEIGHT)
			return true;
		
		for (int i = 1; i < body.size(); ++i) {
			Food food = body.get(i);
			if (head.x == food.x && head.y == food.y) 
				return true;
		}
		return false;
	}
}

 

 

类Food:

import java.awt.*;

/**
 * 食物类
 * @author kyda
 */
public class Food {

	// 食物宽度和高度
	public static final int FOOD_WIDTH = 20, FOOD_HEIGHT = 20;
	
	// 食物坐标
	public int x, y;
	
	public Food() {
	}
	
	public Food(int x, int y) {
		this.x = x;
		this.y = y;
	}

	/**
	 * 画出食物
	 * @param g
	 */
	public void drawFood(Graphics g) {
		g.drawRect(x, y, FOOD_WIDTH, FOOD_HEIGHT);
	}
	
	/**
	 * 检测是否与Food碰撞
	 * @param food
	 * @return 是否与Food碰撞
	 */
	public boolean isCollideWith(Food food) {
		if (this.x == food.x && this.y == food.y) {
			return true;
		}
		return false;
	}
}

 

  • JAVA学习,2个小时写了个简单的贪吃蛇
            
    
    博客分类: JAVA
  • 大小: 25.2 KB