分享狂神贪吃蛇代码及图片素材,包含部分个人优化

按照狂神贪吃蛇教程做出的成品程序,和大家分享

       使用CSDN这么久,第一次自己写文章,如有低级错误,请多包涵。

       我最近在学习JavaSE进阶,按照狂神 (B站ID:遇见狂神说) 推荐的学习路径,学习到了GUI部分,受益匪浅。如果你也在自学Java,不妨去关注up,他的讲课风格很好,而且涉及全面,从Java基础,到MVC,再到SpringBoot,值得一看。

       这篇文章的目的是分享一下狂神贪吃蛇项目的全部代码,其中包含我做出改进的部分,也有我个人的疑惑,希望和大家分享。

       这个贪吃蛇项目实现了简单的GUI界面和键盘监听用户交互,美中不足是比较简陋,而且不是完全的面向对象项目。由于经验与理解尚不足,我暂时没有能力将它更加完善。如果您有好的意见,欢迎与我联系。

启动类:

package com.zcy.JavaSE.GUI.Snake;

import javax.swing.*;
/**
 * @author 睿智的仓鼠
 *
 *-学习自B站up 遇见狂神说,代码非原创,仅供学习参考!
 *
 *-基础功能:
 *1.键盘方向键控制小蛇移动
 *2.空格键暂停游戏
 *
 *-新增功能:
 *1.小蛇运动时无法回头直接吃自己
 *2.增加了难度机制,蛇的长度越长,难度越高
 *3.按c键进入作弊模式
 *
 *-未解决部分:
 *1.无法通过修改timer的参数,来根据难度调整小蛇运动的速度
 *
 */

//主启动类
public class StartGame {
	public static void main(String[] args) {
		new MainFrame();
	}
}

主窗口类:

package com.zcy.JavaSE.GUI.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);
	}
}

游戏面板:

package com.zcy.JavaSE.GUI.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 = 200;//刷新时间(毫秒),越大越慢
	
	//定义蛇的数据结构
	int length;	//蛇的长度
	int[] snake_X = new int[600];	//蛇的x坐标
	int[] snake_Y = new int[600];	//蛇的y坐标
	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) {	//paintComponent无需调用,自动执行
		
		super.paintComponent(g);//清屏
		
		//绘制静态面板
		this.setBackground(Color.lightGray);
		//画上方广告栏
		Data.header.paintIcon(this, g, 25, 11);//在哪个组件画, 用哪个画笔画, X, Y
		//画下方游戏界面
		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);
		
		
		//画食物
		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--) {//向前移动一节(每个身体都到上一节身体的坐标)
				//新生成的身体不可见
				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 > 4 && length < 13){
				level = 2;
				timer.stop();
				snake_Speed = 1000;
			}
	
			repaint();
		}
		timer.start();//定时器开始
	}
	
}

数据部分:

package com.zcy.JavaSE.GUI.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 = 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 = new ImageIcon(bodyURL);
	
	public static URL foodURL = Data.class.getResource("statics/food.png");
	public static ImageIcon food = new ImageIcon(foodURL);
	
}

图片素材保存目录:

Snake.statics

图片素材下载地址:

链接:百度网盘 下载地址
提取码:qbm4

初来乍到,请多关照。

我会写更多文章来分享我觉得有意义的项目,记录学习历程。

上一篇:Android连载41-复习四种基本布局


下一篇:设备事件