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 SnakeView(model,control);
    //添加一个观察者,让view成为model的观察者
    model.addObserver(view);

    (new Thread(model)).start();
  }
}

2、

package mvcTest;

//SnakeControl.java
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

public class SnakeControl implements KeyListener{
  SnakeModel model;

  public SnakeControl(SnakeModel model){
    this.model = model;
  }

  public void keyPressed(KeyEvent e) {
    int keyCode = e.getKeyCode();
    if (model.running){        // 运行状态下,处理的按键
      switch (keyCode) {
        case KeyEvent.VK_UP:
          model.changeDirection(SnakeModel.UP);
          break;
        case KeyEvent.VK_DOWN:
          model.changeDirection(SnakeModel.DOWN);
          break;
        case KeyEvent.VK_LEFT:
          model.changeDirection(SnakeModel.LEFT);
          break;
        case KeyEvent.VK_RIGHT:
          model.changeDirection(SnakeModel.RIGHT);
          break;
        case KeyEvent.VK_ADD:
        case KeyEvent.VK_PAGE_UP:
          model.speedUp();
          break;
        case KeyEvent.VK_SUBTRACT:
        case KeyEvent.VK_PAGE_DOWN:
          model.speedDown();
          break;
        case KeyEvent.VK_SPACE:
        case KeyEvent.VK_P:
          model.changePauseState();
          break;
        default:
      }
    }

    // 任何情况下处理的按键,按键导致重新启动游戏
    if (keyCode == KeyEvent.VK_R ||
        keyCode == KeyEvent.VK_S ||
        keyCode == KeyEvent.VK_ENTER) {
      model.reset();
    }
  }

  public void keyReleased(KeyEvent e) {
  }

  public void keyTyped(KeyEvent e) {
  }
}

3、

package mvcTest;

//SnakeModel.java
import javax.swing.*;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.Observable;
import java.util.Random;

class SnakeModel extends Observable implements Runnable {
  boolean[][] matrix;             // 指示位置上有没蛇体或食物
  LinkedList nodeArray = new LinkedList();  // 蛇体
  Node food;
  int maxX;
  int maxY;
  int direction = 2;             // 蛇运行的方向
  boolean running = false;          // 运行状态

  int timeInterval = 200;           // 时间间隔,毫秒
  double speedChangeRate = 0.75;       // 每次得速度变化率
  boolean paused = false;           // 暂停标志

  int score = 0;               // 得分
  int countMove = 0;             // 吃到食物前移动的次数

  // UP and DOWN should be even
  // RIGHT and LEFT should be odd
  public static final int UP = 2;
  public static final int DOWN = 4;
  public static final int LEFT = 1;
  public static final int RIGHT = 3;

  public SnakeModel( int maxX, int maxY) {
    this.maxX = maxX;
    this.maxY = maxY;

    reset();
  }

  public void reset(){
    direction = SnakeModel.UP;       // 蛇运行的方向
    timeInterval = 200;           // 时间间隔,毫秒
    paused = false;             // 暂停标志
    score = 0;               // 得分
    countMove = 0;             // 吃到食物前移动的次数

    // initial matirx, 全部清0
    matrix = new boolean[maxX][];
    for (int i = 0; i < maxX; ++i) {
      matrix[i] = new boolean[maxY];
      Arrays.fill(matrix[i], false);
    }

    // initial the snake
    // 初始化蛇体,如果横向位置超过20个,长度为10,否则为横向位置的一半
    int initArrayLength = maxX > 20 ? 10 : maxX / 2;
    nodeArray.clear();
    for (int i = 0; i < initArrayLength; ++i) {
      int x = maxX / 2 + i;//maxX被初始化为20
      int y = maxY / 2;  //maxY被初始化为30
      //nodeArray[x,y]: [10,15]-[11,15]-[12,15]~~[20,15]
      //默认的运行方向向上,所以游戏一开始nodeArray就变为:
      //    [10,14]-[10,15]-[11,15]-[12,15]~~[19,15]
      nodeArray.addLast(new Node(x, y));
      matrix[x][y] = true;
    }

    // 创建食物
    food = createFood();
    matrix[food.x][food.y] = true;
  }

  public void changeDirection(int newDirection) {
    // 改变的方向不能与原来方向同向或反向
    if (direction % 2 != newDirection % 2) {
      direction = newDirection;
    }
  }

  public boolean moveOn() {
    Node n = (Node) nodeArray.getFirst();
    int x = n.x;
    int y = n.y;

    // 根据方向增减坐标值
    switch (direction) {
      case UP:
        y--;
        break;
      case DOWN:
        y++;
        break;
      case LEFT:
        x--;
        break;
      case RIGHT:
        x++;
        break;
    }

    // 如果新坐标落在有效范围内,则进行处理
    if ((0 <= x && x < maxX) && (0 <= y && y < maxY)) {

      if (matrix[x][y]) {    // 如果新坐标的点上有东西(蛇体或者食物)
        if (x == food.x && y == food.y) {    // 吃到食物,成功
          nodeArray.addFirst(food);      // 从蛇头赠长

          // 分数规则,与移动改变方向的次数和速度两个元素有关
          int scoreGet = (10000 - 200 * countMove) / timeInterval;
          score += scoreGet > 0 ? scoreGet : 10;
          countMove = 0;

          food = createFood();        // 创建新的食物
          matrix[food.x][food.y] = true;   // 设置食物所在位置
          return true;
        } else                 // 吃到蛇体自身,失败
          return false;

      } else {         // 如果新坐标的点上没有东西(蛇体),移动蛇体
        nodeArray.addFirst(new Node(x, y));
        matrix[x][y] = true;
        n = (Node) nodeArray.removeLast();
        matrix[n.x][n.y] = false;
        countMove++;
        return true;
      }
    }
    return false;                  // 触到边线,失败
  }

  public void run() {
    running = true;
    while (running) {
      try {
        Thread.sleep(timeInterval);
      } catch (Exception e) {
        break;
      }

      if (!paused) {
        if (moveOn()) {
          setChanged();      // Model通知View数据已经更新
          notifyObservers();
        } else {
          JOptionPane.showMessageDialog(null,
              "you failed",
              "Game Over",
              JOptionPane.INFORMATION_MESSAGE);
          break;
        }
      }
    }
    running = false;
  }

  private Node createFood() {
    int x = 0;
    int y = 0;
    // 随机获取一个有效区域内的与蛇体和食物不重叠的位置
    do {
      Random r = new Random();
      x = r.nextInt(maxX);
      y = r.nextInt(maxY);
    } while (matrix[x][y]);

    return new Node(x, y);
  }

  public void speedUp() {
    timeInterval *= speedChangeRate;
  }

  public void speedDown() {
    timeInterval /= speedChangeRate;
  }

  public void changePauseState() {
    paused = !paused;
  }

  public String toString() {
    String result = "";
    for (int i = 0; i < nodeArray.size(); ++i) {
      Node n = (Node) nodeArray.get(i);
      result += "[" + n.x + "," + n.y + "]";
    }
    return result;
  }
}

class Node {
  int x;
  int y;

  Node(int x, int y) {
    this.x = x;
    this.y = y;
  }
}

4、

package mvcTest;

//SnakeView.java
import javax.swing.*;
import java.awt.*;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Observable;
import java.util.Observer;

public class SnakeView implements Observer {
  SnakeControl control = null;
  SnakeModel model = null;

  JFrame mainFrame;
  Canvas paintCanvas;
  JLabel labelScore;

  public static final int canvasWidth = 200;
  public static final int canvasHeight = 300;

  public static final int nodeWidth = 10;
  public static final int nodeHeight = 10;

  public SnakeView(SnakeModel model, SnakeControl control) {
    this.model = model;
    this.control = control;

    mainFrame = new JFrame("GreedSnake");

    Container cp = mainFrame.getContentPane();

    // 创建顶部的分数显示
    labelScore = new JLabel("Score:");
    cp.add(labelScore, BorderLayout.NORTH);

    // 创建中间的游戏显示区域
    paintCanvas = new Canvas();
    paintCanvas.setSize(canvasWidth + 1, canvasHeight + 1);
    paintCanvas.addKeyListener(control);
    cp.add(paintCanvas, BorderLayout.CENTER);

    // 创建底下的帮助栏
    JPanel panelButtom = new JPanel();
    panelButtom.setLayout(new BorderLayout());
    JLabel labelHelp;
    labelHelp = new JLabel("PageUp, PageDown for speed;", JLabel.CENTER);
    panelButtom.add(labelHelp, BorderLayout.NORTH);
    labelHelp = new JLabel("ENTER or R or S for start;", JLabel.CENTER);
    panelButtom.add(labelHelp, BorderLayout.CENTER);
    labelHelp = new JLabel("SPACE or P for pause", JLabel.CENTER);
    panelButtom.add(labelHelp, BorderLayout.SOUTH);
    cp.add(panelButtom, BorderLayout.SOUTH);

    mainFrame.addKeyListener(control);
    mainFrame.pack();
    mainFrame.setResizable(false);
    mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    mainFrame.setVisible(true);
  }

  void repaint() {
    Graphics g = paintCanvas.getGraphics();

    //draw background
    g.setColor(Color.WHITE);
    g.fillRect(0, 0, canvasWidth, canvasHeight);

    // draw the snake
    g.setColor(Color.BLACK);
    LinkedList na = model.nodeArray;
    Iterator it = na.iterator();
    while (it.hasNext()) {
      Node n = (Node) it.next();
      drawNode(g, n);
    }

    // draw the food
    g.setColor(Color.RED);
    Node n = model.food;
    drawNode(g, n);

    updateScore();
  }

  private void drawNode(Graphics g, Node n) {
    g.fillRect(n.x * nodeWidth,
        n.y * nodeHeight,
        nodeWidth - 1,
        nodeHeight - 1);
  }

  public void updateScore() {
    String s = "Score: " + model.score;
    labelScore.setText(s);
  }

  public void update(Observable o, Object arg) {
    repaint();
  }
}

本文的目的就是带着大家回味经典,但是更主要的目的就是帮助大家学习好java程序设计。

(0)

相关推荐

  • Java的GUI编程之列表和组合框的设计使用

    列表和组合框是又一类供用户选择的界面组件,用于在一组选择项目选择,组合框还可以输入新的选择. 列表 列表(JList)在界面中表现为列表框,是JList类或它的子类的对象.程序可以在列表框中加入多个文本选择项条目.列表事件的事件源有两种: 一是鼠标双击某个选项:双击选项是动作事件,与该事件相关的接口是ActionListener,注册监视器的方法是addActionListener(),接口方法是actionPerformed(ActionEvent e). 二是鼠标单击某个选项:单击选项是选项

  • java必学必会之GUI编程

    一.事件监听 测试代码一: package cn.javastudy.summary; import java.awt.*; import java.awt.event.*; public class TestTextField { public static void main(String args[]) { new MyFrameTextField(); } } class MyFrameTextField extends Frame { MyFrameTextField() { Text

  • Java编程中应用的GUI设计基础

    早先程序使用最简单的输入输出方式,用户在键盘输入数据,程序将信息输出在屏幕上.现代程序要求使用图形用户界面(Graphical User Interface,GUI),界面中有菜单.按钮等,用户通过鼠标选择菜单中的选项和点击按钮,命令程序功能模块.本章学习如何用Java语言编写GUI科学试验,如何通过GUI实现输入和输出. AWT和Swing 先前用Java编写GUI程序,是使用抽象窗口工具包AWT(Abstract Window Toolkit).现在多用Swing.Swing可以看作是AWT

  • JAVA GUI自定义JPanel画板背景

    自定义JPanel面板背景 一.前言 1.GUI全称是Graphical User Interface,就是图形用户界面.JAVA的GUI应用广泛在我们生活中也很常见.很多应用使用该GUI编程设计,像点击QQ图标弹出对应的登录窗体. 一般程序与用户的交互都基于对应程序的运行界面. 2.JPanel面板是SWING下的一个面板容器类.该面板支持嵌套,可设置布局方式,设置不同的布局管理器可添加其他控件像JButton按钮,JTextField文本框等.来设计完善一个程序界面窗体. 作为绘制面板支持s

  • 使用Java编写GUI对话框的教程

    对话框是为了人机对话过程提供交互模式的工具.应用程序通过对话框,或给用户提供信息,或从用户获得信息.对话框是一个临时窗口,可以在其中放置用于得到用户输入的控件.在Swing中,有两个对话框类,它们是JDialog类和JOptionPane类.JDialog类提供构造并管理通用对话框:JOptionPane类给一些常见的对话框提供许多便于使用的选项,例如,简单的"yes-no"对话框等. JDialog类 JDialog类作作对话框的基类.对话框与一般窗口不同,对话框依赖其他窗口,当它所

  • java实现的简单猜数字游戏代码

    本文实例讲述了java实现的简单猜数字游戏代码.分享给大家供大家参考. 具体代码如下: 复制代码 代码如下: import java.util.InputMismatchException; import java.util.Scanner; public class Main {         public static void main(String[] args) {                 // 产生一个随机数                 int number = (in

  • 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 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贪吃蛇游戏展示的具体代码,供大家参考,具体内容如下 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中使用双向链表实现贪吃蛇程序源码分享

    使用双向链表实现贪吃蛇程序 1.链表节点定义: package snake; public class SnakeNode { private int x; private int y; private SnakeNode next; private SnakeNode ahead; public SnakeNode() { } public SnakeNode(int x, int y) { super(); this.x = x; this.y = y; } public int getX(

随机推荐