基于Java的贪吃蛇小游戏
一、开发思路
设定一个一定大小的且大小不可变的游戏窗口
在创建的窗口上绘制游戏的基本面板样式
使用提前保存的素材图标绘制一条静态的小蛇
使小蛇能够移动;实际只需蛇头坐标移动,每节身体覆盖前一节身体坐标,设置定时器Timer timer =new Timer();监听时间让小蛇能移动
监听键盘操作,使用户能通过键盘控制蛇的方向
定义一个食物坐标,用random随机数类实现食物随机生成
小蛇吃到食物时身体长度+1,实际是蛇头坐标与食物坐标重合时
boolean定义游戏失败的判断,当蛇头与任何身体部位坐标重合(或撞到边界)则游戏失败,可再设置积分系统,每吃到一次食物加一定分数
二 新建一个Data类,作为图片资源
package snake;
import java.net.URL;
import javax.swing.ImageIcon;
public class Data {
public static URL headerURL = Data.class.getResource("/statics/header.png");
public static ImageIcon header;
static {
assert headerURL != null;
header = new ImageIcon(headerURL);
}
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 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 URL bodyURL = Data.class.getResource("/statics/body.png");
public static ImageIcon body;
static {
assert bodyURL != null;
body = new ImageIcon(bodyURL);
}
public static URL foodURL = Data.class.getResource("/statics/food.png");
public static ImageIcon food;
static {
assert foodURL != null;
food = new ImageIcon(foodURL);
}
}
三 绘制静态游戏窗口
package snake;
import javax.swing.JFrame;
import javax.swing.WindowConstants;
//创建主窗口
public class MainFrame{
public MainFrame(){
init();
}
public void init(){
JFrame frame = new JFrame();
frame.setSize(915, 745);
frame.setResizable(false);//窗口不可拉伸
frame.setTitle("贪吃蛇小游戏");
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.add(new GamePanel());
frame.setVisible(true);
}
}
四 游戏面板类 GamePanel
package snake;
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 implements ActionListener{
//定义游戏数据
int panel_Width;
int panel_Height;
int snake_Speed = 300;//刷新时间
//定义蛇的数据结构
int length; //蛇的长度
int[] snake_X = new int[600];
int[] snake_Y = new int[600];
String snake_Orientation; //蛇头朝向
//食物的坐标
int food_X;
int food_Y;
Random random = new Random();
//定义游戏状态
boolean isStrat = false; //默认暂停状态
//游戏失败
boolean isFail = false;
//游戏积分
int score;
int food_Value;//食物分数
//游戏难度
int level;
//cheat
boolean cheat = false;
//定时器
Timer timer = new Timer(snake_Speed, this);
//构造器
public GamePanel() {
init();
//获得焦点和键盘事件
this.setFocusable(true); //获得焦点事件
this.addKeyListener(new keyboardListener());
timer.start();//游戏一开始,定时器就启动
}
//初始化
public void init(){
panel_Width = 850;
panel_Height = 600;
length = 3;
snake_X[0] = 100;snake_Y[0] = 100; //头的坐标
snake_X[1] = 75;snake_Y[1] = 100; //第一节身体的坐标
snake_X[2] = 50;snake_Y[2] = 100; //第二节身体的坐标
snake_Orientation = "right"; //初始头的方向为右
//食物随机分布在界面上
food_X = 25 + 25*random.nextInt(33);//生成1到34的随机数
food_Y = 75 + 25*random.nextInt(23);
score = 0;
food_Value = 5;
level = 1;
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);//清屏
//绘制静态面板
this.setBackground(Color.lightGray);
//画下方游戏界面
g.fillRect(25, 75, panel_Width, panel_Height);
//画积分
g.setColor(Color.white);
g.setFont(new Font("微软雅黑", Font.BOLD, 15));
g.drawString("长度:"+length, 750, 25);
g.drawString("分数:"+score, 750, 40);
g.drawString("难度:"+level, 750, 55);
g.drawString("~糖豆人大作战~", 370, 30);
//画食物
Data.food.paintIcon(this, g, food_X, food_Y);
//画小蛇
if (snake_Orientation.equals("right")){
Data.right.paintIcon(this, g, snake_X[0], snake_Y[0]);//画朝右的头部
}else if(snake_Orientation.equals("left")){
Data.left.paintIcon(this, g, snake_X[0], snake_Y[0]);//画朝左的头部
}else if(snake_Orientation.equals("up")){
Data.up.paintIcon(this, g, snake_X[0], snake_Y[0]);//画朝上的头部
}else if(snake_Orientation.equals("down")){
Data.down.paintIcon(this, g, snake_X[0], snake_Y[0]);//画朝下的头部
}
for (int i = 1; i < length; i++) {
Data.body.paintIcon(this, g, snake_X[i], snake_Y[i]);//画每一节身体
}
//游戏状态
if (isStrat == false){
g.setColor(Color.white);
g.setFont(new Font("微软雅黑", Font.BOLD, 40));
g.drawString("按下空格开始游戏", 300, 300);
}
//游戏失败
if (isFail == true){
g.setColor(Color.red);
g.setFont(new Font("微软雅黑", Font.BOLD, 40));
g.drawString("失败,按下空格重新开始", 220, 300);
}
}
//键盘监听
class keyboardListener extends KeyAdapter{
@Override
public void keyPressed(KeyEvent e) {
int keyCode = e.getKeyCode();//获得按下的键
if (keyCode == KeyEvent.VK_SPACE){
if (isFail == true){
//空格控制重新开始
isFail = false;
init();
}else {
//空格控制游戏暂停
isStrat = !isStrat; //isStart取反
}
repaint();
}
//控制小蛇移动
if (keyCode == KeyEvent.VK_UP){
if (snake_Orientation != "down"){
snake_Orientation = "up";
}
}else if (keyCode == KeyEvent.VK_DOWN){
if (snake_Orientation != "up"){
snake_Orientation = "down";
}
}else if (keyCode == KeyEvent.VK_LEFT){
if (snake_Orientation != "right"){
snake_Orientation = "left";
}
}else if (keyCode == KeyEvent.VK_RIGHT){
if (snake_Orientation != "left"){
snake_Orientation = "right";
}
}
if (keyCode == KeyEvent.VK_C){
cheat = !cheat;
}
}
}
//事件监听,通过固定的时间来刷新
@Override
public void actionPerformed(ActionEvent e) {
if (isStrat == true && isFail == false){ //游戏开始,小蛇运动
//身体跟随移动
for (int i = length-1; i > 0; i--) {//向前移动一节(每个身体都到上一节身体的坐标)
//新生成的身体不可见,否则有bug
snake_X[length] = -50;
snake_Y[length] = -50;
snake_X[i] = snake_X[i-1];
snake_Y[i] = snake_Y[i-1];
}
//头部运动判断,只需要控制头部的运动,其他身体都会跟着动
if (snake_Orientation == "up"){
snake_Y[0] = snake_Y[0]-25;
if (snake_Y[0] < 75){
snake_Y[0] = panel_Height+50;
}
}else if (snake_Orientation == "down"){
snake_Y[0] = snake_Y[0]+25;
if (snake_Y[0] > panel_Height+50){
snake_Y[0] = 75;
}
}else if (snake_Orientation == "left"){
snake_X[0] = snake_X[0]-25;
if (snake_X[0] < 25){
snake_X[0] = panel_Width;
}
}else if (snake_Orientation == "right"){
snake_X[0] = snake_X[0]+25;
if (snake_X[0] > panel_Width){
snake_X[0] = 25;
}
}
//吃食物
if (snake_X[0] == food_X && snake_Y[0] == food_Y) {
length++;
score += food_Value;
//重新生成食物
food_X = 25 + 25 * random.nextInt(34);
food_Y = 75 + 25 * random.nextInt(24);
}
//失败判定,头碰到身体就算失败
if (cheat == false){
for (int i = 1; i < length; i++) { //遍历所有身体坐标
if (snake_X[0] == snake_X[i] && snake_Y[0] == snake_Y[i]){
isFail = true;
break;
}
}
}
if (length > 5 && length < 10){
level = 2;
timer.stop();
snake_Speed = 100;
}
if (length > 20 && length < 30){
level = 3;
timer.stop();
snake_Speed = 50;
}
repaint();
}
timer.start();
}
}
1. 游戏规则:蛇头碰到蛇身结束游戏
2. 根据积分等级,蛇的移动速度加快,积分越高,移动速度越快
3. 键盘:上下左右键控制蛇的移动方向
五 最后一个类,启动类 StartGame
package snake;
public class StartGame {
public static void main(String[] args) {
new MainFrame();
}
}
六、效果截图