在跟着视频敲的时候出现了一些bug
可能是jdk版本问题 我用的jdk11
主要问题就是
随机玄学监听不到键盘事件
其他都是一些小问题了
可能和视频代码有出入,
一是因为改bug乱撞
二是看到24一半之后就自己敲着试试了
废话不多说上代码
package snake;
import javax.swing.*;
import java.awt.*;
//启动类 主窗口 创建游戏panel、添加监听
public class StartGame extends JFrame {
public StartGame(){
this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
this.setVisible(true);
this.setBounds(10,10,900,720);
this.setResizable(false);
Container container=this.getContentPane();
GamePanel panel=new GamePanel();
container.add(panel);
//监听不到键盘事件的bug在这里把监听放到Frame里就能完美解决
this.addKeyListener(panel);
this.setFocusable(true);
}
public static void main(String[] args) {
new StartGame();
}
}
package snake;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
//游戏主体部分
public class GamePanel extends JPanel implements KeyListener , ActionListener {
//数据域
Timer timer=new Timer(100,this);
String direction;
int length;
int[][] snake =new int[900][2];
int[] foodLocation;
int mark;
boolean reStart;
boolean derectionChange;
boolean isStart=false;
//初始化函数 游戏启动和重开时调用
public void init(){
length=3;
snake[0][0]=100;snake[0][1]=100;
snake[1][0]=75;snake[1][1]=100;
snake[2][0]=50;snake[2][1]=100;
foodLocation=putFood();
direction="R";
mark=0;
reStart=false;
derectionChange=false;
}
//游戏结束分数和重开提示
public void paintEnd(Graphics g){
g.setColor(Color.WHITE);
g.setFont(new Font("微软雅黑",Font.BOLD,40));
g.drawString("按下空格重新开始",285,420);
g.drawString("游戏结束!",285,340);
g.drawString("最终得分:"+String.format("%5d",mark),285,380);
g.setColor(Color.BLACK);
}
//画蛇、食物、开始暂停提示等
@Override
public void paint(Graphics g) {
//背景板绘制
super.paint(g);
setBackground(Color.WHITE);
Data.header.paintIcon(this,g,25,11);
g.fillRect(25,75,850,600);
//画食物
Data.food.paintIcon(this,g,foodLocation[0]+25,foodLocation[1]+75);
//画蛇头 需要判断方向
switch (direction){
case "R":
Data.right.paintIcon(this,g,snake[0][0]+25,snake[0][1]+75);
break;
case "L":
Data.left.paintIcon(this,g,snake[0][0]+25,snake[0][1]+75);
break;
case "U":
Data.up.paintIcon(this,g,snake[0][0]+25,snake[0][1]+75);
break;
case "D":
Data.down.paintIcon(this,g,snake[0][0]+25,snake[0][1]+75);
break;
}
//画身体
for (int i = 1; i<length; i++) {
Data.body.paintIcon(this,g,snake[i][0]+25,snake[i][1]+75);
}
//在暂停时提示空格开始
if(!isStart){
g.setColor(Color.WHITE);
g.setFont(new Font("微软雅黑",Font.BOLD,40));
g.drawString("按下空格开始游戏",285,380);
g.setColor(Color.BLACK);
}
//计分板
g.setColor(Color.RED);
g.setFont(new Font("微软雅黑",Font.BOLD,15));
g.drawString("分数:"+mark,700,50);
g.setColor(Color.BLACK);
}
//构造
public GamePanel() {
//setBackground(Color.BLACK);
init();
timer.start();
}
@Override
public void keyTyped(KeyEvent keyEvent) {
}
//键盘事件监听
@Override
public void keyPressed(KeyEvent keyEvent) {
//如果按下和游戏无关键位直接退出
if(keyEvent.getKeyCode()!=KeyEvent.VK_DOWN
&&keyEvent.getKeyCode()!=KeyEvent.VK_UP
&&keyEvent.getKeyCode()!=KeyEvent.VK_LEFT
&&keyEvent.getKeyCode()!=KeyEvent.VK_RIGHT
&&keyEvent.getKeyCode()!=KeyEvent.VK_SPACE){
return;
}
//获取按下键键码
int keyCode= keyEvent.getKeyCode();
/*
* 按下不同键位实行不同操作
* 空格开始/暂停游戏
* 上下左右键改变方向
* 注意:不能直接回头
* */
switch (keyCode){
case KeyEvent.VK_SPACE:
//判断:如果是游戏结束后重开,需要重新对游戏进行初始化操作
if(reStart){
init();
isStart=true;
break;
}
isStart=!isStart;
break;
case KeyEvent.VK_RIGHT:
//方向改变 先判断现在方向是不是和按键相反方向 如果是 不能转向
//同时 判定在一个定时器时间内是否已经进行过方向的改变
//如果是,那么不允许再次转向
//否则会出现两次快速转向自杀的情况(比如初始向右,快速连续按上左将会直接向左自杀)
//转向成功后把标记是否转向的变量置为Ture
if(direction!="L"){
if (direction!="R"&&!derectionChange){
direction="R";
derectionChange=true;
}
}
break;
case KeyEvent.VK_LEFT:
if(direction!="R"){
if (direction!="L"&&!derectionChange){
direction="L";
derectionChange=true;
}
}
break;
case KeyEvent.VK_UP:
if(direction!="D"){
if (direction!="U"&&!derectionChange){
direction="U";
derectionChange=true;
}
}
break;
case KeyEvent.VK_DOWN:
if(direction!="U"){
if (direction!="D"&&!derectionChange){
direction="D";
derectionChange=true;
}
}
break;
}
repaint();
}
@Override
public void keyReleased(KeyEvent keyEvent) {
}
//定时器操作
@Override
public void actionPerformed(ActionEvent actionEvent) {
//判断蛇头是否碰到身体,如果是 游戏结束打印计分板
for (int i = 1; i < length; i++) {
if(snake[0][0]==snake[i][0]&&snake[0][1]==snake[i][1]){
isStart=false;
paintEnd(this.getGraphics());
reStart=true;
return;
}
}
//游戏在进行状态下 蛇身向前移动 蛇头向现在所朝向的方向移动
if(isStart){
int[] temp={snake[0][0],snake[0][1]};
for (int i = length-1; i >0; i--) {
snake[i][0]=snake[i-1][0];
snake[i][1]=snake[i-1][1];
}
switch (direction){
case "R":
snake[0][0]+=25;
snake[0][0]%=850;
break;
case "L":
snake[0][0]+=825;
snake[0][0]%=850;
break;
case "U":
snake[0][1]+=575;
snake[0][1]%=600;
break;
case "D":
snake[0][1]+=25;
snake[0][1]%=600;
break;
}
repaint();
//重置转向的标记
derectionChange=false;
}
//判断是否吃到食物 如果吃到 加一节身体叠在现在最后一节身体上 让图像更平滑
//同时重新放置食物和加分
if (snake[0][0]==foodLocation[0]&&snake[0][1]==foodLocation[1]){
foodLocation=putFood();
length++;
snake[length-1][0]=snake[length-2][0];
snake[length-1][1]=snake[length-2][1];
mark+=50;
}
}
//放置食物,产生随机坐标 和蛇身比较,若和蛇身重合,则重新放置
public int[] putFood(){
int x=(int)(Math.random()*34);
int y=(int)(Math.random()*24);
x*=25;
y*=25;
for (int i = 0; i < length; i++) {
if(x==snake[i][0]&&y==snake[i][1]){
return putFood();
}
}
return new int[]{x,y};
}
}
package snake;
import javax.swing.*;
import java.net.URL;
//取得蛇身蛇头等元素
public class Data {
public static URL headerURL =Data.class.getResource("header.png");
public static URL upURL =Data.class.getResource("up.png");
public static URL downURL =Data.class.getResource("down.png");
public static URL leftURL =Data.class.getResource("left.png");
public static URL rightURL =Data.class.getResource("right.png");
public static URL foodURL =Data.class.getResource("food.png");
public static URL bodyURL =Data.class.getResource("body.png");
public static ImageIcon header=new ImageIcon(headerURL);
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 food=new ImageIcon(foodURL);
public static ImageIcon body=new ImageIcon(bodyURL);
}
教材链接~