一、前序
最近用java写了一个贪吃蛇游戏的Demo,感觉还不错,在这上面整理一下。
(1)游戏的运行图:
游戏规则很简单:
1.按空格启动开始游戏,再次按空格可以切换暂停和开始游戏,死亡之后按空格可以重新开始游戏
2.监听键盘空格键和上、下、左、右 键,使小蛇可以按规定方向行走
(2)游戏工程图:
(3)游戏所需要素材
二、核心代码:
1.Images.java 作用:封装所用到的图像地址
package cm.msb.gane;
/**
*
* @author 16574
*这个类专门获取游戏中所需要的图片
*/
import java.net.URL;
import javax.swing.ImageIcon;
public class Images {
public static URL bodyUrl=Images.class.getResource("/images/body.png");
public static ImageIcon bodyIcon = new ImageIcon(bodyUrl);
public static URL downUrl=Images.class.getResource("/images/down.png");
public static ImageIcon downIcon = new ImageIcon(downUrl);
public static URL foodUrl=Images.class.getResource("/images/food.png");
public static ImageIcon foodIcon = new ImageIcon(foodUrl);
public static URL headerUrl=Images.class.getResource("/images/header.png");
public static ImageIcon headerIcon = new ImageIcon(headerUrl);
public static URL leftUrl=Images.class.getResource("/images/left.png");
public static ImageIcon leftIcon = new ImageIcon(leftUrl);
public static URL rightUrl=Images.class.getResource("/images/right.png");
public static ImageIcon rightIcon = new ImageIcon(rightUrl);
public static URL upUrl=Images.class.getResource("/images/up.png");
public static ImageIcon upIcon = new ImageIcon(upUrl);
}
2.StartGame.java
主要功能:主程序入口,设置窗口属性
package cm.msb.gane;
import java.awt.Toolkit;
import javax.swing.*;
public class StartGame {
public static void main(String[] args) {
// TODO Auto-generated method stub
JFrame jf =new JFrame();
jf.setTitle("小游戏 大逻辑 by王振");
int width = Toolkit.getDefaultToolkit().getScreenSize().width;
int height = Toolkit.getDefaultToolkit().getScreenSize().height;
int x = (width-800)/2;
int y = (height-800)/2;
jf.setBounds(x, y, 800, 800);
//关闭窗口的同时,程序停止运行
jf.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
//设置窗体大小不可调节
GamePanel gPanel = new GamePanel();
jf.add(gPanel);
jf.setResizable(false);
jf.setVisible(true);
}
}
3、GamePanel.java
主要功能:实现游戏运行逻辑
package cm.msb.gane;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.Random;
import javax.swing.JPanel;
import javax.swing.Timer;
public class GamePanel extends JPanel{
//初始化蛇的长度
int length;
//定两个数组
//一个数组专门储存蛇的x轴坐标
int snakex[] = new int[200];
//第二个储存蛇的y轴数组
int snakey[] = new int[200];
//定时器
Timer timer;
//游戏只有两个状态,开始或者暂停
boolean isStart = false;
//定义蛇的行走方向
String direction;
//定义食物的x轴和y轴坐标
int foodx;
int foody;
//定义一个积分
int score;
//加入一个小蛇生死状态
boolean isDie = false;
//小蛇初始化方法
public void inite() {
length = 3;
snakex[0] = 250;
snakey[0] = 275;
snakex[1] = 200;
snakey[1] = 275;
snakex[2] = 225;
snakey[2] = 275;
direction = "R";
foodx = 300;
foody = 150;
score = 0;
}
//面板类的初始化
public GamePanel() {
// TODO Auto-generated constructor stub
inite();
//将焦点定位在当前面板
this.setFocusable(true);
//加入监听
this.addKeyListener(new KeyAdapter() {
public void keyPressed(KeyEvent e) {
super.keyPressed(e);
int keyCode = e.getKeyCode();
if(keyCode == KeyEvent.VK_SPACE) {
if(isDie) {
//全部恢复到初始状态
inite();
isDie = false;
}
else {
isStart = !isStart;
repaint();
}
}
//监听向上箭头
if(keyCode == KeyEvent.VK_UP) {
direction = "U";
}
if(keyCode == KeyEvent.VK_DOWN) {
direction = "D";
}
if(keyCode == KeyEvent.VK_LEFT) {
direction = "L";
}
if(keyCode == KeyEvent.VK_RIGHT) {
direction = "R";
}
}
});
//
timer = new Timer(100, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// 游戏是开始状态的时候蛇才动
if(isStart&&isDie==false) {
for(int i=length-1;i>0;i--) {
snakex[i] = snakex[i-1];
snakey[i] = snakey[i-1];
}
//动头
if(direction.equals("U")) {
snakey[0] -= 25;
}
if(direction.equals("D")) {
snakey[0] += 25;
}
if(direction.equals("L")) {
snakex[0] -= 25;
}
if(direction.equals("R")) {
snakex[0] += 25;
}
//防止蛇超出边界
if(snakex[0] > 775) {
snakex[0] = 25;
}
if(snakex[0] < 25) {
snakex[0] = 775;
}
if(snakey[0] < 75) {
snakey[0] = 725;
}
if(snakey[0] > 725) {
snakey[0] = 75;
}
//检测碰撞的动作
//食物的坐标和蛇的坐标一致
if(snakex[0]==foodx&&snakey[0]==foody) {
length++;
//食物坐标改变,随机生成坐标**必须是25的倍数
/*
* [25,775] -> [1,31]*25
* Math.random() ->[0.0,1.0)
* (int)Math.random()*31 ->[0,30]
* (int)Math.random()*31+1 ->[1,31]
*/
foodx = ((int)(Math.random()*31)+1)*25;//[25,775]
/*
* [75,725] ->[3,28]*25
* [3,28] ->[0,25]+3
* [0,25]
* new random().nextInt(26) ->[0,26) ->[0,25]
*/
foody = (new Random().nextInt(26)+3)*25;//[75,725]
//吃上食物之后,积分加10
score = score+10;
}
//死亡判定:
for(int i=1;i<length;i++) {
if (snakex[0]==snakex[i]&&snakey[0]==snakey[i]) {
//将死亡状态改为true
isDie = true;
}
}
repaint();
}
}
});
timer.start();
}
@Override
protected void paintComponent(Graphics g) {
// TODO Auto-generated method stub
super.paintComponent(g);
//填充背景色
this.setBackground(new Color(226,224,217));
Images.headerIcon.paintIcon(this, g, 10, 0);
g.setColor(new Color(219,226,219));
g.fillRect(10, 70, 775, 685);
//画小蛇
//画蛇头
if(direction.equals("R"))
Images.rightIcon.paintIcon(this, g, snakex[0], snakey[0]);
if(direction.equals("U"))
Images.upIcon.paintIcon(this, g, snakex[0], snakey[0]);
if(direction.equals("L"))
Images.leftIcon.paintIcon(this, g, snakex[0], snakey[0]);
if(direction.equals("D"))
Images.downIcon.paintIcon(this, g, snakex[0], snakey[0]);
// Images.bodyIcon.paintIcon(this, g, snakex[1], snakey[1]);
// Images.bodyIcon.paintIcon(this, g, snakex[2], snakey[2]);
for (int i = 1; i <length; i++) {
Images.bodyIcon.paintIcon(this, g, snakex[i], snakey[i]);
}
//如果有游戏是暂停的,界面中间有一句提示语
if(isStart == false) {
g.setColor(new Color(114,98,255));
//字体,加粗,字号
g.setFont(new Font("微软雅黑",Font.BOLD,40));
//参数内容,x轴坐标,y轴坐标
g.drawString("点击空格开始游戏", 250, 330);
}
//画食物
Images.foodIcon.paintIcon(this, g, foodx, foody);
//画积分
g.setColor(new Color(255,248,248));
g.setFont(new Font("微软雅黑",Font.BOLD,20));
g.drawString("积分"+score, 680, 42);
//画死亡状态
if(isDie) {
g.setColor(new Color(255,82,68));
g.setFont(new Font("微软雅黑",Font.BOLD,20));
g.drawString("小蛇死亡,游戏停止,按下空格重新开始游戏", 200, 330);
}
}
}
三、结束
这样一个简单的小游戏就做好啦!
建议:可以根据需要自行改变图中的代码,小蛇移动的快慢,改变小蛇的头和身体及各种参数
可以为面板边缘增加墙壁,使得小蛇实现撞墙死的效果,还可以改善UI使得观看更美观。
建议就先写到这了,有什么好的建议可以通过评论区和我交流。