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

一个非常简单的贪吃蛇

 

共4个类:

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

GameCanvas----主体类

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

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

 

截图:


 


代码:

类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;
	}
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值