贪吃蛇大作战技术报告(JAVA)

 完整作品见链接:JAVA贪吃蛇大作战大作业_Java贪吃蛇如何实现向左不能向右资源-CSDN文库


猫猫大作战技术报告

1、项目概述

       本项目的编译环境为jdk-19,用到的编译器为Eclipse,采用图形化编程,基于JAVA的Swing库进行界面的绘制,基于Timer类进行动态任务执行。

       本项目包括两个页面:游戏规则介绍页面和游戏界面。游戏开始时,首先展示游戏规则介绍页面,玩家阅读规则后按下Enter键即可开始游戏。游戏开始后,跳转到游戏界面,玩家通过按下空格键正式开始游戏。在游戏中,玩家将遇到小鱼干、炸弹和电脑NPC。玩家需要通过吃掉电脑NPC的身体,使其长度减少到小于3,以取得胜利。同时,玩家还可以通过吃小鱼干来增加自己的长度和速度,增强胜利的能力。每局游戏结束后,会进行计分和最高纪录的统计。玩家可以按下空格键重新开始无限次对决,也可以按下Esc键结束整个游戏,并记录最高得分。

       其中游戏界面的初始界面(按下空格键可暂停或开始),运行效果如下:

         其中,玩家初始状态方向向右,停留在左上角;电脑NPC初始状态方向向左,停留在右下角;界面上的“Press the space bar to start”提示按下空格键开始;玩家活动界面上还有5个小鱼干和1个炸弹;最右侧一栏是当前的状态栏,包含玩家及电脑蛇长度及速度、比分、最高分的相关信息。

2、系统总体功能设计

2.1游戏规则

       本游戏采取玩家与电脑对决的形式进行,采用得分制,可无限循环畅玩。简易规则界面(同时也是本游戏的游戏规则介绍页面,按下Enter键开始),具体展示如下:

         本游戏通过上下左右的按键来控制玩家黑色猫猫的移动方向,电脑蛇是随机移动的,猫猫可穿墙移动。

       单局游戏结束的判断条件:若其中一方蛇的长度小于3,则判定游戏结束,本游戏结束共3个状态,若是玩家(黑蛇)长度小于3,则判定玩家失败,电脑得分加一;若是电脑(黄蛇)长度小于3,则判定为玩家胜利,玩家得分加一;若玩家与电脑头相撞,则判定为平局,双方都不加得分。示意图如下:

          玩家与电脑可以通过互相吃对方的身体使得对方的长度小于3而将对方杀死,其中,关于玩家吃电脑身体的细节图像化展示如下(电脑吃玩家也同理):

        玩家或者电脑在吃到小鱼干时候,长度会加一,同时速度和分数也会对应增加,一个小鱼干增加速度1,分数10。具体示意图如下:

         玩家或者电脑在吃到炸弹时候,长度会减一,同时速度和分数也会对应减少,一个小鱼干减少速度1,分数10。同时,被炸到后的蛇会陷入短暂晕眩状态,不能动弹,也增加了被其他蛇吃掉的危险性,具体示意图如下:

        同时,本游戏可通过按空格键实现一局游戏的开始与暂停,按下Esc键即可实现游戏的结束。  

2.2面向对象类的设计

       本游戏共设计了三个类,包括Snake(游戏启动类)、 RuleForm(游戏规则介绍界面类)、Snake_Panel(游戏运行类)。

1 Snake(游戏启动类)

       该类通过Java的Swing库中的Jframe类,实现对窗口的创建与设计,并规定窗口的大小(1115*780),同时通过调用Snake_Panel类实现游戏的开始。

2 RuleForm(游戏规则介绍界面类)

       该类通过加载实现设计好的关于游戏规则的界面的图片并添加到页面,实现游戏规则的显示。

3 Snake_Panel(游戏启动类)

       该类是本项目的核心部分,实现了界面调用及各个功能的实现,还包括背景音乐及音效的设置,具体实现展现在后文。

2.3功能模块设计

       本文将从以下界面跳转、界面暂停、蛇的移动、蛇的变速、蛇的对抗、蛇的捕食、蛇的晕眩、蛇游戏背景音乐及、数据保存九个方面对该项目进行一个展示。具体流程图绘制如下:

3、代码实现

       本文就Snake_Panel类的代码实现进行一个详细讲解,具体如下:

3.1 变量设计

       1、我们定义一个结构体Coordinate来存储每一个对象(包含猫头、猫身、小鱼干、炸弹)的坐标信息。对应代码如下:

public class Coordinate {

           public int x, y;

}

       2、我们基于结构体Coordinate定义玩家蛇和电脑蛇各个部位的坐标列表及食物的坐标列表,还有炸弹的坐标。对应变量声明如下:

ArrayList<Coordinate> snakeBody;//玩家蛇各个部位的坐标列表

ArrayList<Coordinate> enemy_snakeBody; //电脑蛇各个部位的坐标列表

ArrayList<Coordinate> fishList;// 食物的坐标列表

       3、我们定义ImageIcon类型变量用于存储即将需要用到的图片。对应变量声明格式为“ImageIcon+Name”,具体变量名对应如下:

变量名

解释

变量名

解释

Rule

游戏规则介绍界面

down

玩家蛇方向向下的蛇头

title

游戏标题

left

玩家蛇方向向左的蛇头

state

状态栏标题

right

玩家蛇方向向右的蛇头

fish

食物

enemy_up

电脑蛇方向向上的蛇头

bomb

炸弹

enemy_down

电脑蛇方向向下的蛇头

bo

玩家蛇的身体

enemy_left

电脑蛇方向向左的蛇头

up

玩家蛇方向向上的蛇头

enemy_right

电脑蛇方向向右的蛇头

      

       4、我们定义boolean类型变量用于表示当前的状态,对应变量声明格式为“boolean+Name”,具体变量名对应如下:

变量名

解释

isRuleEnd

游戏规则是否阅读完毕

isStart

游戏是否开始

isFailed

本局游戏是否失败

isWined

本局游戏是否胜利

isEqual

本局游戏是否平局

isBomb

玩家蛇是否被眩晕

enemy_isBomb

电脑蛇是否被眩晕

      

       5、我们定义Clip类型变量用于表示背景音乐及音效,对应变量声明格式为“Clip+Name”,具体变量名对应如下:

变量名

解释

bgm

背景音乐

eatbgm

吃到食物的音效

bombbgm

吃到炸弹的音效

       6、我们定义Random类型变量rand用于生成随机数。

       7、我们定义int类型的变量表示各个参数,具体变量名对应如下:

变量名

解释

变量名

解释

BlackValue

玩家比分

score

玩家得分

YellowValue

电脑比分

speedValue

玩家速度

maxValue

玩家最高得分

enemy_speedValue

电脑速度

initSpeed

玩家速度上限

enemy_snakeLen

电脑长度

enemy_initSpeed

电脑速度上限

bBomb

玩家晕眩计时

vd

用于随机变换方向

enemy_bBomb

电脑晕眩计时

foodNum

食物数量

bombTime

晕眩时间

snakeLen

蛇的长度

3.1 主要控制的设计

Snake_Panel的构造函数

public Snake_Panel()

{

              loadImage();//加载图片的封装函数

              initSnake();//初始化玩家蛇

              enemy_initSnake();//初始化电脑蛇

              this.setFocusable(true);//可获取键盘事件

              this.addKeyListener(this);//添加键盘监听器

              timer.start();//开始游戏运行

              loadbgm();//加载音乐及音效

              enemyTimer.start();//开始敌人蛇的运行

}

3.2 页面绘制(paintComponent)

       本文通过paintComponent实现界面的绘制,同时其对应的repaint()函数可实现对界面的刷新。由于代码量过大,本文仅对核心部分进行介绍。

       1、设置背景颜色

this.setBackground(new Color(100,100,100));

       2、设置颜色

g.setColor(new Color(224,224,224));

       3、设置添加的位置(x:25,y:125)及宽高(width:850,Height:600)

g.fillRect(25,125,850,600);

       4、设置字体(arial)及大小(30)

g.setFont(new Font("arial",Font.BOLD,30));

       5、添加文字,并设置其添加的坐标

g.drawString("BlackCat",900,145);

       6、蛇的绘制,分成两部分:蛇头的绘制、蛇身的绘制。由于玩家和敌人蛇的绘制方式一样,对于敌人蛇的绘制讲解省略。

       蛇头的绘制(下标为1),其中,U、D、L、R分别对应上、下、左、右的蛇头方向,通过switch-case对代码进行简化。

switch(direction)

{

       case "U":up.paintIcon(this, g, coordinate.x, coordinate.y);break;

       case "D":down.paintIcon(this, g, coordinate.x, coordinate.y);break;

       case "L":left.paintIcon(this, g, coordinate.x, coordinate.y);break;

       case "R":right.paintIcon(this, g, coordinate.x, coordinate.y);break;

}

       蛇身的绘制(从1开始),通过循环遍历蛇身体的每一个坐标进行绘制

for(int i = 1;i < snakeLen; i++)

{

       coordinate = snakeBody.get(i);

       bo.paintIcon(this, g, coordinate.x, coordinate.y);

}

       7、食物的绘制(本游戏设置默认食物的数量为5)

for (int i = 0; i < fishList.size();i++) {

       coordinate = fishList.get(i);//获取食物的坐标

       fish.paintIcon(this, g, coordinate.x, coordinate.y);//根据食物的坐标绘制食物

}

       8、绘制炸弹

bomb.paintIcon(this, g, newBomb.x, newBomb.y);

       9、空白键提示文字绘制

if(!isStart)//isStart控制游戏的开始状态

{

       //提示信息

       g.setColor(Color.WHITE);//设置颜色

       g.setFont(new Font("arial",Font.BOLD,40));//设置字体,字体大小40          g.drawString("Press the space bar to start",180,300);

}

       10、游戏胜负及平局的判断,由于代码相似,这里仅展示游戏失败的代码,每次游戏结束都会更新一次胜负比分及玩家最高得分。

if(isFailed)

{

       YellowValue++;//敌人胜利,得分加一

       g.setColor(Color.RED);//设置字体颜色为红色

       g.setFont(new Font("arial",Font.BOLD,50));//设置字体及字体大小

       g.drawString("Game Over",300,300);//设置显示的文字及位置

       if(maxValue < score) maxValue = score;//更新玩家最高得分

}

       11、跳转界面,其中isRuleEnd表示玩家看规则是否看完的状态,若玩家看完了,其值为1,否则,其值为0。Rule即笔者绘制的游戏规则介绍界面

if(!isRuleEnd)

{

       Rule.paintIcon(this, g, -45, 0);

}

3.3 随机位置更新

       由于食物与炸弹的位置更新同理,本文仅对食物的位置更新进行详细介绍,其中,游戏界面的长为850,宽为600,其二维直角坐标系的绘制如下:

          本游戏界面中的每个小方块的长宽均为25,故实际的大小为(33*19),每个小方块左上角的位置表示该小方块的坐标,为保证生成的坐标信息不与小方块的摆放错位,即保证生成随机数可以在小方块的坐标集合中,我们通过方块映射的方式进行实现,具体示意图如下:

        接着将被吃掉的食物的坐标更新为生成的新坐标,并移除原先的旧坐标,具体代码如下:

Coordinate newFish = new Coordinate();

newFish.x = 25 + 25 * rand.nextInt(33);//生成随机坐标

newFish.y = 125 + 25 * rand.nextInt(19); //生成随机坐标

fishList.add(newFish);//将生成的新食物加入当前食物列表

if(i!=-1)

       fishList.remove(i); //将吃掉的食物移除

3.4 初始化initSnake

       为实现游戏可以无限次重新开局,我们需要设置一个初始化的函数,对游戏参数初始化为开局的状态(玩家蛇头初始方向设置为右,位于左上角,电脑蛇头初始方向为左,位于右下角,并随机生成若干个食物及一个炸弹)。这里仅展示蛇各个部位身体坐标初始化:

for(int i = 0; i < snakeLen; i++)

{

        Coordinate coordinate = new Coordinate();

        coordinate.y = 125;

        coordinate.x = 100 - i * 25;

        snakeBody.add(coordinate);

}

3.4 按键事件keyPressed

       通过键盘监听器,我们对各个按键对应的事件进行设置,为提高代码的美观度及清晰度,我们同样采用switch-case的方式列出各个按键对应的功能:

       首先我们通过如下代码获取用户按下的按键信息:

int KeyCode = e.getKeyCode();

       Enter键:对应游戏的开局,将游戏规则阅读状态更新为1,即阅读完毕,并刷新画面进入游戏运行界面,同时读取之前保存的数据,显示历史最高分:

case KeyEvent.VK_ENTER:isRuleEnd = true;repaint();readData();break;

       空格键:根据状态控制游戏的开始与暂停,同时伴随着音乐的开始与暂停。

case KeyEvent.VK_SPACE:  

       if(isFailed || isWined || isEqual) {

              isFailed = false;isWined = false;

              isEqual = false;initSnake();enemy_initSnake();

       }

       else isStart = !isStart;repaint();

       if(isStart) playbgm(); else stopbgm();

       break;

       Esc键:保存数据,显示最高得分,并退出游戏。

case KeyEvent.VK_ESCAPE:

       frame = new JFrame();

       frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

       frame.setSize(300, 200);//设置提示框大小

       int option = JOptionPane.showOptionDialog(frame, "是否退出且保存数据?", "确认退出",JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESS

AGE, null,new String[]{"取消", "确定"}, "取消");

       if (option == JOptionPane.YES_OPTION) {

              return;

       } else if (option == JOptionPane.NO_OPTION) {

              saveData();

              System.exit(0);

       }

       frame.setVisible(true);

       break;

       上下左右的按键控制方向

case KeyEvent.VK_UP:if(direction != "D") direction = "U";break;

case KeyEvent.VK_DOWN:if(direction != "U") direction = "D";break;

case KeyEvent.VK_LEFT:if(direction != "R") direction = "L";break;

case KeyEvent.VK_RIGHT:if(direction != "L") direction = "R";break;     

3.5 蛇头的碰撞事件actionPerformed

       这是本项目最为核心的代码,我们将分别从游戏状态的控制,蛇头吃到食物、炸弹及另一方蛇身对应变化的实现,音乐的加载及播放停止,数据的保存及读取等操作的代码,具体如下:

       首先需对当前的游戏状态进行判断,若玩家规则阅读完毕(isRuleEnd),且是游戏开局状态(isStart),同时不是游戏的胜负状态(isEqual),则执行事件

if(isRuleEnd && isStart && !isFailed && !isWined && !isEqual) {…}

       蛇头吃到食物,若蛇头与食物的坐标重合,则播放吃到食物的音效,同时增加蛇的长度和速度,并同时更新吃掉的食物的位置。

for (int i = 0; i < fishList.size();i++) {

   fish_coordinate = fishList.get(i);

   if(Math.abs(snakeHead.x - fish_coordinate.x) < 25 && Math.abs(snakeHead.y - fish_coordinate.y) < 25)

   {

      //播放吃到食物的音效

      eatbgm.stop();

      eatbgm.setFramePosition(0);

      eatbgm.start();

      //随机生成食物新坐标

      Coordinate coordinate = new Coordinate();

      coordinate.y = snakeBody.get(snakeLen - 1).y;

      coordinate.x = snakeBody.get(snakeLen - 1).x;

      snakeBody.add(coordinate);

      snakeLen ++; //蛇长度加1

      updateFish(i);// 更新吃掉的食物的位置

      updateSpeed();//更新蛇的速度

   }

}

       蛇头吃到食物,若蛇头与炸弹的坐标重合,则播放碰到炸弹的音效,同时减少蛇的长度和速度,并更新吃掉的炸弹的位置,同时更新玩家蛇的状态为被轰炸,即晕眩状态,当bBomb等待到设定的晕眩时间时,才可以继续移动,由于碰到与碰到食物的代码重复,这里仅展示移动身体的判断:

if(!isBomb || bBomb == bombTime)

       蛇的移动,与蛇绘制同理,分成两部分,分别为蛇身动及蛇头动,蛇身就是跟随着前一个身体节点移动:

for(int i = snakeLen - 1; i > 0; i--)

{

       snakeBody.get(i).x = snakeBody.get(i-1).x;

       snakeBody.get(i).y = snakeBody.get(i-1).y;

}

       蛇头的移动,根据不同的方向控制移动,同时,若蛇头碰到一方边界,则将其更新为该边界对应的另一方边界,实现蛇的“穿越”:

switch(direction)

{

       case "U":snakeHead.y -=25;if(snakeHead.y < 125) snakeHead.y = 700;break;

       case "D":snakeHead.y +=25;if(snakeHead.y > 700) snakeHead.y = 125;break;

       case "L":snakeHead.x -=25;if(snakeHead.x < 25) snakeHead.x = 850;break;

       case "R":snakeHead.x +=25;if(snakeHead.x > 850) snakeHead.x = 25;break;

}

       蛇的截断,当一方蛇头碰到另一方的身体时,另一方的身体则进行截断,己方身体则增长对应长度。实现方式即遍历电脑蛇的每一个节点,若发现有节点与玩家头重合,则进行截断操作,并对应更新蛇的长度、速度及分数。

for(int i=1; i < enemy_snakeLen; i++)

{

       if(Math.abs(snakeHead.x - enemy_snakeBody.get(i).x) < 25 && Math.abs(snakeHead.y - enemy_snakeBody.get(i).y) < 25)

       {

              for(int j = 1;j < enemy_snakeLen - i + 1;j++)

              {

                     Coordinate coordinate = new Coordinate(); // 创建Coordinate对象

                     coordinate.y = snakeBody.get(snakeLen - 1).y;

                     coordinate.x = snakeBody.get(snakeLen - 1).x;

                     snakeBody.add(coordinate);

                     snakeLen ++;

                     score += 10;//一个长度对应10

              }

                     for(int j = enemy_snakeLen - 1;j > i - 1;j--)

                     enemy_snakeBody.remove(j);

                     enemy_snakeLen = i - 1; 

                     eatbgm.start();

                     updateSpeed();  

       }

}

       胜负判断,若是蛇头与蛇头碰撞,则判定为平局,若玩家蛇长度小于3,则判定为失败,若电脑蛇长度小于3,则判定为胜利,同时,每次判定都会对比分进行统计。

for(int i=1; i < enemy_snakeLen; i++)

if(Math.abs(snakeHead.x - enemy_snakeBody.get(0).x) < 25 && Math.abs(snakeHead.y - enemy_snakeBody.get(0).y) < 25)

{

       isEqual = true;

}

else if(snakeLen < 3)

       isFailed = true;

else if(enemy_snakeLen < 3)

       isWined = true;

       速度更新,注意timer.setDelay里的参数是间隔,越长速度越慢。

speedValue = 2*(snakeLen - 2);

timer.setDelay(initSpeed - speedValue);

       加载音乐,并打开音乐,为后续音乐的播放做准备:

bgm = AudioSystem.getClip();

InputStream is = this.getClass().getClassLoader().getResourceAsStream("sounds/b

gm.wav");

//转音频(注意转jar时,利用BufferedInputStream先生成一个缓存区)

AudioInputStream ais = AudioSystem.getAudioInputStream(new BufferedInputStream(is));

bgm.open(ais);//打开

       播放音乐

bgm.loop(Clip.LOOP_CONTINUOUSLY);

       停止音乐

bgm.stop();

       保存数据,对话框提示

try (BufferedWriter writer = new BufferedWriter(new FileWriter("data.txt"))) {

   writer.write("BlackCat\n"+"SnakeLen: " + snakeLen);

          …

   JOptionPane.showMessageDialog(null, "数据已保存到文件", "提示", JOptionPane.INFORMATION_MESSAGE);

   } catch (IOException e) {

   JOptionPane.showMessageDialog(null, "保存数据时出现错误"+ e.getMessage(), "提示", JOptionPane.INFORMATION_MESSAGE);

}

       读取数据,更新历史最高分

try (BufferedReader br = new BufferedReader(new FileReader("data.txt"))) {

     String data;

     while ((data = br.readLine()) != null) {

          if (data.startsWith("maxValue")) {

               String[] value = data.split(": ");

               if (value.length == 2) {

                    maxValue = Integer.parseInt(value[1]);

               }

          }

     }

} catch (IOException e) {

     e.printStackTrace();

}

       加载图片

is = getClass().getClassLoader().getResourceAsStream("images/Rule.png");

Rule = new ImageIcon(ImageIO.read(is)); 

4、心得体会及项目评价与展望

4.1心得体会

       通过系统的学习本学期的JAVA课程,我运用所学,历时一周,成功的完成了本次的大作业。在项目编写的开始,我就想好要与别的同学做的不同,别人都是直接贪吃蛇大作战,都是蛇的移动,千篇一律,故我在页面设计时就动了心思,自己设计界面和“蛇”的样式,在用户观感上先胜一筹。

       在大作业完成的过程中,也遇到过许多困难,比如如何实现两条蛇不同速度的运动,如何仅让一方蛇晕眩停留,如何实现界面的跳转等问题,最终查阅相关资料及转换设计思路,成功实现了我想表达的功能。

       由于刚开始我仅设置了一个时间Timer来控制全局的运行,所以很难实现两条蛇的不同速度的运动,它们总是会保持相同的速度,同时,这也对我晕眩状态的实现起了阻碍。当时查阅资料也无所收获,网上对于不同蛇速度的实现代码存在欠缺,大部分贪吃蛇的代码都很简单,故我决定自己想想办法,然后决定尝试再顶一个Timer类型的变量来控制电脑蛇,还真就被我实现了。

       不过晕眩还是存在问题,于是我换了一种思路,不再从停止当前游戏运行的状态思考,而是从控制蛇不能移动的方向思考,故我设置了一个晕眩时间及用于对晕眩时间进行计数的变量,一旦蛇进入晕眩状态,就停止移动,然后开始计数,计数达到晕眩时间之后蛇才可以继续移动。这便成功实现了我想要的功能。

       最后就是界面跳转的部分,我发现直接从Snake游戏启动类对页面进行更换之后,游戏就动不了了,所以我又定义了一个状态变量,用于表示用户是否读完游戏规则,若读完,按下Enter键再实现跳转,要注意页面的刷新。

       通过本次项目的编写,我对于JAVA的各种细节有了更深的理解,也因为自行独立完成了该项目获得了满满的成就感。我发现写代码真的会上瘾,在完成一个功能后总会又有新的想法,然后就会不断完善,不过这也需要编写代码时要给之后的改善留一个改善空间,如尽量用变量代替常量参数。

4.2项目展望

       本项目可拓展功能还有很多,比如现在我的食物数量设置的是5,那么我们能不能设置多种模式,比如简单版,将其设置成10,困难版将其设置成3,这种;现在我就设置了两种食物,碰到炸弹晕眩,碰到食物加长加速,那么能不能再增加一些新的类型,比如吃到后会减速,或者蛇的长度成双倍,这些都是简单且可以实现的功能。当然,我现在只设置了一个电脑NPC,再未来可以多设置几条蛇,设置还可以设置多个玩家,玩家的装扮也可以变……

       当然,更高级一点的话,我现在对电脑NPC设置的随机移动,可不可以加一个算法,算出哪种路径更容易将玩家杀死,或者哪种路径更容易吃到食物……

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 这里提供一个基于Java Swing开发的简单贪吃蛇游戏代码: ``` import java.awt.Color; import java.awt.Graphics; import java.awt.Point; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.util.LinkedList; import java.util.Random; import javax.swing.JFrame; import javax.swing.JPanel; public class SnakeGame extends JPanel implements Runnable, KeyListener { private static final long serialVersionUID = 1L; // 游戏宽度 private static final int WIDTH = 500; // 游戏高度 private static final int HEIGHT = 500; // 方格大小 private static final int BLOCK_SIZE = 20; // 蛇的长度 private int snakeLength = 3; // 蛇的坐标 private LinkedList<Point> snake = new LinkedList<Point>(); // 蛇的方向 private int direction = KeyEvent.VK_RIGHT; // 食物坐标 private Point food = new Point(); // 随机种子 private Random random = new Random(); // 游戏是否结束 private boolean gameOver = false; public SnakeGame() { // 初始化界面 JFrame frame = new JFrame("贪吃蛇作战"); frame.setSize(WIDTH, HEIGHT); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setLocationRelativeTo(null); frame.setResizable(false); frame.addKeyListener(this); frame.add(this); frame.setVisible(true); // 初始化蛇 snake.add(new Point(2, 0)); snake.add(new Point(1, 0)); snake.add(new Point(0, 0)); // 初始化食物 generateFood(); // 启动游戏线程 Thread thread = new Thread(this); thread.start(); } @Override public void paint(Graphics g) { // 清空画布 g.clearRect(0, 0, WIDTH, HEIGHT); // 画蛇 g.setColor(Color.GREEN); for (Point p : snake) { g.fillRect(p.x * BLOCK_SIZE, p.y * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE); } // 画食物 g.setColor(Color.RED); g.fillRect(food.x * BLOCK_SIZE, food.y * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE); // 画分数 g.setColor(Color.BLACK); g.drawString("分数:" + (snakeLength - 3), 10, 20); // 画游戏结束提示 if (gameOver) { g.setColor(Color.RED); g.drawString("游戏结束!", WIDTH / 2 - 30, HEIGHT / 2); } } @Override public void run() { while (!gameOver) { try { // 控制游戏速度 Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } // 移动蛇 moveSnake(); // 判断是否吃到食物 if (snake.getFirst().equals(food)) { snakeLength++; generateFood(); } // 判断是否撞到墙或自己 if (snake.getFirst().x < 0 || snake.getFirst().x >= WIDTH / BLOCK_SIZE || snake.getFirst().y < 0 || snake.getFirst().y >= HEIGHT / BLOCK_SIZE || snake.contains(snake.getFirst())) { gameOver = true; } // 重绘界面 repaint(); } } @Override public void keyPressed(KeyEvent e) { // 更新蛇的方向 if (e.getKeyCode() == KeyEvent.VK_UP && direction != KeyEvent.VK_DOWN) { direction = KeyEvent.VK_UP; } else if (e.getKeyCode() == KeyEvent.VK_DOWN && direction != KeyEvent.VK_UP) { direction = KeyEvent.VK_DOWN; } else if (e.getKeyCode() == KeyEvent.VK_LEFT && direction != KeyEvent.VK_RIGHT) { direction = KeyEvent.VK_LEFT; } else if (e.getKeyCode() == KeyEvent.VK_RIGHT && direction != KeyEvent.VK_LEFT) { direction = KeyEvent.VK_RIGHT; } } @Override public void keyTyped(KeyEvent e) { } @Override public void keyReleased(KeyEvent e) { } // 移动蛇 private void moveSnake() { int x = snake.getFirst().x; int y = snake.getFirst().y; switch (direction) { case KeyEvent.VK_UP: y--; break; case KeyEvent.VK_DOWN: y++; break; case KeyEvent.VK_LEFT: x--; break; case KeyEvent.VK_RIGHT: x++; break; } snake.addFirst(new Point(x, y)); if (snake.size() > snakeLength) { snake.removeLast(); } } // 生成食物 private void generateFood() { while (true) { int x = random.nextInt(WIDTH / BLOCK_SIZE); int y = random.nextInt(HEIGHT / BLOCK_SIZE); food.setLocation(x, y); if (!snake.contains(food)) { break; } } } public static void main(String[] args) { new SnakeGame(); } } ``` 以上代码仅提供参考,可以根据自己的需求进行修改和完善。 ### 回答2: Java贪吃蛇作战代码是一段用Java语言编写的程序,实现了经典游戏“贪吃蛇作战”。 首先,程序需要定义蛇的属性,比如蛇的位置、尺寸、速度以及方向等信息。通过一个数组或者链表来保存蛇的身体坐标,每个节点表示蛇身体的一个部分。还需要定义食物的属性,比如食物的位置和大小。 接下来,程序需要监听玩家的输入,根据玩家的操作来改变蛇的方向:向上、向下、向左或向右移动。可以使用键盘事件监听,通过按键的keyCode来确定操作。 然后,程序需要实现蛇的移动逻辑。蛇向前移动时,身体的每一节都要跟着移动,并且新增加的食物会被蛇吃掉,使得蛇的身体变长。当蛇的头部与身体相撞或者撞墙时,游戏结束。 在游戏进行时,程序需要不断更新屏幕上的蛇和食物的位置,以及判断蛇是否吃到食物,如果吃到了则生成新的食物。可以使用定时器或者循环来实现游戏的更新和渲染。 最后,当游戏结束时,可以显示游戏结束的提示信息,比如游戏得分、最高分等。 总结来说,Java贪吃蛇作战代码是通过定义蛇和食物的属性,监听玩家输入,实现蛇的移动逻辑,并在游戏进行时不断更新屏幕上的内容,最后展示游戏结束信息的一段Java程序。编写这样的代码可以锻炼编程能力,并且可以在游戏中体验到程序设计的乐趣。 ### 回答3: 在Java贪吃蛇作战代码中,首先需要创建一个贪吃蛇的类。这个类包含贪吃蛇的身体坐标、移动方向和长度等属性。在游戏开始时,需要初始化贪吃蛇的位置和长度。 然后,我们需要实现游戏的主循环。在每一轮循环中,根据用户输入或者预设的策略改变贪吃蛇的移动方向,并且根据贪吃蛇当前位置和移动方向计算下一步的位置。如果下一步的位置是食物的位置,那么贪吃蛇的长度加一,并且在地图上生成一个新的食物。如果下一步的位置是地图边界或者贪吃蛇自身的位置,那么游戏结束。 游戏的地图可以使用二维数组来表示,每个元素的值表示该位置的状态,比如空白、贪吃蛇的身体或者食物。 为了让游戏有更好的可玩性,我们可以添加一些额外的功能。比如,在地图上随机生成障碍物,让贪吃蛇在遇到障碍物时无法通过。我们还可以设计多个关卡和不同的游戏模式,让玩家可以选择不同的难度或者挑战各种挑战。此外,我们还可以添加一些特殊道具,比如加速、减速或者变换方向等,让游戏更加有趣。 最后,我们需要实现一些图形界面交互,比如显示地图和贪吃蛇,监听键盘事件来改变贪吃蛇的移动方向。如果有条件的话,我们还可以将游戏进行网络化,实现多人联机对战,让玩家可以与其他玩家进行对战和竞争。 总之,Java贪吃蛇作战代码需要实现贪吃蛇的移动、长度增加、判断游戏结束等基本功能,并可以通过添加障碍物、地图关卡、道具等来增加游戏的可玩性和趣味性。同时,还可以实现图形界面和网络对战等功能来提供更好的游戏体验。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值