在开始着手去做这个游戏之前,首先我们需要知道,我们看到的动态图画是一张张图片 然后通过一帧帧拼凑出来的。
那什么叫做帧呢?
帧数就是在1秒钟时间里传输的图片的帧数,也可以理解为图形处理器每秒钟能够刷新几次,它的单位通常用FPS(Frames Per Second)表示
打比方 例如用帧率这个量词来为字画,就可以称其为 一帧,
每一帧都是静止的图象,快速连续地显示帧便形成了运动的假象。高的帧率可以得到更流畅、更逼真的动画。每秒钟帧数 (fps) 愈多,所显示的动作就会愈流畅。
现在我们有了帧率的概念,有了帧率的概念,我们可以脑补到贪吃蛇的游戏界面是怎么制作成动态的了。那还需要键盘监听的事件,因为我们需要用键盘来进行游戏的控制,然后还需要一个定时器 Timer
先进行一波分析,界面绘制,我们会需要一个启动类,用来启动程序,然后肯定需要一个窗口容器的,窗口容器中,我们需要放进去我们的图片素材,素材要放在面板上,把面板在放进容器中,这样我们的界面大体就能绘制出来了。
经思路分析了之后,我们来具体实现一下。
package com.Gluttonous_Snake;
import javax.swing.*;
public class GameStart {
public static void main(String[] args) {
JFrame jFrame = new JFrame("兔C-贪吃蛇");
jFrame.setVisible(true); //可见性
jFrame.setResizable(false); //不可拉伸
jFrame.setBounds(220,200,900,720); //窗口弹出位置及大小
//将面板添加进容器当中
jFrame.add(new GamePanel());
jFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); //关闭事件
}
}
有了窗口容器,我们就可以设置面板了,把面板添加到容器当中,我们就可以实现贪吃蛇的第一步,但是再此之前,还需要先将准备的素材给设置好。
上面的图片 是我素材的存储,
然后现在需要创建一个类,将素材全部存进类里,然后面板需要素材的时候,通过调用这个类就能获取到里面的内容。
package com.Gluttonous_Snake;
import javax.swing.*;
import java.net.URL;
//贪吃蛇数据存储中心
public class GameData {
public static URL headerURL = GameData.class.getResource("statics/header.png");
public static Icon header = new ImageIcon(headerURL);
public static URL upURL = GameData.class.getResource("statics/up.png");
public static URL downURL = GameData.class.getResource("statics/down.png");
public static URL leftURL = GameData.class.getResource("statics/left.png");
public static URL rightURL = GameData.class.getResource("statics/right.png");
public static Icon up = new ImageIcon(upURL);
public static Icon down = new ImageIcon(downURL);
public static Icon left = new ImageIcon(leftURL);
public static Icon right = new ImageIcon(rightURL);
public static URL bodyURL = GameData.class.getResource("statics/body.png");
public static Icon body = new ImageIcon(bodyURL);
public static URL foodURL = GameData.class.getResource("statics/food.png");
public static Icon food = new ImageIcon(foodURL);
}
好了,现在有了容器,有了对素材的封装准备,我们可以设置面板了。
package com.Gluttonous_Snake;
import javax.swing.*;
import java.awt.*;
public class GamePanel extends JPanel {
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g); //不删此行,可实现屏幕清屏刷作用
//准备好图片后,开始绘制静态的面板
this.setBackground(Color.WHITE);
GameData.header.paintIcon(this,g,25,11); //绘制广告栏
g.fillRect(25,75,850,600); //绘制默认游戏界面
}
}
第一步做完了之后,我们来看一下效果
一个静态的界面我们准备完成了,现在马上开始第二步的下一阶段准备。
但是再次之前,需要注意图片的获取,路径的存放要规避好,是相对路径的获取方法,还是绝对路径的获取。不然会报 找不到图片资源的。
绘制静态的小蛇,我们知道小蛇的长度不是恒常不变的,所以可以借助数据结构来进行设置,我们用数组来存储静态的小蛇,而且还要给小蛇设置初始化值,那初始化值就会涉及到小蛇的初始长度,还有坐标位置。
具体操作我们还是先来看一下代码怎么写
//小蛇需要画在面板上,所以关于小蛇的代码 写在了面板类里
package com.Gluttonous_Snake;
import sun.security.util.LegacyAlgorithmConstraints;
import javax.swing.*;
import java.awt.*;
public class GamePanel extends JPanel {
//定义蛇的数据结构
int length; //蛇的长度
int[] snakeX = new int[600]; //蛇的 x 坐标 25*25
int[] snakeY = new int[500]; //蛇的 Y 坐标 25*25
String fx;
boolean flag = false;
//利用构造器调用初始化方法
public GamePanel(){
init();
}
//定义初始化方法,设置小蛇的初始化值
public void init(){
length = 3;
snakeX[0] =100; snakeY[0] =100; //小蛇脑袋的坐标
snakeX[1] =75; snakeY[1] =100; //小蛇第一节身体坐标
snakeX[2] =50; snakeY[2] =100; //小蛇第二节身体坐标
fx = "R";
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g); //不删此行,可实现屏幕清屏刷作用
//准备好图片后,开始绘制静态的面板
this.setBackground(Color.WHITE);
GameData.header.paintIcon(this,g,25,11); //绘制广告栏
g.fillRect(25,75,850,600); //绘制默认游戏界面
//把小蛇画到面板上
if (fx.equals("R")){
GameData.right.paintIcon(this,g,snakeX[0],snakeY[0]);
}else if (fx.equals("L")){
GameData.left.paintIcon(this,g,snakeX[0],snakeY[0]);
}else if (fx.equals("U")){
GameData.up.paintIcon(this,g,snakeX[0],snakeY[0]);
}else if (fx.equals("D")){
GameData.down.paintIcon(this,g,snakeX[0],snakeY[0]);
}
for (int i = 1; i < length; i++) {
GameData.body.paintIcon(this,g,snakeX[i],snakeY[i]);
}
if (flag == false){
g.setColor(Color.white);
g.setFont(new Font("微软雅黑",Font.BOLD,40));
g.drawString("按下空格开始游戏!",300,300);
}
}
}
我们在来梳理一下流程,在原来的游戏面板上,加入小蛇的相关代码。借助数组的数据结构对小蛇进行设置。
先设置小蛇长度的初始化变量,然后是坐标位置。
在初始化方法当中,设置小蛇的初始化长度,还有小蛇的第一节身体,和第二节身体,因为小蛇的默认长度是3节(加上脑袋)。设置好了小蛇长度的初始化方法,利用构造器进行调用,因为我们知道,对象的初始化值是通过构造器来赋值的。
紧接着,在到绘画方法当中,将小蛇画出来,因为小蛇的默认移动方向是向右的,所以又加了一个控制方向的变量,然后进行判断,如果是向右的那头向右,反正向左,,向下,,或者是上。
设置好了小蛇的相关内容,我们还需要一个游戏暂停或者开始的判断状态,如果是暂停的,就在游戏界面上展示相关提示,所以加了一个flag,然后进行判断,将提示游戏画到了游戏界面上。
对上述代码进行了总结,我们在看一下现在的代码状态,展示效果图::
顾名思义,就是点击空格的时候,提示的按下空格开始游戏的字体会消失,在按会出现。
这个操作很简单,实现监听接口,重写个方法,最后在初始化方法中加个焦点事件和监听事件就好了。看Code,对喽,就是继续在面板中设置就好了。
package com.Gluttonous_Snake;
import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
public class GamePanel extends JPanel implements KeyListener {
//定义蛇的数据结构
int length; //蛇的长度
int[] snakeX = new int[600]; //蛇的 x 坐标 25*25
int[] snakeY = new int[500]; //蛇的 Y 坐标 25*25
String fx;
boolean flag = false;
//利用构造器调用初始化方法
public GamePanel(){
init();
//获得焦点和键盘事件
this.setFocusable(true);
this.addKeyListener(this);
}
//定义初始化方法,设置小蛇的初始化值
public void init(){
length = 3;
snakeX[0] =100; snakeY[0] =100; //小蛇脑袋的坐标
snakeX[1] =75; snakeY[1] =100; //小蛇第一节身体坐标
snakeX[2] =50; snakeY[2] =100; //小蛇第二节身体坐标
fx = "R";
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g); //不删此行,可实现屏幕清屏刷作用
//准备好图片后,开始绘制静态的面板
this.setBackground(Color.WHITE);
GameData.header.paintIcon(this,g,25,11); //绘制广告栏
g.fillRect(25,75,850,600); //绘制默认游戏界面
//把小蛇画到面板上
if (fx.equals("R")){
GameData.right.paintIcon(this,g,snakeX[0],snakeY[0]);
}else if (fx.equals("L")){
GameData.left.paintIcon(this,g,snakeX[0],snakeY[0]);
}else if (fx.equals("U")){
GameData.up.paintIcon(this,g,snakeX[0],snakeY[0]);
}else if (fx.equals("D")){
GameData.down.paintIcon(this,g,snakeX[0],snakeY[0]);
}
for (int i = 1; i < length; i++) {
GameData.body.paintIcon(this,g,snakeX[i],snakeY[i]);
}
if (flag == false){
g.setColor(Color.white);
g.setFont(new Font("微软雅黑",Font.BOLD,40));
g.drawString("按下空格开始游戏!",300,300);
}
}
//键盘监听事件
@Override
public void keyPressed(KeyEvent e) {
int keyCode = e.getKeyCode();
if (keyCode == KeyEvent.VK_SPACE){
flag = !flag; //取反值,如果直接取值会写死的
repaint();
}
}
@Override
public void keyTyped(KeyEvent e) {
}
@Override
public void keyReleased(KeyEvent e) {
}
}
我们这里就把这个思路梳理清楚就好了,效果图展示与不展示都没有什么意义,无非就是按下空格 游戏界面上没有了提示的字样,在按一下 字样就显示出来了,这里还没有设置别的东西,没有必要展示出来的意义。
这里我遇到了一个问题,如果朋友们是按照我这个博文思路也会遇到这个问题,这个问题就是:当我们的代码开发到这一步的时候,按下空格 看效果的时候,发现游戏界面上的提示信息并没有受控,按爆了空格也没好用。
开始我以为是监听不到,单独定义了监听类,然后在面板中添加监听事件的时候,new 了一下自己写的监听类,结果还是不好用。
其实这个问题是因为焦点事件没有成功,在不改代码的情况下,按一下table键 然后在进行操作也有用。其实根本的问题是因为在启动类中设置的窗口可见性,写早了,应该放在代码的最后,这个不用太过思索,窗口可见性 程序走完在可见很合乎逻辑的啊,没走完就可见了,代码里面的优先级问题牵扯到,肯定会有部分功能实现不出来的。毕竟没可见的。把窗口可见性放到最后一行,即 setVisible(true);
.
这里我们需要添加一个事件监听,然后这个监听需要通过定时器来进行辅助,之后的效果就是让其根据固定的时间来进行刷新。
所以:
这里我们就需要在面板类中添加个全局变量—> Time;这个对象会有两个参数,第一个参数是设置的毫秒数,第二个参数是要监听的对象。
有了这个定时器对象,我们在用对象名 调用它的start 开启方法,就可以开启一个定时器了。
在下一步,需要在新添加的监听事件方法里写逻辑了。
就是判断监听器是否是开启的状态,如果是开启的状态,就让小蛇动起来。
我们先来看一下代码吧
package com.Gluttonous_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 {
//定义蛇的数据结构
int length; //蛇的长度
int[] snakeX = new int[600]; //蛇的 x 坐标 25*25
int[] snakeY = new int[500]; //蛇的 Y 坐标 25*25
String fx;
boolean flag = false;
//定时器 以毫秒为单位,1000ms =1s
Timer timer = new Timer(100,this); //100毫秒执行一次定时器
//利用构造器调用初始化方法
public GamePanel(){
init();
//获得焦点和键盘事件
this.setFocusable(true);
this.addKeyListener(this);
timer.start(); //开启定时器
}
//定义初始化方法,设置小蛇的初始化值
public void init(){
length = 3;
snakeX[0] =100; snakeY[0] =100; //小蛇脑袋的坐标
snakeX[1] =75; snakeY[1] =100; //小蛇第一节身体坐标
snakeX[2] =50; snakeY[2] =100; //小蛇第二节身体坐标
fx = "R";
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g); //不删此行,可实现屏幕清屏刷作用
//准备好图片后,开始绘制静态的面板
this.setBackground(Color.WHITE);
GameData.header.paintIcon(this,g,25,11); //绘制广告栏
g.fillRect(25,75,850,600); //绘制默认游戏界面
//把小蛇画到面板上
if (fx.equals("R")){
GameData.right.paintIcon(this,g,snakeX[0],snakeY[0]);
}else if (fx.equals("L")){
GameData.left.paintIcon(this,g,snakeX[0],snakeY[0]);
}else if (fx.equals("U")){
GameData.up.paintIcon(this,g,snakeX[0],snakeY[0]);
}else if (fx.equals("D")){
GameData.down.paintIcon(this,g,snakeX[0],snakeY[0]);
}
for (int i = 1; i < length; i++) {
GameData.body.paintIcon(this,g,snakeX[i],snakeY[i]);
}
if (flag == false){
g.setColor(Color.white);
g.setFont(new Font("微软雅黑",Font.BOLD,40));
g.drawString("按下空格开始游戏!",300,300);
}
}
@Override
public void actionPerformed(ActionEvent e) {
if (flag){ //如果游戏是开始状态,让小蛇开始动起来
//右移
for (int i = length-1; i >0 ; i--) {
snakeX[i] = snakeX[i-1];
snakeY[i] = snakeY[i-1];
}
snakeX[0] = snakeX[0]+25;
//加边界判断,为防止小蛇一去不复返
if (snakeX[0] >850){
snakeX[0] = 25; //重新赋值,让其归位
}
repaint(); //重画界面
}
timer.start(); //定时器开始!
}
@Override
public void keyPressed(KeyEvent e) {
int keyCode = e.getKeyCode();
if (keyCode == KeyEvent.VK_SPACE){
flag = (!flag); //取反值,如果直接取值会写死的
repaint();
}
}
@Override
public void keyTyped(KeyEvent e) {
}
@Override
public void keyReleased(KeyEvent e) {
}
}
嚯 ~ 整个面板对象里的代码 全贴了一遍。 有点乱奥,但是全贴出来 好梳理,我怕文章的节奏会乱。
来梳理一下:
这里先不放效果图了,一条蛇无限循环的一直向右来回的跑,没意义。现在小蛇是能动了。所以我们赶快进行下一步,让键盘操控小蛇上下左右进行移动。
我们需要现在键盘监听中 监听键盘的↑↓←→按键,然后给之前方向的变量重新赋值即可。
if (keyCode == KeyEvent.VK_UP){
fx ="U";
}else if (keyCode == KeyEvent.VK_DOWN){
fx = "D";
}else if (keyCode == KeyEvent.VK_LEFT){
fx = "L";
}else if (keyCode == KeyEvent.VK_RIGHT){
fx = "R";
}
}
加上了新的按键监听事件,然后还需要在小蛇的走向控制中设置方向改变后的走向。 就是修改一下监听事件方法里的逻辑。
@Override
public void actionPerformed(ActionEvent e) {
if (flag){ //如果游戏是开始状态,让小蛇开始动起来
//右移
for (int i = length-1; i >0 ; i--) {
snakeX[i] = snakeX[i-1];
snakeY[i] = snakeY[i-1];
}
if (fx.equals("R")){
snakeX[0] = snakeX[0]+25;
//加边界判断,为防止小蛇一去不复返
if (snakeX[0] >850){snakeX[0] = 25;}
}else if (fx.equals("L")){
snakeX[0] = snakeX[0]-25;
if (snakeX[0] <25){snakeX[0] =850;}
}else if (fx.equals("U")){
snakeY[0] = snakeY[0]-25;
if (snakeY[0] <75){snakeX[0] =650;}
}else if(fx.equals("D")){
snakeY[0] = snakeY[0]+25;
if (snakeY[0] >650){snakeX[0] =75;}
}
repaint(); //重画界面
}
timer.start(); //定时器开始!
}
现在的小蛇就可以进行上下左右的按键控制移动了
…我还没把文章叙述出来,写完忍不住…就先玩起来了。
很简单,先定义事物的坐标,x y 坐标都要有,然后创建一个随机数对象,因为食物是在随机的位置上出来的,之后将计算好的食物坐标画到面板上,然后在监听事件里加个判断,如果小蛇的坐标和食物的坐标重合,那小蛇的长度就加1。
看下面的代码自己梳理一下目前为止的逻辑::
package com.Gluttonous_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;
import java.util.Random;
public class GamePanel extends JPanel implements KeyListener, ActionListener {
//定义蛇的数据结构
int length; //蛇的长度
int[] snakeX = new int[600]; //蛇的 x 坐标 25*25
int[] snakeY = new int[500]; //蛇的 Y 坐标 25*25
String fx;
//小蛇的食物设置
int foodx;
int foody;
Random random = new Random();
boolean flag = false;
//定时器 以毫秒为单位,1000ms =1s
Timer timer = new Timer(100,this); //100毫秒执行一次定时器
//利用构造器调用初始化方法
public GamePanel(){
init();
//获得焦点和键盘事件
this.setFocusable(true);
this.addKeyListener(this);
timer.start(); //开启定时器
}
//定义初始化方法,设置小蛇的初始化值
public void init(){
length = 3;
snakeX[0] =100; snakeY[0] =100; //小蛇脑袋的坐标
snakeX[1] =75; snakeY[1] =100; //小蛇第一节身体坐标
snakeX[2] =50; snakeY[2] =100; //小蛇第二节身体坐标
fx = "R";
//将食物分布在界面上
foodx = 25 + 25*random.nextInt(34);
foody = 75 + 25*random.nextInt(24);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g); //不删此行,可实现屏幕清屏刷作用
//准备好图片后,开始绘制静态的面板
this.setBackground(Color.WHITE);
GameData.header.paintIcon(this,g,25,11); //绘制广告栏
g.fillRect(25,75,850,600); //绘制默认游戏界面
//把小蛇画到面板上
if (fx.equals("R")){
GameData.right.paintIcon(this,g,snakeX[0],snakeY[0]);
}else if (fx.equals("L")){
GameData.left.paintIcon(this,g,snakeX[0],snakeY[0]);
}else if (fx.equals("U")){
GameData.up.paintIcon(this,g,snakeX[0],snakeY[0]);
}else if (fx.equals("D")){
GameData.down.paintIcon(this,g,snakeX[0],snakeY[0]);
}
GameData.food.paintIcon(this,g,foodx,foody);
for (int i = 1; i < length; i++) {
GameData.body.paintIcon(this,g,snakeX[i],snakeY[i]);
}
if (flag == false){
g.setColor(Color.white);
g.setFont(new Font("微软雅黑",Font.BOLD,40));
g.drawString("按下空格开始游戏!",300,300);
}
}
@Override
public void actionPerformed(ActionEvent e) {
if (flag){ //如果游戏是开始状态,让小蛇开始动起来
//吃食物的操作
if (snakeX[0] == foodx && snakeY[0] == foody){
length++;
foodx = 25 + 25*random.nextInt(34);
foody = 75 + 25*random.nextInt(24);
}
//右移
for (int i = length-1; i >0 ; i--) {
snakeX[i] = snakeX[i-1];
snakeY[i] = snakeY[i-1];
}
if (fx.equals("R")){
snakeX[0] = snakeX[0]+25;
//加边界判断,为防止小蛇一去不复返
if (snakeX[0] >850){snakeX[0] = 25;}
}else if (fx.equals("L")){
snakeX[0] = snakeX[0]-25;
if (snakeX[0] <25){snakeX[0] =850;}
}else if (fx.equals("U")){
snakeY[0] = snakeY[0]-25;
if (snakeY[0] <75){snakeY[0] =650;}
}else if(fx.equals("D")){
snakeY[0] = snakeY[0]+25;
if (snakeY[0] >650){snakeY[0] =75;}
}
repaint(); //重画界面
}
timer.start(); //定时器开始!
}
@Override
public void keyPressed(KeyEvent e) {
int keyCode = e.getKeyCode();
if (keyCode == KeyEvent.VK_SPACE){
flag = (!flag); //取反值,如果直接取值会写死的
repaint();
}
if (keyCode == KeyEvent.VK_UP){
fx ="U";
}else if (keyCode == KeyEvent.VK_DOWN){
fx = "D";
}else if (keyCode == KeyEvent.VK_LEFT){
fx = "L";
}else if (keyCode == KeyEvent.VK_RIGHT){
fx = "R";
}
}
@Override
public void keyTyped(KeyEvent e) {
}
@Override
public void keyReleased(KeyEvent e) {
}
}
我已经非常努力的再写了,我不知道这样写博客是好还是不好,太过冗长,可能有很多没用的内容,或者说是可以省略的内容,但是我还是尽全力在叙述着。。过于啰嗦。。太追求文章的完整性了。
三部曲:
一会在贴代码,上边叙述的有点乱。
其实所谓的三部曲就是 先设置遍历,设置好了变量,就给它画到面板上,画好之后在监听事件中添加新的逻辑,无非就是键盘监听或者是事件监听里进行添加。
上述内容有点乱的问题,看一下代码就明白了,写好积分计算一起贴出来,就几行代码,没必要重新贴一遍了。
同上 三部曲,直接看代码吧,我贴出来
package com.Gluttonous_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;
import java.util.Random;
public class GamePanel extends JPanel implements KeyListener, ActionListener {
//定义蛇的数据结构
int length; //蛇的长度
int[] snakeX = new int[600]; //蛇的 x 坐标 25*25
int[] snakeY = new int[500]; //蛇的 Y 坐标 25*25
String fx;
//小蛇的食物设置
int foodx;
int foody;
Random random = new Random();
boolean flag = false;
boolean isFile = false;
int score;
//定时器 以毫秒为单位,1000ms =1s
Timer timer = new Timer(115,this); //100毫秒执行一次定时器
//利用构造器调用初始化方法
public GamePanel(){
init();
//获得焦点和键盘事件
this.setFocusable(true);
this.addKeyListener(this);
timer.start(); //开启定时器
}
//定义初始化方法,设置小蛇的初始化值
public void init(){
length = 3;
snakeX[0] =100; snakeY[0] =100; //小蛇脑袋的坐标
snakeX[1] =75; snakeY[1] =100; //小蛇第一节身体坐标
snakeX[2] =50; snakeY[2] =100; //小蛇第二节身体坐标
fx = "R";
//将食物分布在界面上
foodx = 25 + 25*random.nextInt(34);
foody = 75 + 25*random.nextInt(24);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g); //不删此行,可实现屏幕清屏刷作用
//准备好图片后,开始绘制静态的面板
this.setBackground(Color.WHITE);
GameData.header.paintIcon(this,g,25,11); //绘制广告栏
g.fillRect(25,75,850,600); //绘制默认游戏界面
g.setColor(Color.white);
g.setFont(new Font("微软雅黑",Font.BOLD,18));
g.drawString("长度:"+length,765,30);
g.drawString("积分:"+score,765,55);
GameData.food.paintIcon(this,g,foodx,foody);//食物的绘画放在小蛇的上边,不然会压住小蛇
//把小蛇画到面板上
if (fx.equals("R")){
GameData.right.paintIcon(this,g,snakeX[0],snakeY[0]);
}else if (fx.equals("L")){
GameData.left.paintIcon(this,g,snakeX[0],snakeY[0]);
}else if (fx.equals("U")){
GameData.up.paintIcon(this,g,snakeX[0],snakeY[0]);
}else if (fx.equals("D")){
GameData.down.paintIcon(this,g,snakeX[0],snakeY[0]);
}
for (int i = 1; i < length; i++) {
GameData.body.paintIcon(this,g,snakeX[i],snakeY[i]);
}
if (flag == false){
g.setColor(Color.white);
g.setFont(new Font("微软雅黑",Font.BOLD,40));
g.drawString("按下空格开始游戏!",300,300);
}
if (isFile){
g.setColor(Color.red);
g.setFont(new Font("微软雅黑",Font.BOLD,40));
g.drawString("按下空格重新开始!",300,300);
}
}
@Override
public void actionPerformed(ActionEvent e) {
if (flag && isFile == false){ //如果游戏是开始状态,让小蛇开始动起来
//吃食物的操作
if (snakeX[0] == foodx && snakeY[0] == foody){
length++;
score+=10;
foodx = 25 + 25*random.nextInt(34);
foody = 75 + 25*random.nextInt(24);
}
//右移
for (int i = length-1; i >0 ; i--) {
snakeX[i] = snakeX[i-1];
snakeY[i] = snakeY[i-1];
}
if (fx.equals("R")){
snakeX[0] = snakeX[0]+25;
//加边界判断,为防止小蛇一去不复返
if (snakeX[0] >850){snakeX[0] = 25;}
}else if (fx.equals("L")){
snakeX[0] = snakeX[0]-25;
if (snakeX[0] <25){snakeX[0] =850;}
}else if (fx.equals("U")){
snakeY[0] = snakeY[0]-25;
if (snakeY[0] <75){snakeY[0] =650;}
}else if(fx.equals("D")){
snakeY[0] = snakeY[0]+25;
if (snakeY[0] >650){snakeY[0] =75;}
}
for (int i = 1; i < length; i++) {
if (snakeX[0] == snakeX[i] && snakeY[0] == snakeY[i]){
isFile = true;
}
}
repaint(); //重画界面
}
timer.start(); //定时器开始!
}
@Override
public void keyPressed(KeyEvent e) {
int keyCode = e.getKeyCode();
if (keyCode == KeyEvent.VK_SPACE){
if (isFile){
isFile = false;
init();
}else {
flag = (!flag); //取反值,如果直接取值会写死的
}
repaint();
}
if (keyCode == KeyEvent.VK_UP){
fx ="U";
}else if (keyCode == KeyEvent.VK_DOWN){
fx = "D";
}else if (keyCode == KeyEvent.VK_LEFT){
fx = "L";
}else if (keyCode == KeyEvent.VK_RIGHT){
fx = "R";
}
}
@Override
public void keyTyped(KeyEvent e) {
}
@Override
public void keyReleased(KeyEvent e) {
}
}
.