首先给出代码下载地址(含素材):https://share.weiyun.com/8hkvy1Ja

目录

1.实现效果:

​​2.游戏玩法

3.需求分析

4.代码实现


1.实现效果:

2.游戏玩法

该游戏用上下左右控制蛇的方向,寻找吃的东西,每吃一口就能得到一定的积分,而且蛇的身子会越吃越长,身子越长玩的难度就越大,不能碰墙,不能咬到自己的身体,更不能咬自己的尾巴,等到了一定的分数,就能过关,然后继续玩下一关。这次我们以一关的实现为例,关卡控制交给读者自行添加。

3.需求分析

  • 方向控制

首先我们需要实现的是通过按键实现控制蛇的运动方向,需要注意的有两点:

1.蛇运动的时候不能向上一个状态的反方向运动,例如,原先向右,下一次改变的方向不能为左。

2.运动的时候如果按了一个方向键,再下一次按键之前将维持原先的方向运动。

2.如果蛇头和身体的图片不一样,那么蛇头要随着运动方向进行旋转。

  • 蛇的绘制

蛇我这里分为了蛇头和蛇身两部分,当然你也可以加蛇尾。这里以蛇头和蛇身两部分为例:

蛇头游戏开始就已经存在,之后吃到一个食物都会使蛇身长度加一。蛇身的每一部分都会沿着它的前一部分的轨迹运动,而每一部分都会沿着蛇头的轨迹运动。

  • 食物绘制

食物绘制相对比较简单,当一个食物被吃掉以后,便在地图的其他随机的一个地方产生下一个食物。

  • 蛇和食物的生命周期

蛇:当蛇碰到地图边界,碰到自己的身体和尾巴的时候,即判定为死亡。

食物:当蛇头碰到食物,则食物死亡。

4.代码实现

  • 项目目录

  • Constant类,存储一些常量。
public class Constant {public static final int GAME_WIDTH = 1024;//窗体宽度public static final int GAME_HEIGHT = 578;//窗体高度public static final String IMG_PRE="com/zzk/snake/img/";//图片路径前缀
}
  • MyFrame类,用于加载游戏窗体和不断刷新绘制窗体内容:
import java.awt.Color;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;import com.zzk.snake.constant.Constant;public class MyFrame extends Frame{/*** 加载窗体*/public void loadFrame(){this.setTitle("贪吃蛇");//设置窗体标题this.setSize(Constant.GAME_WIDTH, Constant.GAME_HEIGHT);//设置窗体大小this.setBackground(Color.BLACK);//设置背景this.setLocationRelativeTo(null);//居中//设置可关闭this.addWindowListener(new WindowAdapter() {@Overridepublic void windowClosing(WindowEvent e) {System.exit(0);}});//设置可见this.setVisible(true);//运行重绘线程new MyThread().start();}/*** 防止图片闪烁,使用双重缓存* * @param g*/Image backImg = null;@Overridepublic void update(Graphics g) {if (backImg == null) {backImg = createImage(Constant.GAME_WIDTH, Constant.GAME_HEIGHT);}Graphics backg = backImg.getGraphics();Color c = backg.getColor();backg.setColor(Color.BLACK);backg.fillRect(0, 0, Constant.GAME_WIDTH, Constant.GAME_HEIGHT);backg.setColor(c);paint(backg);       g.drawImage(backImg, 0, 0, null);}/*** 这里创建一个不断重绘的线程内部类* * @param args*/class MyThread extends Thread{@Overridepublic void run() {while(true){repaint();try {sleep(30);//每30毫秒重绘一次} catch (InterruptedException e) {e.printStackTrace();}}}}
}

这里为了防止图片闪烁所以说添加了一个新方法,具体细节原因请读者自行学习。

  • GameUtil类,用于获取图片和处理图片旋转
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;import javax.imageio.ImageIO;public class GameUtil {/*** 根据图片的相对路径获取图片* * @param imagePath* @return 图片*/public static Image getImage(String imagePath) {URL url = GameUtil.class.getClassLoader().getResource(imagePath);BufferedImage img = null;try {img = ImageIO.read(url);} catch (IOException e) {e.printStackTrace();}return img;}/*** 按指定角度旋转图片* @param bufferedimage* @param degree* @return 图片*/public static Image rotateImage(final BufferedImage bufferedimage, final int degree) {int w = bufferedimage.getWidth();// 得到图片宽度。int h = bufferedimage.getHeight();// 得到图片高度。int type = bufferedimage.getColorModel().getTransparency();// 得到图片透明度。BufferedImage img;// 空的图片。Graphics2D graphics2d;// 空的画笔。(graphics2d = (img = new BufferedImage(w, h, type)).createGraphics()).setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);graphics2d.rotate(Math.toRadians(degree), w / 2, h / 2);// 旋转,degree是整型,度数,比如垂直90度。graphics2d.drawImage(bufferedimage, 0, 0, null);// 从bufferedimagecopy图片至img,0,0是img的坐标。graphics2d.dispose();return img;// 返回复制好的图片,原图片依然没有变,没有旋转,下次还可以使用。}
}
  • ImageUtil类,用于存储图片,方便使用
import java.awt.Image;
import java.util.HashMap;
import java.util.Map;import com.zzk.snake.constant.Constant;public class ImageUtil {public static Map<String,Image> images = new HashMap<>();static{images.put("snake_body", GameUtil.getImage(Constant.IMG_PRE+"snake_body.png"));images.put("food", GameUtil.getImage(Constant.IMG_PRE+"food.png"));images.put("snake_head", GameUtil.getImage(Constant.IMG_PRE+"snake_head.png"));images.put("background", GameUtil.getImage(Constant.IMG_PRE+"background.jpg"));images.put("fail", GameUtil.getImage(Constant.IMG_PRE+"fail.png"));}
}
  • Drawable和Moveable接口,蛇有移动和绘制的能力
import java.awt.Graphics;public interface Drawable {void draw(Graphics g);
}
public interface Moveable {void move();
}
  • SnakeObject类,蛇和食物的父类,由于食物和蛇都需要进行绘制,都有生命周期,所以抽取出一个父类
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Rectangle;public abstract class SnakeObject implements Drawable {int x;//横坐标int y;//纵坐标Image img;//图片int width;//图片宽度int height;//图片高度public boolean live;//死亡/存活@Overridepublic abstract void draw(Graphics g);/*** 获取图片对应的矩形* * @return*/public Rectangle getRectangle() {return new Rectangle(x, y, width, height);}
}
  • Food类,食物类,绘制食物
import java.awt.Graphics;import com.zzk.snake.constant.Constant;
import com.zzk.snake.util.ImageUtil;public class Food extends SnakeObject{public Food(){this.live=true;this.img=ImageUtil.images.get("food");this.width=img.getWidth(null);this.height=img.getHeight(null);this.x=(int) (Math.random()*(Constant.GAME_WIDTH-width+10));this.y=(int) (Math.random()*(Constant.GAME_HEIGHT-40-height)+40);}/*** 食物被吃的方法* @param mySnake*/public void eaten(MySnake mySnake){if(mySnake.getRectangle().intersects(this.getRectangle())&&live&&mySnake.live){this.live=false;//食物死亡mySnake.setLength(mySnake.getLength()+1);//长度加一mySnake.score+=10*mySnake.getLength();//加分}}/*** 绘制食物*/@Overridepublic void draw(Graphics g) {g.drawImage(img, x, y, null);}}
  • MySnake ,蛇类,用于绘制蛇,用了一个LinkedList<Point>存储蛇的每一次移动的轨迹点,当蛇吃到东西时,从尾部的轨迹点绘制一块蛇身。每次移动后添加新的轨迹点,同时移除不必要的轨迹点。
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import java.util.LinkedList;
import java.util.List;import com.zzk.snake.constant.Constant;
import com.zzk.snake.util.GameUtil;
import com.zzk.snake.util.ImageUtil;public class MySnake extends SnakeObject implements Moveable {//蛇头图片(未旋转)private static final BufferedImage IMG_SNAKE_HEAD = (BufferedImage) ImageUtil.images.get("snake_head");private int speed;//移动速度private int length;//长度private int num;//public static List<Point> bodyPoints = new LinkedList<>();public int score = 0;//分数private static BufferedImage newImgSnakeHead;//旋转后的蛇头图片boolean up, down, left, right = true;//初始态向右public MySnake(int x, int y) {this.live = true;this.x = x;this.y = y;this.img = ImageUtil.images.get("snake_body");this.width = img.getWidth(null);this.height = img.getHeight(null);this.speed = 5;this.length = 1;this.num = width / speed;newImgSnakeHead = IMG_SNAKE_HEAD;}public int getLength() {return length;}public void setLength(int length) {this.length=length;}/*** 接收键盘按下事件* @param e*/public void keyPressed(KeyEvent e) {switch (e.getKeyCode()) {case KeyEvent.VK_UP:if (!down) {// 不能向初始方向的反方向移动up = true;down = false;left = false;right = false;newImgSnakeHead = (BufferedImage) GameUtil.rotateImage(IMG_SNAKE_HEAD, -90);//旋转图片}break;case KeyEvent.VK_DOWN:if (!up) {up = false;down = true;left = false;right = false;newImgSnakeHead = (BufferedImage) GameUtil.rotateImage(IMG_SNAKE_HEAD, 90);}break;case KeyEvent.VK_LEFT:if (!right) {up = false;down = false;left = true;right = false;newImgSnakeHead = (BufferedImage) GameUtil.rotateImage(IMG_SNAKE_HEAD, -180);}break;case KeyEvent.VK_RIGHT:if (!left) {up = false;down = false;left = false;right = true;newImgSnakeHead = IMG_SNAKE_HEAD;}break;}}/*** 移动*/@Overridepublic void move() {if (up)y -= speed;else if (down)y += speed;else if (left)x -= speed;else if (right)x += speed;}/*** 绘制*/@Overridepublic void draw(Graphics g) {outOfBounds();//处理出界问题eatBody();//处理是否吃到身体问题bodyPoints.add(new Point(x, y));//保存轨迹if (bodyPoints.size() == (this.length+1) * num) {//当保存的轨迹点的个数为蛇的长度+1的num倍时bodyPoints.remove(0);//移除第一个}g.drawImage(newImgSnakeHead, x, y, null);//绘制蛇头drawBody(g);//绘制蛇身move();//移动}/*** 处理是否吃到到身体问题*/public void eatBody(){for (Point point : bodyPoints) {for (Point point2 : bodyPoints) {if(point.equals(point2)&&point!=point2){this.live=false;//食物死亡}}}}/*** 绘制蛇身* @param g*/public void drawBody(Graphics g) {int length = bodyPoints.size() - 1-num;//前num个存储的是蛇头的当前轨迹坐标for (int i = length; i >= num; i -= num) {//从尾部添加Point p = bodyPoints.get(i);g.drawImage(img, p.x, p.y, null);}}/*** 处理出界问题*/private void outOfBounds() {boolean xOut = (x <= 0 || x >= (Constant.GAME_WIDTH - width));boolean yOut = (y <= 40 || y >= (Constant.GAME_HEIGHT - height));if (xOut || yOut) {live = false;}}
}
  • SnakeClient类,加载窗体,控制游戏流程,我这里没有进行关卡控制和开始界面等,读者可以自行修改。
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;import com.zzk.snake.core.Food;
import com.zzk.snake.core.MyFrame;
import com.zzk.snake.core.MySnake;
import com.zzk.snake.util.ImageUtil;public class SnakeClient extends MyFrame{public MySnake mySnake = new MySnake(100, 100);//蛇public Food food = new Food();//食物Image background = ImageUtil.images.get("background");//背景图片Image fail = ImageUtil.images.get("fail");//游戏结束的文字@Overridepublic void loadFrame() {super.loadFrame();//添加键盘监听器,处理键盘按下事件addKeyListener(new KeyAdapter() {@Overridepublic void keyPressed(KeyEvent e) {mySnake.keyPressed(e);//委托给mysnake}});}/*** 绘制界面*/@Overridepublic void paint(Graphics g) {g.drawImage(background, 0, 0, null);//绘制背景if(mySnake.live){//如果蛇活着,就绘制mySnake.draw(g);if(food.live){//如果食物活着,就绘制food.draw(g);food.eaten(mySnake);}else{//否则,产生新食物food = new Food();}}else{//蛇死亡,弹出游戏结束字样g.drawImage(fail, (background.getWidth(null)-fail.getWidth(null))/2, (background.getHeight(null)-fail.getHeight(null))/2, null);}drawScore(g);//绘制分数}/*** 绘制分数* @param g*/public void drawScore(Graphics g){g.setFont(new Font("Courier New", Font.BOLD, 40));g.setColor(Color.WHITE);g.drawString("SCORE:"+mySnake.score,700,100);}public static void main(String[] args) {new SnakeClient().loadFrame();//加载窗体}
}

GitHub地址:https://github.com/a13835614623/JavaGame(其他java游戏也在其中)

Gitee地址:https://gitee.com/zzk4513/JavaGame

代码下载地址(含素材):https://share.weiyun.com/8hkvy1Ja

java贪吃蛇小游戏(详解)相关推荐

  1. 手把手教你做一个Java贪吃蛇小游戏

    大家好,我是孙不坚1208,这篇博客给大家分享一下:如何做一个贪吃蛇小游戏(Java版)的exe应用程序,希望能给需要帮助的朋友带来方便. 手把手教你做一个Java贪吃蛇小游戏的exe应用程序 一.J ...

  2. java闯关小游戏+详解+完整源代码+测试结果

    小游戏面向对象 一,问题分析 计算机输出字符串,玩家根据计算输出的内容重复输入,如果输入正确,进入一下关的练习 该过程记录玩家的积分,定义游戏的关卡,定义游戏的规则 1.1定义游戏的规则 游戏的关卡 ...

  3. Java 贪吃虫小游戏

    我参考了[Java]Java实现贪吃蛇小游戏(带详细注释)和 java贪吃蛇小游戏(详解) 先设置需要用到的常数 package Snake;public class ConstantNumber { ...

  4. 100行实现《贪吃蛇》小游戏详解(Qt)

    目录 游戏说明 游戏效果展示 游戏代码详解 ​关键数据结构 初始化游戏界面 游戏部分 提示部分 蛇逻辑 小蛇的初始化 边界判断 蛇吃食物判断 随机生成食物 是否撞到自己 小蛇的移动 游戏主体逻辑 定时 ...

  5. python贪吃蛇小游戏制作思路详解

    很多时候,游戏都是一种可以发泄自己内心情绪的工具,在游戏中,我们可以忘记经历过的很多不快.如今呢,随着软硬件的不断提高,游戏市场越来越繁华红火,很多游戏都动辄好几个G.让人不得不感叹啊,以前那种玩贪吃 ...

  6. Java实现贪吃蛇小游戏(附完整源码)

    今天我就从零开始来完成这个小游戏,完成的方式也是一步一步的添加功能这样的方式来实现. 第一步完成的功能:写一个界面 大家见到的贪吃蛇小游戏,界面肯定是少不了的.因此,第一步就是写一个小界面. 实现代码 ...

  7. 简易贪吃蛇小游戏java版_用GUI实现java版贪吃蛇小游戏

    本文实例为大家分享了java版贪吃蛇小游戏的具体代码,供大家参考,具体内容如下 项目结构 新建一个JFrame窗口,作为程序入口 public class GameStart{ public stat ...

  8. 用 Java 实现贪吃蛇小游戏

    程序说明 这是一个用 Java Awt 实现的贪吃蛇小游戏的完整代码 算法分析 (一)启动一个独立线程根据 direction 重绘面板实现蛇身移动效果,运行过程: 记录上次头部的坐标到 tempBo ...

  9. 贪吃蛇小游戏java实现代码分析

    贪吃蛇小游戏java实现代码分析 贪吃蛇的小游戏,网上的代码比较多,今天周五,在教研室没啥事做,在电脑中发现了一个贪吃蛇的小游戏,于是就看了下实现的源码,发现别人写的代码确实挺好的,自己也是边加注释边 ...

最新文章

  1. LINUX动态链接库高级应用
  2. 计算机视觉中的数据预处理与模型训练技巧总结
  3. windows server 2008的安装以及主机IP配置实验
  4. go和python计算字节数组sha1
  5. elk中kibana中如何显示写入elasticsearch的数据
  6. YBTOJ:斐波拉契(矩阵快速幂)
  7. 弹性计算平台技术:云服务器“安全”“稳定”“弹性”的基石
  8. 马的遍历(洛谷-P1443)
  9. 目标检测: Anchor-Free 时代
  10. 从入门到精通进阶篇 - 设置负载阶梯式压测场景(详解教程)
  11. 【转】Apache+php+mysql在windows下的安装与配置图解(最新版)
  12. 216.组合总和III
  13. Gallery3d 学习笔记(12)
  14. 数据结构之二叉树深度计算
  15. Gmail企业邮箱让中小企业免费拥有企业邮箱
  16. 如何储存图片方法jpg格式png格式#ps教程#ps抠图
  17. 2016年,上海的互联网企业是否值得加入?
  18. 面试侃集合 | LinkedBlockingQueue篇
  19. 解除BitLocker加密
  20. Linux驱动——mmc sd card 块设备读写流程(十三)

热门文章

  1. ReportPainter报表(GRR1/GRR2/GRR3/GR51/GR52/GR53)分配事物代码(T-CODE)
  2. 黑手已经伸向了微信自媒体营销
  3. android imageview选择器,ImageView 实现Android colorPikcer 选择器的示例代码
  4. win10输入法首字母粘连/首字母重复
  5. java中写入文件_java中创建、写入文件的5种方式
  6. 邮票的孔怎么做出来的_邮票怎么做防潮工作,防潮柜有用吗【中华古画古物邮票吧】...
  7. eBPF Talk: 比 kprobe 更好的 trampoline
  8. 数据处理:应用Savitzky-Golay算法对数据进行平滑化处理
  9. 美南方电力解围东芝西屋困局 计提损失将减一半生 “蝴蝶效应”
  10. 哈尔滨理工oj2316ID