贪吃蛇项目总结
功能实现一般都要经过三个过程:定义数据,静态实现,动态实现
- 编程应是一种思想.写代码的时间是很少的,大部分时间是用于思考和解决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();
}
public void init(){
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;
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(){
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);
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();
}
}
狂神说视频地址:https://www.bilibili.com/video/BV1HE41127CV