java实现贪吃蛇

9 篇文章 0 订阅
108 篇文章 0 订阅

贪吃蛇项目总结

功能实现一般都要经过三个过程:定义数据,静态实现,动态实现

  • 编程应是一种思想.写代码的时间是很少的,大部分时间是用于思考和解决bug上了.
  • 贪吃蛇的整个开发过程总结下来就是:一个主界面上放了一个面板.这个面板画了一些东西和监听事件.
  • 很多功能的实现其实来源于一个想法.如(1)贪吃蛇吃食物,本质就是判断蛇头和食物是否重合.(2)贪吃蛇死亡是遍历所有贪吃蛇的所有身体,当头和身体座标相同时,就是死了.
  • 逆向思维很重要:不允许贪吃蛇倒着走,就只是判断"按键方向不是蛇头相反的方向",只需要一行代码就可以实现一个功能.
  • ""debug"可以解决大部分想不懂的问题:学会利用工具
  • 在初始化方法中为值赋初始化值,这样就不用总是想着属性什么时候是什么状态–>万物终究归一
  • 先实现基本功能再优化,重要的是先要从0到1:道生一,一生二,二生三,三生万物.
  • 写代码应是一种享受的事情,特别是实现一个功能,解决一个bug时的那种成就感.
  • 道阻且长,行则将至.

主界面

package com.li.changGe.snake;

import javax.swing.*;

public class Index extends JFrame/**/{

  public static void main(String[] args) {
    new Index().init();
  }

  /**
   * 一个900x720的界面,不可拉伸
   * 添加一个游戏面板类用来画图
   */
  public void init(){
    //JFrame jFrame = new JFrame();

    setBounds(100,100,900,720);
    setResizable(false);

    setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    setVisible(true);

    add(new GamePanel());
  }

}

数据层

package com.li.changGe.snake;

import javax.swing.*;
import java.net.URL;

/**
 * 导入图片数据
 */
public class Data {

  private static URL bodyURL = Data.class.getResource("statics/body.png");
  public static ImageIcon body = new ImageIcon(bodyURL);

  private static URL downURL = Data.class.getResource("statics/down.png");
  public static ImageIcon down = new ImageIcon(downURL);

  private static URL foodURL = Data.class.getResource("statics/food.png");
  public static ImageIcon food = new ImageIcon(foodURL);

  private static URL headerURL = Data.class.getResource("statics/header.png");
  public static ImageIcon header = new ImageIcon(headerURL);

  private static URL leftURL = Data.class.getResource("statics/left.png");
  public static ImageIcon left = new ImageIcon(leftURL);

  private static URL rightURL = Data.class.getResource("statics/right.png");
  public static ImageIcon right = new ImageIcon(rightURL);

  private static URL upURL = Data.class.getResource("statics/up.png");
  public static ImageIcon up = new ImageIcon(upURL);

}

面板类

package com.li.changGe.snake;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Random;

/**
 * 主程序要有一个游戏面板
 *
 * 实现paintComponent方法
 * 留着super方法清屏
 *
 * 一个功能的实现一般经过三个过程
 * 定义数据,静态实现,动态实现
 */
public class GamePanel extends JPanel implements KeyListener, ActionListener {

  private int length;
  private int[] snakeX = new int[100];
  private int[] snakeY = new int[100];
  private String hear;

  private boolean start;
  
  private Timer timer = new Timer(100,this);

  private int[] food = new int[2];

  Random random = new Random();

  private boolean fail;

  private String body;

  public GamePanel(){
    this.init();

    /**
     * 让当前组件获取焦点
     *
     * 游戏一开始就要运行
     */
    setFocusable(true);
    addKeyListener(this);
    timer.start();
  }

  private void init(){
    /**
     * 初始化蛇的长度,x,y座标.
     * 一个格子25度
     *
     * java是以;号为结尾的
     * 
     * 在初始化方法中给属性赋初始值
     * 添加功能时知道程序最后都会回到初始
     */
    hear = "R";

    body = "L";

    start = false;

    length = 3;
    snakeX[0] = 100;snakeY[0] = 100;
    snakeX[1] = 75;snakeY[1] = 100;
    snakeX[2] = 50;snakeY[2] = 100;

    food[0] = 25 + (25 * random.nextInt(34));
    food[1] = 75 + (25 * random.nextInt(24));

    fail = true;
  }

  @Override
  public void paintComponent(Graphics g) {
    super.paintComponents(g);

    /**
     * 绘制广告头
     * 中间是个实心矩形
     */
    this.setBackground(new Color(0x2626D1));

    Data.header.paintIcon(this,g,25,11);

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

    /**
     * 食物画在蛇前面,
     * 蛇吃食物时是遮住食物的
     *
     * 画上小蛇,默认向右
     *
     * 变成动态的,小于length
     *
     * 设置默认头的方向
     *
     * 设置初始化提示语
     */

    g.setColor(new Color(0x4BE91B));
    g.setFont(new Font("微软雅黑",1,40));
    g.drawString("分数:" + length,730,50);

    Data.food.paintIcon(this,g,food[0],food[1]);

    for (int i = 1; i < length; i++) {
      Data.body.paintIcon(this,g,snakeX[i],snakeY[i]);
    }

    switch (hear){
      case "U":
        Data.up.paintIcon(this,g,snakeX[0],snakeY[0]);
        break;
      case "D":
        Data.down.paintIcon(this,g,snakeX[0],snakeY[0]);
        break;
      case "L":
        Data.left.paintIcon(this,g,snakeX[0],snakeY[0]);
        break;
      default:
        Data.right.paintIcon(this,g,snakeX[0],snakeY[0]);
    }

    if(start == false){
      g.setColor(new Color(0xF1E240));
      g.setFont(new Font("方正舒体",1,60));
      g.drawString("按下空格开始游戏",200,300);
    }

    /**
     * 游戏失败,重新开始
     */
    if(fail == false){
      g.setColor(new Color(0xD50C0C));
      g.setFont(new Font("方正舒体",1,40));
      g.drawString("游戏失败,按下空格重新开始,总得分:"+length,100,300);
    }

  }


  @Override
  public void keyTyped(KeyEvent e) {}

  /**
   * 监听空格键
   *
   * 别忘了重画
   */
  @Override
  public void keyPressed(KeyEvent e) {

    int key = e.getKeyCode();

    /**
     * 按下空格如果失败了游戏重新开始
     */
    if(key == KeyEvent.VK_SPACE){

      if(fail == false){
        init();
      }else {
        start = !start;
      }

      repaint();

    }

    /**
     * 开始和结束界面不允许操作
     * 
     * 上下左右的改变方向
     *
     * 如果按键时头是相反的方向,方向不变
     */
    if(fail != false && start != false){
      switch (key){

        case KeyEvent.VK_UP:
          if(hear != "D"){
            hear = "U";
          }
          break;
        case KeyEvent.VK_DOWN:
          if(hear != "U") {
            hear = "D";
          }
          break;
        case KeyEvent.VK_LEFT:
          if(hear != "R"){
            hear = "L";
          }
          break;
        case KeyEvent.VK_RIGHT:
          if(hear != "L"){
            hear = "R";
          }
          break;
      }

    }

    repaint();

  }

  @Override
  public void keyReleased(KeyEvent e) {}

  @Override
  public void actionPerformed(ActionEvent e) {
    /**
     * 界面动起来的条件:
     * 不需要按空格启动并且游戏没有失败
     *
     * 游戏开始就要不停的动
     *
     * 当前座标变成上一个座标
     *
     * 不能超过边界
     */
    if(start && fail){
      for (int i = length - 1; i > 0; i--) {
        snakeX[i] = snakeX[i -1];
        snakeY[i] = snakeY[i -1];
      }

      switch (hear){
        case "U":
          snakeY[0] -= 25;
          if(snakeY[0] < 75){
            snakeY[0] = 650;
          }
          break;
        case "D":
          snakeY[0] += 25;
          if(snakeY[0] > 650){
            snakeY[0] = 75;
          }
          break;
        case "L":
          snakeX[0] -= 25;
          if(snakeX[0] < 25){
            snakeX[0] = 850;
          }
          break;
        case "R":
          snakeX[0] += 25;
          if(snakeX[0] > 850){
            snakeX[0] = 25;
          }
          break;

      }

      /**
       * 蛇的身体和食物重叠
       * 食物被吃,重新刷新
       */
      if(snakeX[0] == food[0] && snakeY[0] == food[1]){
        length++;
        food[0] = 25 + (25 * random.nextInt(34));
        food[1] = 75 + (25 * random.nextInt(24));
      }


      /**
       * 头和身体重合 = 失败
       *
       * 按下空格重新开始
       */
      for (int i = 1; i < length; i++) {
        if(snakeX[0] == snakeX[i] && snakeY[0] == snakeY[i]){
          fail = false;
        }

      }

      if(snakeY[0] <= 75 || snakeY[0] >= 650 || snakeX[0] <= 25 || snakeX[0] >= 850){
        fail = false;
      }

      repaint();

    }

    timer.start();

  }

}

snke

狂神说视频地址:https://www.bilibili.com/video/BV1HE41127CV

  • 2
    点赞
  • 10
    收藏
  • 打赏
    打赏
  • 0
    评论

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

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:大白 设计师:CSDN官方博客 返回首页
评论

打赏作者

望江s

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值