欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

java實(shí)現(xiàn)貪吃蛇小游戲

 更新時間:2020年07月27日 11:47:18   作者:AdvancedPawn  
這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)貪吃蛇小游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下

本文實(shí)例為大家分享了java實(shí)現(xiàn)貪吃蛇小游戲的具體代碼,供大家參考,具體內(nèi)容如下

這是MVC模式的完整Java項目,編譯運(yùn)行SnakeApp.java即可開始游戲。

可擴(kuò)展功能:

1、積分功能:可以創(chuàng)建得分規(guī)則的類(模型類的一部分), 在GameController的run()方法中計算得分
2、變速功能:比如加速功能,減速功能,可以在GameController的keyPressed()方法中針對特定的按鍵設(shè)置每一次移動之間的時間間隔,將Thread.sleep(Settings.DEFAULT_MOVE_INTERVAL);替換為動態(tài)的時間間隔即可
3、更漂亮的游戲界面:修改GameView中的drawXXX方法,比如可以將食物渲染為一張圖片,Graphics有drawImage方法

View

SnakeApp.java

/*
 * 屬于View,用來根據(jù)相應(yīng)的類展示出對應(yīng)的游戲主界面,也是接收控制信息的第一線。
 */
public class SnakeApp {
 public void init() {
  //創(chuàng)建游戲窗體
  JFrame window = new JFrame("一只長不大的蛇");
  //初始化500X500的棋盤,用來維持各種游戲元素的狀態(tài),游戲的主要邏輯部分
  Grid grid = new Grid(50*Settings.DEFAULT_NODE_SIZE,50*Settings.DEFAULT_NODE_SIZE);
  //傳入grid參數(shù),新建界面元素對象
  GameView gameView = new GameView(grid);//繪制游戲元素的對象
  //初始化面板
  gameView.initCanvas();
  //根據(jù)棋盤信息建立控制器對象
  GameController gameController = new GameController(grid);
  
  //設(shè)置窗口大小
  window.setPreferredSize(new Dimension(526,548));
  
  //往窗口中添加元素,面板對象被加入到窗口時,自動調(diào)用其中的paintComponent方法。
  window.add(gameView.getCanvas(),BorderLayout.CENTER);
  
  //畫出蛇和棋盤和食物
  GameView.draw();
  
  //注冊窗口監(jiān)聽器
  window.addKeyListener((KeyListener)gameController);
  
  //啟動線程
  new Thread(gameController).start();
  
  //窗口關(guān)閉的行為
  window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  //設(shè)置窗口大小不可變化
  window.setResizable(false);
  //渲染和顯示窗口
  window.pack();
  window.setVisible(true);
 }
 //可以忽略,以后每個類中都有這么一個測試模塊
 public static void main(String[] args) {
  SnakeApp snakeApp = new SnakeApp();
  snakeApp.init();
 }
}

GameView.java

/*
 * 屬于View,用于繪制地圖、蛇、食物
*/

 /* Graphics 相當(dāng)于一個畫筆。對象封裝了 Java 支持的基本呈現(xiàn)操作所需的狀態(tài)信息。此狀態(tài)信息包括以下屬性:
 要在其上繪制的 Component 對象。
 呈現(xiàn)和剪貼坐標(biāo)的轉(zhuǎn)換原點(diǎn)。
 當(dāng)前剪貼區(qū)。
 當(dāng)前顏色。
 當(dāng)前字體。
 當(dāng)前邏輯像素操作函數(shù)(XOR 或 Paint)。
 當(dāng)前 XOR 交替顏色
*/

/* java.awt.Component的repaint()方法
 作用:更新組件。
 如果此組件不是輕量級組件,則為了響應(yīng)對 repaint 的調(diào)用,AWT 調(diào)用 update 方法??梢约俣ㄎ辞宄尘啊?
 Component 的 update 方法調(diào)用此組件的 paint 方法來重繪此組件。為響應(yīng)對 repaint 的調(diào)用而需要其他工作的子類通常重寫此方法。重寫此方法的 Component 子類應(yīng)該調(diào)用 super.update(g),或者直接從其 update 方法中調(diào)用 paint(g)。
 圖形上下文的原點(diǎn),即它的(0,0)坐標(biāo)點(diǎn)是此組件的左上角。圖形上下文的剪貼區(qū)域是此組件的邊界矩形。
 */
public class GameView {
 private final Grid grid;
 private static JPanel canvas;//畫板,用于在這上面制作畫面,然后返回。
 
 public GameView(Grid grid) {
 this.grid = grid;
 }
 //重新繪制游戲界面元素,不斷重新調(diào)用paintComponent方法覆蓋原本的面板。
 public static void draw() {
  canvas.repaint();
  }
  //獲取畫板對象的接口
 public JPanel getCanvas() {
  return canvas;
  }
 //對畫板進(jìn)行初始化
 public void initCanvas() {
 canvas = new JPanel() {
 //指向一個方法被覆蓋的新面板子類對象
 //paintComponent()繪制此容器中的每個組件,Swing會在合適的時機(jī)去調(diào)用這個方法,展示出合適的界面,這就是典型的回調(diào)(callback)的概念。
 public void paintComponent(Graphics graphics) {
 super.paintComponent(graphics); //這里必須調(diào)用一下父類 也就是 container的重繪方法,否則表現(xiàn)為之前的繪圖不會覆蓋
 drawGridBackground(graphics);//畫出背景網(wǎng)格線
 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運(yùn)動軌跡,橫豎各以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)
 在此圖形上下文的坐標(biāo)系中,使用當(dāng)前顏色在點(diǎn) (x1, y1) 和 (x2, y2) 之間畫一條線。
 參數(shù):
 x1 - 第一個點(diǎn)的 x 坐標(biāo)。
 y1 - 第一個點(diǎn)的 y 坐標(biāo)。
 x2 - 第二個點(diǎn)的 x 坐標(biāo)。
 y2 - 第二個點(diǎn)的 y 坐標(biāo)。
  */
 //提供直接出現(xiàn)游戲結(jié)束的選項框的功能。
 public static void showGameOverMessage() {
  JOptionPane.showMessageDialog(null,"游戲結(jié)束","短暫的蛇生到此結(jié)束", 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即時的更新狀態(tài)。
 * 同時根據(jù)最新狀態(tài)渲染出游戲界面讓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) {//如果下一步更新棋盤時,出現(xiàn)游戲結(jié)束返回值(如果flag為假)則
 this.running = false;
 GameView.showGameOverMessage();
 System.exit(0);
 }
 }
 
 @Override
 /*run()函數(shù)中的核心邏輯是典型的控制器(Controller)邏輯:
 修改模型(Model):調(diào)用Grid的方法使游戲進(jìn)入下一步
 更新視圖(View):調(diào)用GameView的方法刷新頁面*/
 public void run() {
 while(running) {
 try {
 Thread.sleep(Settings.DEFAULT_MOVE_INTERVAL);
 isOver(grid.nextRound());
 GameView.draw();
 } catch (InterruptedException e) {
 break;
 }
 // 進(jìn)入游戲下一步
   // 如果結(jié)束,則退出游戲
   // 如果繼續(xù),則繪制新的游戲頁面
 }
 running = false;
 }
 
 
 @Override
 public void keyTyped(KeyEvent e) {
 }
 @Override
 public void keyReleased(KeyEvent e) {
 }
}

Model

Grid

/*
 * 隨機(jī)生成食物,維持貪吃蛇的狀態(tài),根據(jù)SnakeApp中的用戶交互來控制游戲狀態(tài)。
 */
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;
 }
 }
 //棋盤上隨機(jī)制造食物的功能。
 //一直循環(huán)獲取隨機(jī)值,直到三個條件都不滿足。
 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;
 }
 
 //提供下一步更新棋盤的功能,移動后更新游戲和蛇的狀態(tài)。
 public boolean nextRound() {
 Node trail = snake.move(snakeDirection);
 Node snakeHead = snake.getBody().removeFirst();//將頭部暫時去掉,拿出來判斷是否身體和頭部有重合的點(diǎn)
 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;//更新棋盤狀態(tài)并返回游戲是否結(jié)束的標(biāo)志
 }
 return false;
 }
 
 public Node getFood() {
 return food;
 }
 
 public Snake getSnake() {
 return snake;
 }
 
 public int getWidth() {
 return width;
 }
 
 public int getHeight() {
 return height;
 }
 
 //提供一個更改貪吃蛇前進(jìn)方向的方法
 public void changeDirection(Direction newDirection){
   snakeDirection = newDirection;
 }
}

Snake

/*
 * 蛇類,實(shí)現(xiàn)了自身數(shù)據(jù)結(jié)構(gòu),以及移動的功能
 */
public class Snake implements Cloneable{
 public LinkedList<Node> body = new LinkedList<>();
 public Node move(Direction direction) {
 //根據(jù)方向更新貪吃蛇的body
 //返回移動之前的尾部Node(為了吃到時候后增加尾部長度做準(zhǔn)備)
 Node n;//臨時存儲新頭部移動方向的結(jié)點(diǎ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;
 }
 //判斷參數(shù)結(jié)點(diǎn)是否在蛇身上
 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); //調(diào)用構(gòu)造方法對方向枚舉實(shí)例進(jìn)行代碼初始化
 //成員變量
 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;
 }//使用這種方法可以使得節(jié)點(diǎn)坐標(biāo)不會出現(xiàn)個位數(shù)
 
 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;//每一個節(jié)點(diǎn)方塊的單位
 public static int DEFAULT_MOVE_INTERVAL = 200;//蛇移動時間間隔
}

更多有趣的經(jīng)典小游戲?qū)崿F(xiàn)專題,分享給大家:

C++經(jīng)典小游戲匯總

python經(jīng)典小游戲匯總

python俄羅斯方塊游戲集合

JavaScript經(jīng)典游戲 玩不停

javascript經(jīng)典小游戲匯總

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • java操作gaussDB數(shù)據(jù)庫的實(shí)現(xiàn)示例

    java操作gaussDB數(shù)據(jù)庫的實(shí)現(xiàn)示例

    本文主要介紹了java操作gaussDB數(shù)據(jù)庫的實(shí)現(xiàn)示例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-07-07
  • java開發(fā)Dubbo注解Adaptive實(shí)現(xiàn)原理

    java開發(fā)Dubbo注解Adaptive實(shí)現(xiàn)原理

    這篇文章主要為大家介紹了java開發(fā)Dubbo注解Adaptive實(shí)現(xiàn)原理詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-09-09
  • Java枚舉類型enum的詳解及使用

    Java枚舉類型enum的詳解及使用

    這篇文章主要介紹了Java枚舉類型enum的詳解及使用的相關(guān)資料,需要的朋友可以參考下
    2017-05-05
  • Mybatis通過Mapper代理連接數(shù)據(jù)庫的方法

    Mybatis通過Mapper代理連接數(shù)據(jù)庫的方法

    這篇文章主要介紹了Mybatis通過Mapper代理連接數(shù)據(jù)庫的方法,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-11-11
  • Spring Boot配置動態(tài)更新問題

    Spring Boot配置動態(tài)更新問題

    這篇文章主要介紹了Spring Boot配置動態(tài)更新問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-09-09
  • 微信支付之公眾號支付(java實(shí)現(xiàn))

    微信支付之公眾號支付(java實(shí)現(xiàn))

    這篇文章主要介紹了微信支付之公眾號支付(java實(shí)現(xiàn)),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-10-10
  • 詳解SpringBoot如何實(shí)現(xiàn)多環(huán)境配置

    詳解SpringBoot如何實(shí)現(xiàn)多環(huán)境配置

    在實(shí)際的軟件開發(fā)過程中,一個應(yīng)用程序通常會有多個環(huán)境,pring?Boot?提供了一個非常靈活和強(qiáng)大的方式來管理這些環(huán)境配置,下面就跟隨小編一起學(xué)習(xí)一下吧
    2023-07-07
  • Java基礎(chǔ)之多線程方法狀態(tài)和創(chuàng)建方法

    Java基礎(chǔ)之多線程方法狀態(tài)和創(chuàng)建方法

    Java中可以通過Thread類和Runnable接口來創(chuàng)建多個線程,下面這篇文章主要給大家介紹了關(guān)于Java基礎(chǔ)之多線程方法狀態(tài)和創(chuàng)建方法的相關(guān)資料,需要的朋友可以參考下
    2021-09-09
  • MyBatis查詢無記錄時的返回值問題

    MyBatis查詢無記錄時的返回值問題

    這篇文章主要介紹了MyBatis查詢無記錄時的返回值問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-01-01
  • Spring中Bean對象的定義、注冊和獲取流程分析

    Spring中Bean對象的定義、注冊和獲取流程分析

    這篇文章主要介紹了Spring中Bean對象的定義、注冊和獲取流程分析,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-06-06

最新評論