4.贪吃蛇
必备知识:
- 帧,如果时间片足够小,就是动画,一秒30帧,连起来就是动画,拆开就是静态的图片
- 键盘监听
- 定时器Timer
主启动类
package com.zr.snake;
import javax.swing.*;
import java.awt.*;
//游戏的主启动类
public class StartGame {
public static void main(String[] args) {
//创建游戏窗口,名字为"贪吃蛇的世界"
JFrame frame = new JFrame("贪吃蛇的世界");
//设置游戏窗口大小位置
frame.setBounds(320,100,875,750);
//设置游戏窗口大小不可变
frame.setResizable(false);
//设置游戏窗口可关闭
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
//frame.setVisible(true);如果放在添加面板之前,就只会显示窗口,添加的游戏面板加载不出来
//将游戏面板添加到游戏窗口中
frame.add(new GamePanel());
//设置游戏窗口可见 必须放在最后!!!!!
frame.setVisible(true);
}
}
数据中心
package com.zr.snake;
import javax.swing.*;
import java.net.URL;
//蛇的数据
public class SnakeData {
//蛇的头,身子都为25*25像素的
//相对路径(类的包下的文件):"文件名.后缀名" 绝对路径(src目录下的文件):"/**.*.后缀名"
private static URL bodyURL = SnakeData.class.getResource("/statics/body.png");
public static ImageIcon body = new ImageIcon(bodyURL);
private static URL downURL = SnakeData.class.getResource("/statics/down.png");
public static ImageIcon down = new ImageIcon(downURL);
private static URL foodURL = SnakeData.class.getResource("/statics/food.png");
public static ImageIcon food = new ImageIcon(foodURL);
private static URL headerURL = SnakeData.class.getResource("/statics/header.png");
public static ImageIcon header = new ImageIcon(headerURL);
private static URL leftURL = SnakeData.class.getResource("/statics/left.png");
public static ImageIcon left = new ImageIcon(leftURL);
private static URL rightURL = SnakeData.class.getResource("/statics/right.png");
public static ImageIcon right = new ImageIcon(rightURL);
private static URL upURL = SnakeData.class.getResource("/statics/up.png");
public static ImageIcon up = new ImageIcon(upURL);
}
游戏面板
package com.zr.snake;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.Random;
//游戏的面板 继承面板类,实现键盘监听器接口
public class GamePanel extends JPanel implements KeyListener,ActionListener {
private int length;//蛇的节数
private int[] snakeX = new int[980];//蛇的x坐标数组
private int[] snakeY = new int[980];//蛇的y坐标数组
private String direction;//蛇头的方向
private int score;
private int foodX;//食物的x坐标
private int foodY;//食物的y坐标
private Boolean isStart;//游戏状态
private boolean isFail;//游戏是否失败
private Random random = new Random();//生成随机数种子
//定时器 每1000毫秒执行一次ActionListener对象的actionPerformed()方法
private Timer timer = new Timer(130,this);
//调用构造器执行init()方法
public GamePanel() {
init();//调用初始化方法
this.setFocusable(true);//绑定焦点事件
this.addKeyListener(this);//绑定键盘监听事件
timer.start();//定时器开始
}
//初始化方法
public void init() {
length = 3;
snakeX[0] = 150;snakeY[0] = 100;//蛇头的坐标
snakeX[1] = 125;snakeY[1] = 100;//第一节身子的坐标
snakeX[2] = 100;snakeY[2] = 100;//第二节身子的坐标
direction = "right";//默认蛇头向右
isStart = false;//默认游戏状态为不开始
isFail = false;//默认游戏不失败
//初始化随机食物坐标
//g.fillRect(0, 50, w875, h700);
foodX = 25*random.nextInt(34);
foodY = 50+25*random.nextInt(26);
score = 0;
}
//绘制面板,游戏中的所有资源,都用此画笔g来画
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);//清屏 ??闪烁??
//设置面板颜色为白色
this.setBackground(new Color(134, 93, 75));
//画励志语
SnakeData.header.paintIcon(this, g, 100, 0);
//画游戏界面(实心矩形)
g.fillRect(0, 50, 875, 700);
//画食物
SnakeData.food.paintIcon(this,g,foodX,foodY);
//画蛇
//动态画蛇头
if (direction.equals("right")) {
SnakeData.right.paintIcon(this, g, snakeX[0], snakeY[0]);
} else if (direction.equals("up")) {
SnakeData.up.paintIcon(this, g, snakeX[0], snakeY[0]);
} else if (direction.equals("down")) {
SnakeData.down.paintIcon(this, g, snakeX[0], snakeY[0]);
} else if (direction.equals("left")) {
SnakeData.left.paintIcon(this, g, snakeX[0], snakeY[0]);
}
//动态画蛇身
for (int i = 1; i < length; i++) {
SnakeData.body.paintIcon(this, g, snakeX[i], snakeY[i]);
}
g.setColor(new Color(41, 45, 41, 182));
g.setFont(new Font("微软雅黑", Font.BOLD, 15));
g.drawString("长度:"+length, 800, 20);
g.drawString("积分:"+score, 800, 40);
//画状态提示语
if (isStart == false) {
g.setColor(new Color(235, 255, 232, 182));
g.setFont(new Font("微软雅黑", Font.BOLD, 40));
g.drawString("按下空格开始游戏", 275, 300);
}
//画失败提示语
if (isFail){
g.setColor(new Color(109, 1, 8, 182));
g.setFont(new Font("微软雅黑", Font.BOLD, 40));
g.drawString("你失败了", 275, 300);
}
}
@Override//事件监听---需要通过固定时间来刷新
public void actionPerformed(ActionEvent e) {
if(snakeX[0] == foodX & snakeY[0] == foodY){
length++;
score = score + 10;
foodX = 25*random.nextInt(35);
foodY = 50+25*random.nextInt(30);
}
//如果游戏开始且不失败
if (isStart && isFail == false) {
//蛇身的移动
for (int i = length - 1; i > 0; i--) {
snakeX[i] = snakeX[i - 1];//向前移动一节
snakeY[i] = snakeY[i - 1];
}
//蛇头的移动
if(direction.equals("right")){
snakeX[0] = snakeX[0] + 25;
if(snakeX[0] > 875){ snakeX[0] = 0; }//边界判断
} else if(direction.equals("left")){
snakeX[0] = snakeX[0] - 25;
if(snakeX[0] < 0) { snakeX[0] = 875; }//边界判断
} else if (direction.equals("up")){
snakeY[0] = snakeY[0] - 25;
if(snakeY[0] <50) { snakeY[0] = 750; }//边界判断
} else if(direction.equals("down")){
snakeY[0] = snakeY[0] + 25;
if(snakeY[0] > 750) { snakeY[0] = 50;}//边界判断
}
//失败判定
for (int i = 1; i < length; i++) {
if(snakeX[0] == snakeX[i] & snakeY[0] == snakeY[i]){
isFail = true;
}
}
repaint();
}
}
@Override//键盘监听
public void keyPressed(KeyEvent e) {
int keyCode = e.getKeyCode();//获得键值
if (keyCode == KeyEvent.VK_SPACE) {//当键值为空格
if(isFail){//如果当前为失败
isFail = false;
init();
}else {
isStart = !isStart;//状态取反
}
}else if(keyCode == KeyEvent.VK_UP){//当键值为上
if(direction.equals("down")){//如果此时方向与键值相反,则返回
return;
}else {
direction = "up";
}
}else if(keyCode == KeyEvent.VK_DOWN) {//当键值为下
if(direction.equals("up")){
return;
}else {
direction = "down";
}
}else if(keyCode == KeyEvent.VK_LEFT) {//当键值为左
if(direction.equals("right")){
return;
}else {
direction = "left";
}
}else if(keyCode == KeyEvent.VK_RIGHT) {//当键值为右
if(direction.equals("left")){
return;
}else {
direction = "right";
}
}
repaint();//重画
}
public void keyTyped(KeyEvent e) {}
public void keyReleased(KeyEvent e) {}
}
转载:https://blog.csdn.net/weixin_45363806/article/details/105916654
查看评论