使用java swing实现贪吃蛇

本文介绍了一个使用Java实现的经典贪吃蛇游戏。通过Canvas画板进行绘制,并利用LinkedList存储蛇身各段的位置。游戏包含开始、暂停及结束等功能,并实现了碰撞检测与得分计算。

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

贪吃蛇是一个大家耳熟能详的小游戏,有很多语言的版本,游戏玩法很简单。

这里使用canvas画板实现。

首先定义一个Snake类,该类是一个列表,存放了蛇上的坐标点,以及蛇的节点的绘制、清除、蛇的移动方向等

class Snake extends Arraylist<Point>{

...........

}

接着创建画板GameCanvas类继承Canvas类,该类是程序主要构成,大部分操作放在该类中,包括监听键盘按键,游戏的开始、结束、暂停等操作

class GameCanvas extends Canvas{

...........

}

对于程序的窗口也需要一个类SnakeGame类,该类继承了JFrame,显示程序的主界面,同时显示开始按钮和分数提示等等信息,在窗体中把GameCanvas类添加到窗体中

public class SnakeFrame extends JFrame{

.......

public SnakeFrame(){

JPanel pane=new JPanel(null);

canvas = new GameCanvas(this);

pane.add(canvas);

}

}

运行效果图如下:


程序完整代码如下:

import java.awt.Canvas;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;


import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.Timer;

public class SnakeFrame extends JFrame{
	/**
	 * 
	 */
	private static final long serialVersionUID = 2487843782670565160L;
	static Color BGCOLOR =Color.BLACK;//定义背景色
	static Color SNAKECOLOR =Color.BLUE;//定义蛇的颜色
	static Color BEANCOLOR =Color.RED;//食物的颜色
	static Color EATEDBEANCOLOR =Color.CYAN;//吃的时候食物的颜色
	private String info="请使用键盘上的<上下左右>按钮控制方向-空格暂停-ESC退出";
	private JLabel helplab=new JLabel(info);
	private JLabel scorelab=new JLabel("得分:0");
	private JButton beginbnt=new JButton("开始游戏");
	private GameCanvas canvas;
	
	public void setLable(String str){
		scorelab.setText(str);
	}
	public SnakeFrame() {
		setTitle("-贪吃蛇-");//设置标题
		this.setSize(600,400);//设置窗体大小
		JPanel pane=new JPanel(null);//定义窗体面板
		beginbnt.setBounds(430, 150, 100, 50);//设置开始按钮
		pane.add(beginbnt);
		beginbnt.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				canvas.resetGame();
				beginbnt.setFocusable(false);//按钮失去焦点
				canvas.requestFocus();//画布获得焦点
			}
		});
		//设置帮助信息
		helplab.setBounds(10, 320, 400, 30);
		pane.add(helplab);
		//设置分数显示标签
		scorelab.setBounds(430, 250, 200, 30);
		pane.add(scorelab);
		//创建游戏面板
		canvas = new GameCanvas(this);
		canvas.setBounds(10, 10, 400, 300);
		//添加到窗体
		pane.add(canvas);
		setContentPane(pane);
		//窗体不可变大小
		this.setResizable(false);
		//居中
		this.setLocationRelativeTo(null);
		//关闭窗体程序结束
		setDefaultCloseOperation(EXIT_ON_CLOSE);
	}
	
	public static void main(String[] args) {
		SnakeFrame sFrame=new SnakeFrame();
		sFrame.setVisible(true);
	}
}

/**
 * 
 * @author cslg.yao
 *
 */
class GameCanvas extends Canvas{
	/**
	 * 
	 */
	private static final long serialVersionUID = 8444419077424283797L;
	private int horizontalCount,verticalCount;//明确横向和纵向大小
	private int x,y;
	private Snake snake;//蛇列表
	private LinkedList<Point> eatedBean = new LinkedList<>();
	private Iterator<Point> snakeSq;
	public Timer timer;//定时器,自动移动
	private int direction=2;//方向
	private int score;//得分
	private Point bean= new Point(), eatBean;
	private boolean mark;
	private Graphics2D g;
	private boolean hasStoped =true;
	private SnakeFrame game;
	
	public GameCanvas(SnakeFrame gamefrm) {
		this();
		game=gamefrm;
	}
	public GameCanvas() {
		//设置绘制的尺寸范围
		this.horizontalCount=25;
		this.verticalCount=20;
		this.x=400/25;
		this.y=300/20;
		this.addKeyListener(new KeyHandler());
		//开始
		timer = new Timer(180, new TimerHandler());
		snake = new Snake();
		hasStoped =false;
		setBackground(SnakeFrame.BGCOLOR);
	}
	
	private class KeyHandler extends KeyAdapter{
		
		public void keyPressed(KeyEvent e){
			if (e.getKeyCode()==10) {
				resetGame();
			}else if (e.getKeyCode() == 27) {
				timer.stop();
				if (JOptionPane.showConfirmDialog(null, "你确定退出吗?")==0) {
					System.exit(0);
				}
				timer.start();
			}
			else if (e.getKeyCode()==37 && snake.snakeDirection !=2) {
				direction=4;
			}
			else if (e.getKeyCode()==39 && snake.snakeDirection !=4) {
				direction=2;
			}
			else if (e.getKeyCode()==38 && snake.snakeDirection !=3) {
				direction=1;
			}
			else if (e.getKeyCode()==40 && snake.snakeDirection !=1) {
				direction=3;
			}else if (e.getKeyCode()==32) {
				if (!hasStoped) {
					if (!mark) {
						timer.stop();
						mark=true;
					}else {
						timer.start();
						mark=false;
					}
				}
			}
		}
	}
	
	private class TimerHandler implements ActionListener{
		@Override
		public synchronized void actionPerformed(ActionEvent e) {
			Point temp=(Point)snake.get(snake.size()-1);
			snakeSq=snake.iterator();
			while (snakeSq.hasNext()) {
				Point tempPoint = (Point)snakeSq.next();
				if (temp.equals(tempPoint)&&snakeSq.hasNext()!=false) {
					timer.stop();
					stopGame();
					JOptionPane.showMessageDialog(null,"游戏结束!");
				}
			}
			//判断游戏结束
			if ((temp.x ==0 &&direction==4)||(temp.x==horizontalCount-1 &&direction==2)||(temp.y==0&&direction==1)||(temp.y==verticalCount-1&&direction==3) ) {
				timer.stop();
				stopGame();
				JOptionPane.showMessageDialog(null,"游戏结束!");
			}
			if (direction!=snake.snakeReDirection) {
				moveSnake(direction);
			}
			snake.drawSnake(getGraphics(),x,y);
			
			drawBeanAndEBean(getGraphics());
		}
		
	}
	/**
	 * 游戏结束
	 */
	public void stopGame(){
		this.hasStoped = true;
		this.timer.stop();
		Graphics2D g=(Graphics2D)GameCanvas.this.getGraphics();
		g.setColor(SnakeFrame.BGCOLOR);
		super.paint(g);
	}
	/**
	 * 游戏开始
	 */
	public void resetGame(){
		System.gc();
		this.hasStoped=false;
		Graphics2D g=(Graphics2D)GameCanvas.this.getGraphics();
		g.setColor(SnakeFrame.BGCOLOR);
		super.paint(g);
		this.snake = new Snake();
		this.createBean(bean);
		this.eatedBean.clear();
		snake.drawSnake(getGraphics(),x,y);
		this.timer.start();
		this.direction=2;
		this.score=0;
	}
	/**
	 * 蛇的移动
	 * @param direction
	 */
	private void moveSnake(int direction){
		//判断是否吃到食物
		if (snake.checkBeanIn(this.bean)) {
			this.score+=100;
			game.setLable("得分:"+this.score+" ");
			//添加到吃过的食物列表
			this.eatedBean.add(new Point(this.bean));
			//创建一个新的食物
			this.createBean(this.bean);
		}
		//
		snake.changeDirection((Point)snake.get(snake.size()-1),direction);
		
		Point p=(Point)snake.get(0);
		if (eatedBean.size()!=0) {
			if (eatedBean.getFirst().equals(p)) {
				eatedBean.remove(0);
			}else {
				snake.clearEndSnakePiece(getGraphics(),p.x,p.y,x,y);
				snake.removeTail();
			}
		}else {
			snake.clearEndSnakePiece(getGraphics(),p.x,p.y,x,y);
			snake.removeTail();
		}
	}
	
	/**
	 * 绘制食物
	 * @param g
	 */
	private void drawBeanAndEBean(Graphics g){
		//设置食物的颜色
		g.setColor(SnakeFrame.BEANCOLOR);
		this.drawPiece(g,this.bean.x,this.bean.y);
		//设置正在吃的食物颜色
		g.setColor(SnakeFrame.EATEDBEANCOLOR);
		
		snakeSq =eatedBean.iterator();
		while (snakeSq.hasNext()) {
			Point tempPoint = (Point) snakeSq.next();
			this.drawPiece(g,tempPoint.x,tempPoint.y);
		}
	}
	
	/**
	 * 绘制填充的矩形块
	 * @param g
	 * @param x
	 * @param y
	 */
	private void drawPiece(Graphics g,int x,int y){
		g.fillRect(this.x*x+1, this.y*y+1, this.x-2, this.y-2);
	}
	/**
	 * 随机创建食物
	 * @param temp
	 */
	private void createBean(Point temp){
		while(true){
			temp.x =(int)(Math.random()*this.horizontalCount);
			temp.y =(int)(Math.random()*this.verticalCount);
			snakeSq =snake.iterator();
			while (snakeSq.hasNext()) {
				if (snakeSq.next().equals(new Point(temp.x,temp.y))) {
					break;
				}
			}
			break;
		}
	}
}


class Snake extends ArrayList<Point>{
	/**
	 * 
	 */
	private static final long serialVersionUID = -2545954212854332230L;
	public int snakeDirection=2;
	public int snakeReDirection=4;
	
	public Snake() {
		/**
		 * 添加默认节点
		 */
		this.add(new Point(3, 3));
		this.add(new Point(4, 3));
		this.add(new Point(5, 3));
	}
	
	/**
	 * 根据方向添加蛇的节点
	 * @param temp
	 * @param direction
	 */
	public void changeDirection(Point temp,int direction){
		this.snakeDirection =direction;
		switch (direction) {
		case 1://向上
			this.snakeReDirection =3;
			this.add(new Point(temp.x, temp.y-1));
			break;
		case 2://向右
			this.snakeReDirection =4;
			this.add(new Point(temp.x+1, temp.y));
			break;
		case 3://向下
			this.snakeReDirection =1;
			this.add(new Point(temp.x, temp.y+1));
			break;
		case 4://向左
			this.snakeReDirection =2;
			this.add(new Point(temp.x-1, temp.y));
			break;
		default:
			break;
		}
	}
	
	/**
	 * 清除
	 * @param bean
	 * @return
	 */
	public boolean checkBeanIn(Point bean) {
		Point temp =(Point)this.get(this.size()-1);
		if (temp.equals(bean)) {
			return true;
		}
		return false;
	}
	/**
	 * 删除
	 */
	public void removeTail(){
		this.remove(0);
	}
	
	/**
	 * 绘制蛇
	 * @param g
	 * @param x
	 * @param y
	 */
	public void drawSnake(Graphics g,int x,int y){
		g.setColor(SnakeFrame.SNAKECOLOR);
		Iterator<Point> snakeSq = this.iterator();
		while (snakeSq.hasNext()) {
			Point p = (Point) snakeSq.next();
			g.fillRect(x*p.x+1, y*p.y+1, x-2, y-2);
		}
	}
	/**
	 * 清除节点
	 * @param g
	 * @param x1
	 * @param y1
	 * @param x2
	 * @param y2
	 */
	public void clearEndSnakePiece(Graphics g,int x1,int y1,int x2,int y2){
		g.setColor(SnakeFrame.BGCOLOR);
		g.fillRect(x1*x2+1, y1*y2+1, x2-2, y2-2);
		
	}
	
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值