没想到发的第一篇关于java的博客会是这个,写作业用来练手,顺道就搬上来了。
代码肯定不最优的,欢迎大家一起来探讨~
先搬个效果图~
然后结构~
一共分成4个部分,Define包下有蛇,食物和成绩数据的类,主要包括他们的初始化和像蛇的移动之类的东西;SetWindow包里是主函数的入口,包括窗口和面板的建立过程代码;RunPanel是游戏面板 ,大部分内容都在这个类里,最后是Resource包,包括图片的导入加载。
思路分析~
1、框架搭建,这是我一开始搞的,后面直接代码里小修改,做一件事总是要先规划规划怎么做
2、构建流程,当然,实际写代码时候我可没整这玩意,脑子里知道该做什么就好
之后就是源码~
窗体(游戏界面)MainScene:
package Game.SetWindow;
import Game.RunPanel;
import javax.swing.*;
public class MainScene extends JPanel{
//
public static void main(String[] args) {
//定义类
InterFace initwindow = new InterFace();
//建立基础界面
initwindow.InitWindow();
//建立游戏面板
initwindow.add(new RunPanel());
}
//内部类
static class InterFace extends JFrame {
//界面初始化函数
public void InitWindow() {
setTitle("贪吃蛇游戏 ——Woodenman杜"); //标题
setBounds(0, 0, 820, 820); //界面大小设定
setResizable(false); //设定大小不可改变
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //设定界面可关闭
setLocationRelativeTo(null); //设置屏幕中央打开
setVisible(true); //界面显示
}
}
}
图片加载A_LoadImg:
加了个A就是单纯为了让它排到最前面,其实在Game包下建个类导入可能更好看一点
package Resource;
import java.awt.*;
public class A_LoadImg {
//游戏标题
public static Image logo = Toolkit.getDefaultToolkit().getImage(A_LoadImg.class.getResource("/Resource/Logo.jpg"));
public static Image gamename = Toolkit.getDefaultToolkit().getImage(A_LoadImg.class.getResource("/Resource/Gname.jpg"));
//四个方向的蛇头
public static Image upsnake = Toolkit.getDefaultToolkit().getImage(A_LoadImg.class.getResource("/Resource/UpSnake.jpg"));
public static Image downsnake = Toolkit.getDefaultToolkit().getImage(A_LoadImg.class.getResource("/Resource/DownSnake.jpg"));
public static Image rightsnake = Toolkit.getDefaultToolkit().getImage(A_LoadImg.class.getResource("/Resource/RightSnake.jpg"));
public static Image leftsnake = Toolkit.getDefaultToolkit().getImage(A_LoadImg.class.getResource("/Resource/LeftSnake.jpg"));
//蛇身
public static Image body = Toolkit.getDefaultToolkit().getImage(A_LoadImg.class.getResource("/Resource/Body.jpg"));
//食物
public static Image food = Toolkit.getDefaultToolkit().getImage(A_LoadImg.class.getResource("/Resource/Food.jpg"));
}
蛇对象Snake:
package Game.Define;
public class Snake {
public int length; //蛇长
public int x[] = new int[60]; //蛇的x坐标
public int y[] = new int[60]; //蛇的y坐标
public char dir; //蛇的移动方向
//游戏状态
// 0未开始
// 1结束
// 2暂停
// 3进行中
// 5选择等级
// 6通关
public byte over;
public Snake() {
init();
}
//蛇的初始化
public void init(){
length = 4;
dir = 'R';
over = 0;
x[0] = 30+125; y[0] = 140+100;
x[1] = 30+100; y[1] = 140+100;
x[2] = 30+75; y[2] = 140+100;
x[3] = 30+50; y[3] = 140+100;
}
//蛇的移动和边界检测
public void go(){
//蛇身移动
for(int i = length-1; i > 0; i--){
x[i] = x[i-1];
y[i] = y[i-1];
}
//蛇头移动
if(dir == 'L')
{
x[0] -= 25;
if(x[0] < 30) over = 1;
}
else if(dir == 'R')
{
x[0] += 25;
if(x[0] > 755) over = 1;
}
else if(dir == 'U')
{
y[0] -= 25;
if(y[0] < 140) over = 1;
}
else if(dir == 'D')
{
y[0] += 25;
if(y[0] > 740) over = 1;
}
}
}
食物Food:
package Game.Define;
import java.util.Random;
public class Food {
//食物坐标
public int x;
public int y;
//随机数
Random random = new Random();
//构造体
public Food() {
init();
}
//建立新的食物点
public void set(){
x = 30 + 25*random.nextInt(30);
y = 140 + 25*random.nextInt(25);
}
//食物点初始化
public void init(){
x = 30 + 175;
y = 140 + 175;
}
}
成绩数据Score:
package Game.Define;
public class Score{
public int result; //游戏得分
public int grade; //游戏难度
public int PeopleGrade; //人工设定的游戏难度
//构造函数
public Score() {
init();
}
//数据初始化
public void init(){
result = 0;
PeopleGrade = 0;
grade = 1;
}
//等级判定
public int graded(int length){
return (length - 4) / 5 + 1;
}
//帧率判定(蛇的移动速度)
public int speed(int length){ return 250 - (length - 4) * 5; }
}
最后就是重头戏——游戏面板:
稍微说一下吧,首先对象需要画出来->画笔,键盘操控->键盘监听,实质是高帧率刷新->定时器
结构上:
首先所有的定义,定时器对象,内容对象等等
然后定时器,包括:游戏状态检测,是暂停了,选难度,还是游戏进行中;有没有吃到食物的判定;蛇是否碰到自身;界面刷新
之后键盘监听,顾名思义,就是所有会用到的按键识别,包括游戏状态、游戏难度、游戏操控的读入
最后画笔,包括基础背景界面,游戏界面的对象,各种内容提示的绘制
package Game;
import Game.Define.Food;
import Game.Define.Score;
import Game.Define.Snake;
import Resource.A_LoadImg;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class RunPanel extends JPanel implements ActionListener , KeyListener {
//构造函数
public RunPanel() {
//定时器启动
timer.start();
//键盘监听
this.setFocusable(true);
this.addKeyListener(this);
}
//定义
Snake snake = new Snake(); //snake
Food food = new Food(); //food
Score score = new Score(); //计分
int delay = 250;
boolean ans = false;
Timer timer = new Timer(250,this); //定时器
//定时器
@Override
public void actionPerformed(ActionEvent e) {
//是否为进行状态
if(snake.over == 3) snake.go();
if(score.PeopleGrade != 0){
delay = 250 - score.PeopleGrade*25;
score.grade = score.PeopleGrade;
timer.setDelay(delay);
}
//增长检测
if(snake.x[0] == food.x && snake.y[0]== food.y){
snake.length++; //长度更新
if(snake.length == 54) { snake.over = 6; } //通关判定
food.set(); //食物点更新
score.result += 1; //得分更新
//非人工选定难度状态下更新数据
if(score.PeopleGrade == 0)
{
delay = score.speed(snake.length) > 30 ? score.speed(snake.length) : 25; //帧率更新
score.grade = score.graded(snake.length); //等级更新
timer.setDelay(delay);
}
}
//碰撞检测
for(int i = 1; i < snake.length; i++){
if(snake.y[0] == snake.y[i] && snake.x[0] == snake.x[i]) snake.over = 1;
}
//界面刷新
repaint();
timer.start();
}
//键盘监听
@Override
public void keyPressed(KeyEvent e) {
//进入游戏状态
if(e.getKeyCode() == KeyEvent.VK_ENTER){
if(snake.over == 0) {
snake.over = 3; //初始到进行
//snake.init();
}
else if(snake.over == 1 || snake.over == 2){
snake.over = 0; //结束到初始
}
else if(snake.over == 3) snake.over = 0; //重置到初始状态
}
else if(e.getKeyCode() == KeyEvent.VK_SPACE){
//暂停或者进行状态转换
if(snake.over == 2) snake.over = 3;
else if(snake.over == 3) snake.over = 2;
}
else if(e.getKeyCode() == KeyEvent.VK_G && snake.over == 0){
snake.over = 5;
ans = true;
}
//难度控制
else if(e.getKeyCode() == KeyEvent.VK_1 && ans ){ score.PeopleGrade = 1; snake.over = 3; ans = false; }
else if(e.getKeyCode() == KeyEvent.VK_2 && ans ){ score.PeopleGrade = 2; snake.over = 3; ans = false; }
else if(e.getKeyCode() == KeyEvent.VK_2 && ans ){ score.PeopleGrade = 2; snake.over = 3; ans = false; }
else if(e.getKeyCode() == KeyEvent.VK_3 && ans ){ score.PeopleGrade = 3; snake.over = 3; ans = false; }
else if(e.getKeyCode() == KeyEvent.VK_4 && ans ){ score.PeopleGrade = 4; snake.over = 3; ans = false; }
else if(e.getKeyCode() == KeyEvent.VK_5 && ans ){ score.PeopleGrade = 5; snake.over = 3; ans = false; }
else if(e.getKeyCode() == KeyEvent.VK_6 && ans ){ score.PeopleGrade = 6; snake.over = 3; ans = false; }
else if(e.getKeyCode() == KeyEvent.VK_7 && ans ){ score.PeopleGrade = 7; snake.over = 3; ans = false; }
else if(e.getKeyCode() == KeyEvent.VK_8 && ans ){ score.PeopleGrade = 8; snake.over = 3; ans = false; }
else if(e.getKeyCode() == KeyEvent.VK_9 && ans ){ score.PeopleGrade = 9; snake.over = 3; ans = false; }
//方向控制
else if(e.getKeyCode() == KeyEvent.VK_DOWN){
if(snake.dir == 'U') snake.over = 1; else snake.dir = 'D';
}else if(e.getKeyCode() == KeyEvent.VK_UP){
if(snake.dir == 'D') snake.over = 1; else snake.dir = 'U';
}else if(e.getKeyCode() == KeyEvent.VK_LEFT){
if(snake.dir == 'R') snake.over = 1; else snake.dir = 'L';
}else if(e.getKeyCode() == KeyEvent.VK_RIGHT){
if(snake.dir == 'L') snake.over = 1; else snake.dir = 'R';
}
}
//绘画方法重写
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
//设置基础界面的颜色
setBackground(Color.orange);
//载入游戏标题图片
g.drawImage(A_LoadImg.logo,30,20,160,120,this);
g.drawImage(A_LoadImg.gamename, 190,20,420,120,this);
//画出游戏区域
g.setColor(Color.DARK_GRAY);
g.fillRect(30,140,750,625);
g.setColor(Color.GREEN);
g.drawRect(30,140,750,625);
//计分区域
g.setColor(Color.WHITE);
g.setFont(new Font("隶书",Font.BOLD,25));
g.drawString("长度" + snake.length,620,50);
g.setColor(Color.WHITE);
g.setFont(new Font("隶书",Font.BOLD,25));
g.drawString("得分" + score.result, 620,90);
g.setColor(Color.WHITE);
g.setFont(new Font("隶书",Font.BOLD,25));
g.drawString("游戏等级" + score.grade,620 ,130);
//绘制蛇
switch(snake.dir)
{
case 'L':
g.drawImage(A_LoadImg.leftsnake ,snake.x[0], snake.y[0], 25 ,25,this);
break;
case 'R':
g.drawImage(A_LoadImg.rightsnake ,snake.x[0], snake.y[0], 25 ,25,this);
break;
case 'U':
g.drawImage(A_LoadImg.upsnake ,snake.x[0], snake.y[0], 25 ,25,this);
break;
case 'D':
g.drawImage(A_LoadImg.downsnake ,snake.x[0], snake.y[0], 25 ,25,this);
break;
}
for (int i = 1; i < snake.length; i++) {
g.drawImage(A_LoadImg.body, snake.x[i], snake.y[i],25,25,this);
}
//绘制食物
g.drawImage(A_LoadImg.food, food.x, food.y, 25,25,this);
//游戏状态判断
// 0未开始 1结束 2暂停 3进行中 5选择等级 6通关
if(snake.over == 0){
//刷新界面
repaint();
//初始化
snake.init();
food.init();
score.init();
//显示设置
g.setColor(Color.WHITE);
g.setFont(new Font("华文彩云",Font.BOLD,70));
g.drawString("欢迎来到贪吃蛇游戏",70,400);
g.setColor(Color.CYAN);
g.setFont(new Font("楷书",Font.BOLD,30));
g.drawString("Enter 开始/重置游戏",250,480);
g.drawString("Space 暂停/继续游戏",250,530);
g.drawString("g 选择游戏等级",250,580);
g.drawString("箭头控制小蛇移动,长度54就~通关",200,670);
}
if(snake.over == 1){
g.setColor(Color.RED);
g.setFont(new Font("隶书",Font.BOLD,70));
g.drawString("Game Over!", 200,400);
}
else if(snake.over == 2){
g.setColor(Color.WHITE);
g.setFont(new Font("隶书",Font.BOLD,50));
g.drawString("游戏暂停,按下空格继续游戏",70,400);
}
if(snake.over == 5){
g.setColor(Color.orange);
g.setFont(new Font("隶书",Font.BOLD,50));
g.drawString("请选择游戏难度(1-9)",150,400);
}
if(snake.over == 6){
g.setColor(Color.red);
g.setFont(new Font("隶书",Font.BOLD,50));
g.drawString("恭喜你,游戏胜利!!!",150,400);
}
//repaint();
}
@Override public void keyTyped(KeyEvent e) {} @Override public void keyReleased(KeyEvent e) {}
}
我只是把这个类分开放了,代码原封不动。
这个的核心就是画笔(画图片),键盘监听,定时器,这三个搞定了也就写出来了,定时器用的是swing下的,util的我写一半卡住了,键盘监听写一半也卡住了...........所以,继续学习哈哈