实验二:贪吃蛇游戏开发

贪吃蛇游戏开发

实验要求

①实现贪吃蛇游戏基本功能,屏幕上随机出现一个“食物”,称为豆子。上下左右控制“蛇”的移动,吃到“豆子”以后“蛇”的身体加长一点。
②“蛇”碰到边界或蛇头与蛇身相撞,蛇死亡,游戏结束。
③为游戏设计友好的交互界面;例如欢迎界面,游戏界面,游戏结束界面。要有开始键、暂停键和停止退出的选项。
④对蛇吃到豆子进行分值计算,可以设置游戏速度,游戏音乐等拓展元素。

实验过程

本次实验依然使用Java来完成。一共包括4个大类。

Background类

Background类完成游戏界面的设计。
重要变量定义

private boolean gameover=false;		//判断游戏是否结束
	private Font fontGameover=new Font("宋体",Font.BOLD,50);	//字体属性
	private int score=0;				//分数
	public long beginTime=0;			//游戏开始时间
	public static final int row=30;		//行数
	public static final int col=30;		//列数
	public static final int yard=15;	//游戏区域

通过两个for循环画出贪吃蛇游戏的表格背景

for(int i=1;i<row;i++) {
			g.drawLine(0, yard*i, col*yard, yard*i);
		}
		for(int i=1;i<col;i++) {
			g.drawLine(yard*i, 0, yard*i, yard*row);
		}

创建用于双缓冲的图像,未添加该图像之前,游戏画面会不断闪烁,查阅相关资料之后发现需要添加图像用于双缓冲来避免闪烁。

public void update(Graphics g) {
		if(offScreenImage==null) {
			offScreenImage=this.createImage(col*yard,row*yard);		//创建用于双缓冲的图像,避免图像闪烁
		}
		Graphics gOff=offScreenImage.getGraphics();
		paint(gOff);
		g.drawImage(offScreenImage,0,0,null);
	}

Snake类

Snake类完成蛇头和蛇身的创建以及相关函数的创建。

重要变量定义

private Node head=null;		//头结点
	private Node tail=null;		//尾结点
	private int size=0;			//大小
	/*
	 * 设置起始位置和方向
	 */
	private Node n=new Node(20,30,D.L);
	private Background b;

创建私有类Node,通过Node类完成蛇体和蛇身构建

private class Node{
		int w=Background.yard;
		int h=Background.yard;
		int row, col;
		D d=D.L;
		Node next=null;
		Node prev=null;
		
		Node(int row,int col,D d){
			this.row=row;
			this.col=col;
			this.d=d;
		}
		
		void draw(Graphics g) {
			Color c=g.getColor();
			g.setColor(Color.BLACK);
			g.fillRect(Background.yard*col, Background.yard*row,w,h);
			g.setColor(c);
		}
	}

addToHead函数实现从头部添加

public void addToHead(){
		Node node=null;
		switch(head.d) {
		case L:
			node=new Node(head.row,head.col-1,head.d);
			break;
		case U:
			node=new Node(head.row-1,head.col,head.d);
			break;
		case R:
			node=new Node(head.row,head.col+1,head.d);
			break;
		case D:
			node=new Node(head.row+1,head.col,head.d);
			break;
		}
		head.prev=node;
		node.next=head;
		head=node;
		size++;
	}

move函数实现移动

private void move() {
		addToHead();
		deleteFromTail();
		checkDead();
	}

checkDead函数判断是否死亡

private void checkDead() {
		/*
		 * 碰触边界
		 */
		if(head.row<2||head.col<0||head.row>Background.row||head.col>Background.col) {
			b.stop();
		}
		/*
		 * 头结点与身体相撞
		 */
		for(Node n=head.next;n!=null;n=n.next) {
			if(head.row==n.row&&head.col==n.col) {
				b.stop();
			}
		}
	}

eat函数完成吃豆子

public void eat(Food f) {
		if(this.getRect().intersects(f.getRect())) {
			f.reAppear();
			this.addToHead();
			b.setScore(b.getScore()+1);		//吃到豆子加分
		}
	}

keyPressed函数接收键盘按键

	public void keyPressed(KeyEvent e) {
		int key=e.getKeyCode();
		switch(key) {
		case KeyEvent.VK_LEFT:
		//朝向非右即可向左转
		if(head.d!=D.R) 
			head.d=D.L;
		
		break;
		case KeyEvent.VK_RIGHT:
		//朝向非左即可向右转
		if(head.d!=D.L) 
			head.d=D.R;
		
		break;
		case KeyEvent.VK_UP:
		//朝向非下即可向上转
		if(head.d!=D.D) 
			head.d=D.U;
		
		break;
		case KeyEvent.VK_DOWN:
		//朝向非上即可向下转
		if(head.d!=D.U) 
			head.d=D.D;
		
		break;
	}
	}

Food类

Food类完成豆子的生成。
构造方法完成初始位置生成

public Food() {
		this(r.nextInt(Background.row-2)+2,r.nextInt(Background.col));
	}

reAppear函数完成豆子的随机生成

public void reAppear() {
		this.row=r.nextInt(Background.row-2)+2;
		this.col=r.nextInt(Background.col);
	}

D类

D类通过enum完成常量定义

public enum D {
	L,U,R,D

}

界面展示

在这里插入图片描述
以上就是关于第二个实验:贪吃蛇游戏开发的全部记录。

源代码如下
Background类

package software02;

import java.awt.Color;
import java.awt.Font;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.event.KeyListener;
import java.awt.event.*;

public class Background extends Frame{
	PaintThread paintThread=new PaintThread();
	Snake s=new Snake(this);
	Food f=new Food();
	
	//基本属性
	private boolean gameover=false;		//判断游戏是否结束
	private Font fontGameover=new Font("宋体",Font.BOLD,50);	//字体属性
	private int score=0;				//分数
	public long beginTime=0;			//游戏开始时间
	public static final int row=30;		//行数
	public static final int col=30;		//列数
	public static final int yard=15;	//游戏区域
	
	/*抽象类Image是表示图形图像的所有类的超类
	 * 必须以特定于平台的方式获取图像
	 */
	Image offScreenImage= null;
	
	//结束游戏
	public void stop() {
		gameover=true;
	}
	
	private class KeyFunction extends KeyAdapter{
		public void keyPressed(KeyEvent e) {
			int key=e.getKeyCode();

			//暂停游戏
			 if(key==KeyEvent.VK_F1) {
				paintThread.pause=true;
			}
			
			//恢复游戏
			else if(key==KeyEvent.VK_F9) {
				paintThread.pause=false;
			}
			s.keyPressed(e);
		}
	}
	
	//设置窗口、部分键盘功能
	public void function(){
		this.setLocation(90,10);		//确定窗口位置
		this.setSize(col*yard,row*yard);		//确定窗口大小
		
		/*
		 * 为窗口添加监听器
		 */
		this.addWindowListener(new WindowAdapter(){
			public void windowClosing(WindowEvent e) {
				System.exit(0);
			}
		});
		this.setVisible(true);			//窗口可视化
		this.addKeyListener(new KeyFunction());
		new Thread(paintThread).start();
	}
	
	public void paint(Graphics g) {
		Color c=g.getColor();		//获取该图形上下文颜色
		g.setColor(Color.GRAY);		//指定图形上下文颜色
		g.fillRect(0,0,col*yard,row*yard);	//填充区域
		g.setColor(Color.DARK_GRAY);	//换色,区分绘图颜色和文字颜色
		
		/*
		 * 画出表格
		 */
		for(int i=1;i<row;i++) {
			g.drawLine(0, yard*i, col*yard, yard*i);
		}
		for(int i=1;i<col;i++) {
			g.drawLine(yard*i, 0, yard*i, yard*row);
		}
		g.setColor(Color.YELLOW);	//文字颜色
		g.drawString("操作方法:方向键控制移动,F1停止游戏", 10, 40);
		g.drawString("当前游戏分数"+getScore(), 10, 60);
		g.drawString("耗时:"+(System.currentTimeMillis()-beginTime)/1000,10, 80);
		
		/*
		 * 判断游戏是否结束
		 */
		if(gameover) {
			g.setFont(fontGameover);
			g.drawString("Game Over", 90, 170);
			paintThread.pause();
		}
		if(score>10) {
			g.drawString("太强了吧!", 90, 150);
		}
		if(score>30) {
			g.drawString("牛!", 90, 170);
		}
		g.setColor(c);
		s.eat(f);
		f.draw(g);
		s.draw(g);
	}
	
	public void update(Graphics g) {
		if(offScreenImage==null) {
			offScreenImage=this.createImage(col*yard,row*yard);		//创建用于双缓冲的图像,避免图像闪烁
		}
		Graphics gOff=offScreenImage.getGraphics();
		paint(gOff);
		g.drawImage(offScreenImage,0,0,null);
	}
	
	private class PaintThread implements Runnable{
		private boolean running=true;
		private boolean pause=false;
		public void run() {
			while(running) {
				if(pause)continue;
				else repaint();
				try {
					Thread.sleep(200);
				}catch(InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
		
		public void pause() {
			this.pause=true;
		}
		
		
		
		public void gameover() {
			running=false;
		}
	}

	public int getScore() {
		return score;
	}
	
	public void setScore(int score) {
		this.score=score;
	}
	
	public static void main(String[]args) {
		Background b=new Background();
		b.beginTime=System.currentTimeMillis();
		b.function();
	}
}

Snake类

package software02;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.event.KeyEvent;

public class Snake {
	private Node head=null;		//头结点
	private Node tail=null;		//尾结点
	private int size=0;			//大小
	/*
	 * 设置起始位置和方向
	 */
	private Node n=new Node(20,30,D.L);
	private Background b;
	
	//初始化
	public Snake(Background b) {
		head=n;
		tail=n;
		size=1;
		this.b=b;
	}
	


	//结点类
	private class Node{
		int w=Background.yard;
		int h=Background.yard;
		int row, col;
		D d=D.L;
		Node next=null;
		Node prev=null;
		
		Node(int row,int col,D d){
			this.row=row;
			this.col=col;
			this.d=d;
		}
		
		void draw(Graphics g) {
			Color c=g.getColor();
			g.setColor(Color.BLACK);
			g.fillRect(Background.yard*col, Background.yard*row,w,h);
			g.setColor(c);
			}
		}
	
	
	public void bianSe(Graphics g) {
		Food f=null;
		if(eat(f)) {
			g.setColor(Color.BLUE);
		}
	}
	//从头部开始添加
	public void addToHead(){
		Node node=null;
		switch(head.d) {
		case L:
			node=new Node(head.row,head.col-1,head.d);
			break;
		case U:
			node=new Node(head.row-1,head.col,head.d);
			break;
		case R:
			node=new Node(head.row,head.col+1,head.d);
			break;
		case D:
			node=new Node(head.row+1,head.col,head.d);
			break;
		}
		head.prev=node;
		node.next=head;
		head=node;
		size++;
	}
	
	public void draw(Graphics g) {
		if(size<=0) {
			return;
		}
		move ();
		for(Node n=head;n!=null;n=n.next) {
			n.draw(g);
		}
	}
	
	//移动函数
	private void move() {
		addToHead();
		deleteFromTail();
		checkDead();
	}
	
	private void checkDead() {
		/*
		 * 碰触边界
		 */
		if(head.row<2||head.col<0||head.row>Background.row||head.col>Background.col) {
			b.stop();
		}
		/*
		 * 头结点与身体相撞
		 */
		for(Node n=head.next;n!=null;n=n.next) {
			if(head.row==n.row&&head.col==n.col) {
				b.stop();
			}
		}
	}
	/*
	 * 尾结点删除
	 */
	private void deleteFromTail() {
		if(size==0) {
			return;
		}
		tail=tail.prev;
		tail.next=null;
	}
	
	public boolean eat(Food f) {
		if(this.getRect().intersects(f.getRect())) {
			f.reAppear();
			this.addToHead();
			b.setScore(b.getScore()+1);		//吃到豆子加分
		}
		return true;
	}
	
	
	private Rectangle getRect() {
		return new Rectangle(Background.yard*head.col,Background.yard*head.row,head.w,head.h);
	}
	
	/*
	 * 接收键盘按键
	 */
	public void keyPressed(KeyEvent e) {
		int key=e.getKeyCode();
		switch(key) {
		case KeyEvent.VK_LEFT:
		//朝向非右即可向左转
		if(head.d!=D.R) 
			head.d=D.L;
		
		break;
		case KeyEvent.VK_RIGHT:
		//朝向非左即可向右转
		if(head.d!=D.L) 
			head.d=D.R;
		
		break;
		case KeyEvent.VK_UP:
		//朝向非下即可向上转
		if(head.d!=D.D) 
			head.d=D.U;
		
		break;
		case KeyEvent.VK_DOWN:
		//朝向非上即可向下转
		if(head.d!=D.U) 
			head.d=D.D;
		
		break;
	}
	}
}

Food类

package software02;

import java.awt.Color;
import java.awt.Rectangle;
import java.util.Random;
import java.awt.Graphics;

public class Food {
	int row,col;
	int w=Background.yard;
	int h=Background.yard;
	
	private static Random r=new Random();
	private Color color=Color.PINK;
	
	//运动时的位置
	public Food(int row,int col) {
		this.row=row;
		this.col=col;
	}
	
	//初始位置
	public Food() {
		this(r.nextInt(Background.row-2)+2,r.nextInt(Background.col));
	}
	
	public void reAppear() {
		this.row=r.nextInt(Background.row-2)+2;
		this.col=r.nextInt(Background.col);
	}
	
	public Rectangle getRect() {
		return new Rectangle(Background.yard*col,Background.yard*row,w,h);
	}
	
	public void draw(Graphics g) {
		Color c=g.getColor();
		g.setColor(color);
		//使用当前颜色填充指定矩形框的椭圆
		g.fillOval(Background.yard*col,Background.yard*row, w, h);
		g.setColor(c);
		if(color==Color.GREEN) {
			color=Color.RED;
		}
		else color=Color.GREEN;
	}
	
	public int getCol() {
		return col;
	}
	
	public void setCol(int col) {
		this.col=col;
	}
	
	public int getRow() {
		return row;
	}
	
	public void setRow(int row) {
		this.row=row;
	}

}

D类

package software02;

public enum D {
	L,U,R,D

}

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值