java实现贪吃蛇小游戏

本文实例为大家分享了java实现贪吃蛇小游戏的具体代码,供大家参考,具体内容如下

这是MVC模式的完整Java项目,编译运行SnakeApp.java即可开始游戏。

可扩展功能:

1、积分功能:可以创建得分规则的类(模型类的一部分), 在GameController的run()方法中计算得分
2、变速功能:比如加速功能,减速功能,可以在GameController的keyPressed()方法中针对特定的按键设置每一次移动之间的时间间隔,将Thread.sleep(Settings.DEFAULT_MOVE_INTERVAL);替换为动态的时间间隔即可
3、更漂亮的游戏界面:修改GameView中的drawXXX方法,比如可以将食物渲染为一张图片,Graphics有drawImage方法

View

SnakeApp.java

/*
 * 属于View,用来根据相应的类展示出对应的游戏主界面,也是接收控制信息的第一线。
 */
public class SnakeApp {
 public void init() {
  //创建游戏窗体
  JFrame window = new JFrame("一只长不大的蛇");
  //初始化500X500的棋盘,用来维持各种游戏元素的状态,游戏的主要逻辑部分
  Grid grid = new Grid(50*Settings.DEFAULT_NODE_SIZE,50*Settings.DEFAULT_NODE_SIZE);
  //传入grid参数,新建界面元素对象
  GameView gameView = new GameView(grid);//绘制游戏元素的对象
  //初始化面板
  gameView.initCanvas();
  //根据棋盘信息建立控制器对象
  GameController gameController = new GameController(grid);

  //设置窗口大小
  window.setPreferredSize(new Dimension(526,548));

  //往窗口中添加元素,面板对象被加入到窗口时,自动调用其中的paintComponent方法。
  window.add(gameView.getCanvas(),BorderLayout.CENTER);

  //画出蛇和棋盘和食物
  GameView.draw();

  //注册窗口监听器
  window.addKeyListener((KeyListener)gameController);

  //启动线程
  new Thread(gameController).start();

  //窗口关闭的行为
  window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  //设置窗口大小不可变化
  window.setResizable(false);
  //渲染和显示窗口
  window.pack();
  window.setVisible(true);
 }
 //可以忽略,以后每个类中都有这么一个测试模块
 public static void main(String[] args) {
  SnakeApp snakeApp = new SnakeApp();
  snakeApp.init();
 }
}

GameView.java

/*
 * 属于View,用于绘制地图、蛇、食物
*/

 /* Graphics 相当于一个画笔。对象封装了 Java 支持的基本呈现操作所需的状态信息。此状态信息包括以下属性:
 要在其上绘制的 Component 对象。
 呈现和剪贴坐标的转换原点。
 当前剪贴区。
 当前颜色。
 当前字体。
 当前逻辑像素操作函数(XOR 或 Paint)。
 当前 XOR 交替颜色
*/

/* java.awt.Component的repaint()方法
 作用:更新组件。
 如果此组件不是轻量级组件,则为了响应对 repaint 的调用,AWT 调用 update 方法。可以假定未清除背景。
 Component 的 update 方法调用此组件的 paint 方法来重绘此组件。为响应对 repaint 的调用而需要其他工作的子类通常重写此方法。重写此方法的 Component 子类应该调用 super.update(g),或者直接从其 update 方法中调用 paint(g)。
 图形上下文的原点,即它的(0,0)坐标点是此组件的左上角。图形上下文的剪贴区域是此组件的边界矩形。
 */
public class GameView {
 private final Grid grid;
 private static JPanel canvas;//画板,用于在这上面制作画面,然后返回。

 public GameView(Grid grid) {
 this.grid = grid;
 }
 //重新绘制游戏界面元素,不断重新调用paintComponent方法覆盖原本的面板。
 public static void draw() {
  canvas.repaint();
  }
  //获取画板对象的接口
 public JPanel getCanvas() {
  return canvas;
  }
 //对画板进行初始化
 public void initCanvas() {
 canvas = new JPanel() {
 //指向一个方法被覆盖的新面板子类对象
 //paintComponent()绘制此容器中的每个组件,Swing会在合适的时机去调用这个方法,展示出合适的界面,这就是典型的回调(callback)的概念。
 public void paintComponent(Graphics graphics) {
 super.paintComponent(graphics); //这里必须调用一下父类 也就是 container的重绘方法,否则表现为之前的绘图不会覆盖
 drawGridBackground(graphics);//画出背景网格线
 drawSnake(graphics, grid.getSnake());//画蛇
   drawFood(graphics, grid.getFood());//画食物
 }
 };
 }
 //画蛇
 public void drawSnake(Graphics graphics, Snake snake) {
  for(Iterator<Node> i = snake.body.iterator();i.hasNext();) {
  Node bodyNode = (Node)i.next();
  drawSquare(graphics, bodyNode,Color.BLUE);
  }
 }
 //画食物
 public void drawFood(Graphics graphics, Node food) {
  drawCircle(graphics,food,Color.ORANGE);
 }

 //画格子背景,方便定位Snake运动轨迹,横竖各以10为单位的50个线。
 public void drawGridBackground(Graphics graphics) {
  graphics.setColor(Color.GRAY);
  canvas.setBackground(Color.BLACK);
  for(int i=0 ; i < 50 ; i++) {
  graphics.drawLine(0, i*Settings.DEFAULT_NODE_SIZE, this.grid.getWidth(), i*Settings.DEFAULT_NODE_SIZE);
  }
  for(int i=0 ; i <50 ; i++) {
  graphics.drawLine(i*Settings.DEFAULT_NODE_SIZE, 0, i*Settings.DEFAULT_NODE_SIZE , this.grid.getHeight());
  }
  graphics.setColor(Color.red);
  graphics.fillRect(0, 0, this.grid.width, Settings.DEFAULT_NODE_SIZE);
  graphics.fillRect(0, 0, Settings.DEFAULT_NODE_SIZE, this.grid.height);
  graphics.fillRect(this.grid.width, 0, Settings.DEFAULT_NODE_SIZE,this.grid.height);
  graphics.fillRect(0, this.grid.height, this.grid.width+10,Settings.DEFAULT_NODE_SIZE);

 }
 /*
  * public abstract void drawLine(int x1,int y1,int x2,int y2)
 在此图形上下文的坐标系中,使用当前颜色在点 (x1, y1) 和 (x2, y2) 之间画一条线。
 参数:
 x1 - 第一个点的 x 坐标。
 y1 - 第一个点的 y 坐标。
 x2 - 第二个点的 x 坐标。
 y2 - 第二个点的 y 坐标。
  */
 //提供直接出现游戏结束的选项框的功能。
 public static void showGameOverMessage() {
  JOptionPane.showMessageDialog(null,"游戏结束","短暂的蛇生到此结束", JOptionPane.INFORMATION_MESSAGE);
 }

//画图形的具体方法:
private void drawSquare(Graphics graphics, Node squareArea, Color color) {
 graphics.setColor(color);
 int size = Settings.DEFAULT_NODE_SIZE;
 graphics.fillRect(squareArea.getX(), squareArea.getY(), size - 1, size - 1);
}

private void drawCircle(Graphics graphics, Node squareArea, Color color) {
 graphics.setColor(color);
 int size = Settings.DEFAULT_NODE_SIZE;
 graphics.fillOval(squareArea.getX(), squareArea.getY(), size, size);
}

}

Controller

GameController

/*
 * 接收窗体SnakeApp传递过来的有意义的事件,然后传递给Grid,让Grid即时的更新状态。
 * 同时根据最新状态渲染出游戏界面让SnakeApp显示
 *
 */
public class GameController implements KeyListener, Runnable{
 private Grid grid;
 private boolean running;

 public GameController(Grid grid){
 this.grid = grid;
 this.running = true;
 }

 @Override
 public void keyPressed(KeyEvent e) {
 int keyCode = e.getKeyCode();
 switch(keyCode) {
  case KeyEvent.VK_UP:
   grid.changeDirection(Direction.UP);
   break;
  case KeyEvent.VK_DOWN:
   grid.changeDirection(Direction.DOWN);
   break;
  case KeyEvent.VK_LEFT:
   grid.changeDirection(Direction.LEFT);
   break;
  case KeyEvent.VK_RIGHT:
   grid.changeDirection(Direction.RIGHT);
   break;
 }
 isOver(grid.nextRound());
 GameView.draw();
 }

 private void isOver(boolean flag) {
 if(!flag) {//如果下一步更新棋盘时,出现游戏结束返回值(如果flag为假)则
 this.running = false;
 GameView.showGameOverMessage();
 System.exit(0);
 }
 }

 @Override
 /*run()函数中的核心逻辑是典型的控制器(Controller)逻辑:
 修改模型(Model):调用Grid的方法使游戏进入下一步
 更新视图(View):调用GameView的方法刷新页面*/
 public void run() {
 while(running) {
 try {
 Thread.sleep(Settings.DEFAULT_MOVE_INTERVAL);
 isOver(grid.nextRound());
 GameView.draw();
 } catch (InterruptedException e) {
 break;
 }
 // 进入游戏下一步
   // 如果结束,则退出游戏
   // 如果继续,则绘制新的游戏页面
 }
 running = false;
 }

 @Override
 public void keyTyped(KeyEvent e) {
 }
 @Override
 public void keyReleased(KeyEvent e) {
 }
}

Model

Grid

/*
 * 随机生成食物,维持贪吃蛇的状态,根据SnakeApp中的用户交互来控制游戏状态。
 */
public class Grid {
 private Snake snake;
 int width;
 int height;
 Node food;
 private Direction snakeDirection =Direction.LEFT;
 public Grid(int length, int high) {
 super();
 this.width = length;
 this.height = high;
 initSnake();
 food = creatFood();
 }

 //在棋盘上初始化一个蛇
 private void initSnake() {
 snake = new Snake();
 int x = width/2;
 int y = height/2;
 for(int i = 0;i<5;i++) {
 snake.addTail(new Node(x, y));
 x = x+Settings.DEFAULT_NODE_SIZE;
 }
 }
 //棋盘上随机制造食物的功能。
 //一直循环获取随机值,直到三个条件都不满足。
 private Node creatFood() {
 int x,y;
 do {
 x =(int)(Math.random()*100)+10;
 y =(int)(Math.random()*100)+10;
 System.out.println(x);
 System.out.println(y);
 System.out.println(this.width);
 System.out.println(this.height);
 }while(x>=this.width-10 || y>=this.height-10 || snake.hasNode(new Node(x,y)));
 food = new Node(x,y);
 return food;
 }

 //提供下一步更新棋盘的功能,移动后更新游戏和蛇的状态。
 public boolean nextRound() {
 Node trail = snake.move(snakeDirection);
 Node snakeHead = snake.getBody().removeFirst();//将头部暂时去掉,拿出来判断是否身体和头部有重合的点
 if(snakeHead.getX()<=width-10 && snakeHead.getX()>=10
  && snakeHead.getY()<=height-10 && snakeHead.getY()>=10
  && !snake.hasNode(snakeHead)) {//判断吃到自己和撞到边界
 if(snakeHead.equals(food)) {
 //原本头部是食物的话,将move操作删除的尾部添加回来
 snake.addTail(trail);
 food = creatFood();
 }
 snake.getBody().addFirst(snakeHead);
 return true;//更新棋盘状态并返回游戏是否结束的标志
 }
 return false;
 }

 public Node getFood() {
 return food;
 }

 public Snake getSnake() {
 return snake;
 }

 public int getWidth() {
 return width;
 }

 public int getHeight() {
 return height;
 }

 //提供一个更改贪吃蛇前进方向的方法
 public void changeDirection(Direction newDirection){
   snakeDirection = newDirection;
 }
}

Snake

/*
 * 蛇类,实现了自身数据结构,以及移动的功能
 */
public class Snake implements Cloneable{
 public LinkedList<Node> body = new LinkedList<>();
 public Node move(Direction direction) {
 //根据方向更新贪吃蛇的body
 //返回移动之前的尾部Node(为了吃到时候后增加尾部长度做准备)
 Node n;//临时存储新头部移动方向的结点
 switch (direction) {
  case UP:
  n = new Node(this.getHead().getX(),this.getHead().getY()-Settings.DEFAULT_NODE_SIZE);
  break;
  case DOWN:
  n = new Node(this.getHead().getX(),this.getHead().getY()+Settings.DEFAULT_NODE_SIZE);
  break;
  case RIGHT:
  n = new Node(this.getHead().getX()+Settings.DEFAULT_NODE_SIZE,this.getHead().getY());
  break;
  default:
  n = new Node(this.getHead().getX()-Settings.DEFAULT_NODE_SIZE,this.getHead().getY());

 }
 Node temp = this.body.getLast();
 this.body.addFirst(n);
 this.body.removeLast();
 return temp;
 }
 public Node getHead() {
 return body.getFirst();
 }
 public Node getTail() {
 return body.getLast();
 }
 public Node addTail(Node area) {
 this.body.addLast(area);
 return area;
 }
 public LinkedList<Node> getBody(){
 return body;
 }
 //判断参数结点是否在蛇身上
 public boolean hasNode(Node node) {
 Iterator<Node> it = body.iterator();
 Node n = new Node(0,0);
 while(it.hasNext()) {
 n = it.next();
 if(n.getX() == node.getX() && n.getY() == node.getY()) {
 return true;
 }
 }
 return false;
 }
}

Direction

/*
 * 用来控制蛇的移动方向
 */
public enum Direction {
 UP(0),
 DOWN(1),
 LEFT(2),
 RIGHT(3); //调用构造方法对方向枚举实例进行代码初始化
 //成员变量
 private final int directionCode;

 //成员方法
 public int directionCode() {
 return directionCode;
 }
 Direction(int directionCode){
 this.directionCode = directionCode;
 }
}

Node

public class Node {
 private int x;
 private int y;
 public Node(int x, int y) {
 this.x = ((int)(x/10))*10;
 this.y = ((int)(y/10))*10;
 }//使用这种方法可以使得节点坐标不会出现个位数

 public int getX() {
 return x;
 }

 public int getY() {
 return y;
 }
 @Override
 //判断两个Node是否相同
 public boolean equals(Object n) {
 Node temp;
 if(n instanceof Node) {
 temp = (Node)n;
 if(temp.getX()==this.getX() && temp.getY()==this.getY())
 return true;
 }
 return false;
 }
}

Settings

public class Settings {
 public static int DEFAULT_NODE_SIZE = 10;//每一个节点方块的单位
 public static int DEFAULT_MOVE_INTERVAL = 200;//蛇移动时间间隔
}

更多有趣的经典小游戏实现专题,分享给大家:

C++经典小游戏汇总

python经典小游戏汇总

python俄罗斯方块游戏集合

JavaScript经典游戏 玩不停

javascript经典小游戏汇总

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Java swing框架实现的贪吃蛇游戏完整示例

    本文实例讲述了Java swing框架实现的贪吃蛇游戏.分享给大家供大家参考,具体如下: java是门高级语言,做游戏时适合做后台,但是用它也可以做游戏.闲来无事做的时候可以用来写点小游戏,练习练习预防早衰哈哈! 闲话不说了 下面是以前练习的作品,不怕大家笑话,那个时候用了一个礼拜才做出来的. 源码如下供大家学习. 使用的是java的 swing  Jframe Jpanel JButton   当然你也可以使用awt 先来看看运行效果: 具体代码: package Tcs; /** * * *

  • Java GUI编程之贪吃蛇游戏简单实现方法【附demo源码下载】

    本文实例讲述了Java GUI编程之贪吃蛇游戏简单实现方法.分享给大家供大家参考,具体如下: 例子简单,界面简陋 请见谅 项目结构如下 Constant.jvava 代码如下: package snake; /** * * @author hjn * */ public class Constant { /** * 蛇方移动方向:左边 */ public static final int LEFT = 0; /** * 蛇方移动方向:右边 */ public static final int R

  • Java实现贪吃蛇游戏

    最近JAVA和JSwing上手练习了一下贪吃蛇,供大家参考,具体内容如下 欢迎交流和加入新的内容 用到了JSwing,下面是一些具体的思路 实现  * 蛇: 采用单链表记录首尾,整个蛇被分为lattice格子,放在map里  * 移动: 我在实现的过程中发现最难得反而是蛇的定义和实现.一直想着怎么样用单独的方法表示出蛇来,但是如果将蛇单独实现,总有些细节实现起来特别麻烦 其实蛇移动并非牵一发而动全身,其实身子是没有发生变化的,关键是两点: a.头的移动 b.尾巴的移动 实现: 直接把蛇实现在地图

  • 用GUI实现java版贪吃蛇小游戏

    本文实例为大家分享了java版贪吃蛇小游戏的具体代码,供大家参考,具体内容如下 项目结构 新建一个JFrame窗口,作为程序入口 public class GameStart{ public static void main(String[] args) { JFrame jFrame = new JFrame(); jFrame.setBounds(100,100,900,720); jFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON

  • java贪吃蛇游戏编写代码

    本文实例为大家分享了java贪吃蛇游戏展示的具体代码,供大家参考,具体内容如下 1.采用MVC(model.view.control)框架模式 2.包和类的关系树形图为: 3.源码: package com.huai; import Java.awt.Color; import java.awt.Graphics; import java.awt.Point; import java.util.HashSet; import java.util.LinkedList; import java.u

  • java贪吃蛇极速版

    本文为大家推荐了一款由java实现经典小游戏:贪吃蛇,相信大家都玩过,如何实现的呐? 效果图: 废话不多说,直接奉上代码: 1. public class GreedSnake { public static void main(String[] args) { SnakeModel model = new SnakeModel(20,30); SnakeControl control = new SnakeControl(model); SnakeView view = new SnakeVi

  • java编写简易贪吃蛇游戏

    本文实例为大家分享了java编写的贪吃蛇源码,供大家参考,具体内容如下 程序共包含以下两个文件: 文件:ShellWin.java import java.awt.Color; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.Graphics; import java.awt.event.*; import javax.swing.Box; import javax.swing.JButton; imp

  • java编写贪吃蛇小游戏

    废话不多说,直接奉上代码: Frame.java package snake; import java.awt.Graphics; import java.awt.Menu; import java.awt.MenuBar; import java.awt.MenuItem; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import

  • Java贪吃蛇游戏完善版

    很认真的写的一个java版的贪吃蛇游戏,图形界面,支持菜单操作,键盘监听,可加速,减速,统计得分,设定运动速度,设定游戏背景颜色等!应该没有Bug了,因为全被我修改没了. 下面是项目各包及类的层次关系: 游戏的主要运行界面截图如下: 下面是部分代码,详细源码见此链接:贪吃蛇源码下载 Snake类: package com.huowolf.entities; import java.awt.Color; import java.awt.Graphics; import java.awt.Point

  • Java实现贪吃蛇游戏(1小时学会)

    今天就来拿贪吃蛇小游戏来练练手吧! 贪吃蛇游戏规则: 1.按下空格键(游戏未结束)则游戏暂停或开始: 2.按下空格键(游戏结束后)则游戏重新开始: 3.当贪吃蛇的头部撞到身体时则贪吃蛇死亡(游戏结束): 4.当贪吃蛇的头部撞到墙时贪吃蛇死亡(游戏结束): 游戏界面效果: 我们可以看到自己的贪吃蛇吃了多少食物,以及游戏得分.下面是游戏效果图: 源码(注释超详细,注意ImageDate类中的material是一个包名,里面存放的是游戏素材图片): package program_code; impo

随机推荐