实验系列目录
计算器;贪吃蛇;基于A*算法的迷宫开发
前言
因为前面已经将第一个实验项目完成得差不多,(只剩完善那个历史记录功能)而且一个星期是真的好快啊,所以速度得开始第二个贪吃蛇项目的构建啦。(附图为贪吃蛇项目的要求)
![](https://i-blog.csdnimg.cn/blog_migrate/d0af8057bfc696b40e63f7cf239d3cc7.png)
一、为游戏设计友好的交互界面
首先要初始化静态界面,建立一个数据中心类用来存放所有的静态游戏素材。但是正常的游戏界面应该全部都放在面板上,所以我们建立一个游戏面板类。
当然还可以再添加背景图片,以及背景音乐。举一个例子:
package com.music;
import java.applet.AudioClip;
import java.io.*;
import java.applet.Applet;
import java.awt.Frame;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import javax.swing.JFrame;
public class Music extends JFrame{
File f;
URI uri;
URL url;
Music(){
try {
f = new File("Taylor Swift-Sparks Fly.wav");
uri = f.toURI();
url = uri.toURL(); //解析地址
AudioClip aau;
aau = Applet.newAudioClip(url);
aau.loop(); //循环播放
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String args[]) {
new Music();
}
}
二、
1.贪吃蛇的基本功能
首先需要绘制静态小蛇,并且赋予小蛇初始位置。然后,游戏状态,状态监听需要是实现键盘监听事件KeyListener,重写keyPressed方法。
初始静态界面
- 游戏主窗口的创建,大小不可变
public class StratGame {
public static void main(String[] args) {
JFrame frame= new JFrame();
frame.setBounds(10,10,915,730);
//窗口大小不变
frame.setResizable(false);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
//正常的游戏界面都应该在面板上
frame.add(new GamePanel());
frame.setVisible(true);
}
}
数据中心类
- 存放所有静态游戏素材
//存放外部数据
public class Data {
//头部
//使用相对路径存放素材
public static URL upURL=Data.class.getResource("/statics/up.png");
public static URL downURL=Data.class.getResource("/statics/down.png");
public static URL leftURL=Data.class.getResource("/statics/left.png");
public static URL rightURL=Data.class.getResource("/statics/right.png");
public static URL bodyURL=Data.class.getResource("/statics/body.png");
public static URL foodURL=Data.class.getResource("/statics/food.png");
//将上面获取的图片绘制成图标
public static ImageIcon up=new ImageIcon(upURL);
public static ImageIcon down=new ImageIcon(downURL);
public static ImageIcon left=new ImageIcon(leftURL);
public static ImageIcon right=new ImageIcon(rightURL);
public static ImageIcon body=new ImageIcon(bodyURL);
public static ImageIcon food=new ImageIcon(foodURL);
}
游戏面板类
- 正常的游戏界面放在面板上,于是新建一个游戏面板类,继承JPanel
//游戏面板
public class GamePanel extends JPanel{
//1.绘制组件函数,我们游戏中的所有东西都使用画笔来画
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);//清屏作用,不用出现闪屏
//绘制静态面板
this.setBackground(Color.WHITE);
Data.header.paintIcon(this, g, 25, 0);// 游戏头部,广告栏
g.fillRect(25, 65, 850, 600);// 默认游戏界面
}
}
新建静态小蛇
//游戏面板
public class GamePanel extends JPanel{
//定义蛇的数据结构
int length;//蛇的长度
int[] snakeX = new int[600];//蛇的X坐标
int[] snakeY = new int[500];//蛇的Y坐标
//构造器
public GamePanel() {
init();
}
//初始化小蛇
public void init() {
length = 3;
snakeX[0] = 100;snakeY[0] = 100;//脑袋坐标
snakeX[1] = 75;snakeY[1] = 100;//第一块身体坐标
snakeX[2] = 50;snakeY[2] = 100;//第二块身体坐标
}
//1.绘制组件函数,我们游戏中的所有东西都使用画笔来画
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);//清屏作用,不用出现闪屏
//绘制静态面板
this.setBackground(Color.WHITE);
Data.header.paintIcon(this, g, 25, 0);// 游戏头部,广告栏
g.fillRect(25, 65, 850, 600);// 默认游戏界面
//2.绘制静态小蛇
Data.right.paintIcon(this, g, snakeX[0], snakeY[0]);//绘制初始头的位置
for (int i = 1; i < length; i++) {
Data.body.paintIcon(this, g, snakeX[i], snakeY[i]);// 第一个身体的坐标
}
}
}
让小蛇移动
- 修改gamePanel类,并且赋予小蛇初始位置
//游戏面板
public class GamePanel extends JPanel implements KeyListener, ActionListener {
//定义蛇的数据结构
int length;//蛇的长度
int[] snakeX = new int[600];//蛇的X坐标
int[] snakeY = new int[500];//蛇的Y坐标
String fx;//蛇的初始方向
//游戏状态,默认不开始!
boolean isStart=false;//默认是不开始!
//定时器
Timer timer=new Timer(100,this);//监听当前类,100毫秒刷新一次
//构造器
public GamePanel() {
init();
//获得焦点和键盘事件
this.setFocusable(true);//获得焦点事件
this.addKeyListener(this);//获得键盘监听事件
timer.start();//游戏一开始就开始
}
//初始化小蛇
public void init() {
length = 3;
snakeX[0] = 100;snakeY[0] = 100;//脑袋坐标
snakeX[1] = 75;snakeY[1] = 100;//第一块身体坐标
snakeX[2] = 50;snakeY[2] = 100;//第二块身体坐标
fx = "R";//初始化方向向右
}
//1.绘制组件函数,我们游戏中的所有东西都使用画笔来画
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);//清屏作用,不用出现闪屏
//绘制静态面板
this.setBackground(Color.WHITE);
Data.header.paintIcon(this, g, 25, 0);// 游戏头部,广告栏
g.fillRect(25, 65, 850, 600);// 默认游戏界面
//2.绘制静态小蛇
Data.right.paintIcon(this, g, snakeX[0], snakeY[0]);//绘制初始头的位置
for (int i = 1; i < length; i++) {
Data.body.paintIcon(this, g, snakeX[i], snakeY[i]);// 第一个身体的坐标
}
//画游戏状态
if (!isStart) {
g.setColor(Color.white);
g.setFont(new Font("微软雅黑", Font.BOLD, 40));//设置字体
g.drawString("按下空格开始游戏!", 300, 450);
}
}
//键盘事件监听
@Override
public void keyPressed(KeyEvent e) {
int keyCode = e.getKeyCode();//获得键盘按键是哪一个
if (keyCode==KeyEvent.VK_SPACE){//如果按下空格,则取反游戏状态
isStart=!isStart;
repaint();
}
}
//事件监听----需要用到固定的时间来刷新,1s十次
@Override
public void actionPerformed(ActionEvent e) {
if(isStart){//如果游戏是开始状态,就让小蛇动起来
//移动
for (int i = length-1; i >0 ; i--) {//后一节的位置移到前一节的位置
snakeX[i]=snakeX[i-1];
snakeY[i]=snakeY[i-1];
}
if (fx.equals("R")){
snakeX[0]=snakeX[0]+25;
}
//边界判断
if (snakeX[0]>850){snakeX[0]=25;}
repaint();//重画页面
}
timer.start();//定时器开启!
}
@Override
public void keyReleased(KeyEvent e) {
}
@Override
public void keyTyped(KeyEvent e) {
}
}
小蛇吃食物
- 定义食物坐标,并且需要一个random来使食物随机生成在界面上
//定义一个食物
int foodx;
int foody;
Random random = new Random();
- 将定义的食物画在面板上
//画食物
Data.food.paintIcon(this,g,foodx,foody);
- 在监听事件中,判定吃食物
//吃食物判断 if (snakeX[0]==foodX && snakeY[0]==foodY){ length++;//长度+1 //再次随机生成食物 //初始化食物,把食物随机分布在界面上 foodX=25+25*random.nextInt(34); foodY=75+25*random.nextInt(24); }
2.边界设定
只需要在控制小蛇移动方向后面稍作更改就可以了。 然后,小蛇只要撞墙也会被判定死亡状态。
//通过控制方向让头部移动
if (fx == "R") {
snakeX[0] = snakeX[0] + 25;// 头部移动
if (snakeX[0] > 850){// 当向右运动超出边界时,蛇死,游戏结束
isFail = true;}
} else if (fx == "L") {
snakeX[0] = snakeX[0] - 25;
if (snakeX[0] < 25){
isFail = true;}
} else if (fx == "U") {
snakeY[0] = snakeY[0] - 25;
if (snakeY[0] < 75){
isFail = true;}
} else if (fx == "D") {
snakeY[0] = snakeY[0] + 25;
if (snakeY[0] > 650){
isFail = true;}
}
3.死亡判断
定义boolean类型,新建游戏状态。
boolean isFail= false;//默认游戏状态失败
将失败状态绘制在画板上。
if (isFail){
g.setColor(Color.red);
g.setFont(new Font("微软雅黑", Font.BOLD, 40));//设置字体
g.drawString("失败,按下空格重新开始!", 300, 450);
}
监听键盘事件,判断游戏状态。当小蛇撞到自己时,判定为死亡状态。
if (keyCode==KeyEvent.VK_SPACE){//如果按下空格,则取反游戏状态
if (isFail){
//重新开始
isFail=false;
init();//重新开始重置游戏初始状态
}else {
isStart=!isStart;
}
repaint();
}
//失败判断,撞到自己算失败
for (int i=1;i<length;i++){
if (snakeX[0]==snakeX[i] && snakeY[0]==snakeY[i]){
isFail=true;
}
}
4. 分值计算
- 新增游戏初始分数
//初始化分数
int score;
//初始化小蛇
public void init() {
length = 3;
snakeX[0] = 100;snakeY[0] = 100;//脑袋坐标
snakeX[1] = 75;snakeY[1] = 100;//第一块身体坐标
snakeX[2] = 50;snakeY[2] = 100;//第二块身体坐标
fx = "R";//初始化方向向右
//初始化食物,把食物随机分布在界面上
foodX=25+25*random.nextInt(34);
foodY=75+25*random.nextInt(24);
//初始分数
score=0;
}
- 画分数和长度至画板上
//画积分和长度
g.setColor(Color.WHITE);
g.setFont(new Font("宋体", Font.BOLD, 15));
g.drawString("长度:"+length,750,35);
g.drawString("分数:"+score,750,50);
- 事件判断吃到食物分数增加10
//吃食物判断
if (snakeX[0]==foodX && snakeY[0]==foodY){
length++;//长度+1
score=score+10;
//再次随机生成食物
//初始化食物,把食物随机分布在界面上
foodX=25+25*random.nextInt(34);
foodY=75+25*random.nextInt(24);
}
总结
目前,游戏交互界面还没有头绪。因为是按照b站上播放量最多的那个视频做的。
可能感触最深的是,设置不让蛇头回头。