GUI编程
查看上篇内容:
https://blog.csdn.net/weixin_42681553/article/details/121682018
贪吃蛇游戏
制作贪吃蛇需要:
- 键盘监听
- 定时器 Timer
思路分析
- 定义数据
- 定义需要用到的属性(游戏是否开始,用来存放小蛇X轴和Y轴坐标的数组,小蛇的长度,小蛇运动的方向,事物的位置)
- 画在面板上
- 根据小蛇长度和运动方向动态变化X轴和Y轴的值并在图片数据中展示头的方向
- 通过 Graphics 画笔绘制小蛇和食物
- 增加监听事件
- 键盘监听事件
- 监听键盘的上下左右和空格键,对应修改方向变量和暂停提示变量
- 事件监听事件
- 判断游戏开始,让小蛇移动(从数组最后一个开始让身体可以移动,头的移动结合方向变量的判断确定变化量)
- 判断食物的位置,是否和头重合,重合则小蛇长度增加,当前食物消失,并重新生成新的食物
- 增加判断头是否和身体重合,重合则撞到自己,游戏结束
- 键盘监听事件
案例代码
主方法类
public class StartGame {
public static void main(String[] args) {
JFrame frame = new JFrame();
//0.1游戏内容放在面板上
frame.add(new GamePanel());
frame.setVisible(true); //可见性
frame.setBounds(100,100,900,720);//窗口大小
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);//关闭窗口
frame.setResizable(false);//窗口不可变
}
}
定义图片数据类
public class Data {
//0.2相对路径定义图片路径
//上
public static URL upURL = Data.class.getResource("statics/up.png");
public static ImageIcon up = new ImageIcon(upURL);
//下
public static URL downURL = Data.class.getResource("statics/down.png");
public static ImageIcon down = new ImageIcon(downURL);
//左
public static URL leftURL = Data.class.getResource("statics/left.png");
public static ImageIcon left = new ImageIcon(leftURL);
//右
public static URL rightURL = Data.class.getResource("statics/right.png");
public static ImageIcon right = new ImageIcon(rightURL);
//身体
public static URL bodyURL = Data.class.getResource("statics/body.png");
public static ImageIcon body = new ImageIcon(bodyURL);
//食物
public static URL foodURL = Data.class.getResource("statics/food.png");
public static ImageIcon food = new ImageIcon(foodURL);
}
主要方法实现类
package com.kuang.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;
//游戏的面板,继承面板,实现监听类(不需要额外写class监听类)
public class GamePanel extends JPanel implements KeyListener, ActionListener {
//0.3定义静态的蛇(长度,头,身体等初始属性)
int length; //蛇的长度
int[] snakeX = new int[600]; //蛇的 X 坐标长度
int[] snakeY = new int[600]; //蛇的 Y 坐标长度
String direction; //小蛇运动的方向
boolean isStart; //游戏开始 or 暂停
boolean isFail; //游戏是否失败
int score; //分数
int foodX; //食物的 X 坐标
int foodY; //食物的 Y 坐标
Random random; //用于食物位置的随机值
//4.0定时器。以毫秒为单位,1000ms = 1s
Timer timer = new Timer(100,this);
//2.2构造器,初始化
public GamePanel() {
init();
//3.2获取焦点和键盘事件
this.setFocusable(true); //获取鼠标焦点事件
this.addKeyListener(this); //获取键盘监听事件,因为实现了键盘监听类,所以不需要 new keylistener
timer.start(); //游戏加载时就
}
//2.1初始化方法
public void init(){
length = 3; //初始身体长度
snakeX[0]=100; snakeY[0]=100; //头的坐标
snakeX[1]=75; snakeY[1]=100; //头的坐标
snakeX[2]=50; snakeY[2]=100; //头的坐标
direction = "right"; //头的方向
isStart = false; //初始游戏暂停
isFail = false;
score = 0;
//4.2食物的坐标,根据随机数生成
//带参的nextInt(int x)会生成一个范围在0~x(不包含X)内的任意正整数
random = new Random();
foodX = 25 + 25*random.nextInt(32);
foodY = 75 + 25*random.nextInt(24);
}
//绘制面板
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g); //清屏,用来展示添加的贪吃蛇
this.setBackground(Color.WHITE); //背景
//1.绘制静态面板
g.setFont(new Font("微软雅黑",Font.BOLD,20));
g.drawString("广告位招商进行中!!!", 350,40);
g.fillRect(25,75,850,600); //默认的游戏界面
//绘制分数面板
g.setColor(Color.green);
g.setFont(new Font("微软雅黑",Font.BOLD,18));
g.drawString("分数:"+score, 750,40);
//4.2绘制食物图标s
Data.food.paintIcon(this, g, foodX, foodY);
// //2.3绘制静态小蛇身体
// Data.body.paintIcon(this,g,snakeX[1],snakeY[1]);
// Data.body.paintIcon(this,g,snakeX[2],snakeY[2]);
//动态绘制身体,因为 body 是动态变化,所以通过 for 循环增加身体
for (int i=1; i<length; i++){
Data.body.paintIcon(this,g,snakeX[i],snakeY[i]);
}
//2.3绘制小蛇头
// Data.right.paintIcon(this,g,snakeX[0],snakeY[0]); //初始向右
//动态变换头的方向
if (direction.equals("right")){
Data.right.paintIcon(this,g,snakeX[0],snakeY[0]);
}else if (direction.equals("left")){
Data.left.paintIcon(this,g,snakeX[0],snakeY[0]);
}else if (direction.equals("up")){
Data.up.paintIcon(this,g,snakeX[0],snakeY[0]);
}else if (direction.equals("down")){
Data.down.paintIcon(this,g,snakeX[0],snakeY[0]);
}
//2.4游戏暂停提示
if (isStart==false){
g.setColor(Color.WHITE);
g.setFont(new Font("楷体 常规",Font.BOLD,40));
g.drawString("按下空格开始/暂停游戏",250,300);
}
//4.3游戏失败判断
if (isFail){
g.setColor(Color.red);
g.setFont(new Font("楷体 常规",Font.BOLD,40));
g.drawString("游戏失败,点击空格重新开始",250,300);
}
}
//3.1重写监听键盘按压事件
@Override
public void keyPressed(KeyEvent e) {
int keyCode = e.getKeyCode();
if (keyCode == KeyEvent.VK_SPACE){ //按下空格
if (isFail){ //4.3如果游戏结束时按下空格则从新开始,否则暂停
this.init();
}else {
isStart = !isStart; //不能写死(isStart = true),否则无法通过监听空格停止,所以取反
}
repaint(); //重新绘制面板
}
//3.1键盘的上下左右
if (keyCode == KeyEvent.VK_UP){
direction = "up";
}else if (keyCode == KeyEvent.VK_DOWN){
direction = "down";
}else if (keyCode == KeyEvent.VK_LEFT){
direction = "left";
}else if (keyCode == KeyEvent.VK_RIGHT){
direction = "right";
}
}
//4.1定时器事件监听(通过固定事件刷新,例:每秒刷新 N 次)
@Override
public void actionPerformed(ActionEvent e) {
//如果游戏是开始状态,就让小蛇动起来
//需要先判断游戏是否暂停,然后依次移动身体,由尾巴开始,每一个向前移动,然后再移动头的位置
//若先移动头的位置,则头的原本位置丢失,只记录了新的头的位置,则身体的第一节无法判断向何处移动
if (isStart && isFail==false){
//4.2吃食物,头的位置和食物位置重合,则身体长度 +1,并重新生成食物
for (int i = 0; i < length-1; i++) {
if (snakeX[i] == foodX && snakeY[i] == foodY){
length++;
score = (length-3)*5;
//食物的坐标,根据随机数生成
//带参的nextInt(int x)会生成一个范围在0~x(不包含X)内的任意正整数
foodX = 25 + 25 * random.nextInt(34);
foodY = 75 + 25 * random.nextInt(24);
}
}
//4.0移动
for (int i = length-1; i > 0 ; i--) { //身体等于前一节的值,即可完成向前移动身体
snakeX[i] = snakeX[i-1];
snakeY[i] = snakeY[i-1];
}
//4.1方向,判断键盘按键
if (direction.equals("right")){ //判断向右
snakeX[0] = snakeX[0]+25; //头的位置 +25 向右移动
if (snakeX[0] == 875) //穿越屏幕边界
snakeX[0] = 25;
}else
if (direction.equals("left")){ //判断向左
snakeX[0] = snakeX[0]-25; //头的位置 -25 向左
if (snakeX[0] == 0) //穿越屏幕边界
snakeX[0] = 850;
}else
if (direction.equals("up")){
snakeY[0] = snakeY[0]-25; //头的位置 Y 轴 -25向上
if (snakeY[0] == 50)
snakeY[0] = 650;
}else
if (direction.equals("down")){
snakeY[0] = snakeY[0]+25; //头的位置 Y 轴 +25向下
if (snakeY[0] == 675)
snakeY[0] = 75;
}
//4.3判断游戏失败,注释 for 循环即可成为无敌版
for (int i = 1; i < length; i++) {
if (snakeX[0]==snakeX[i] && snakeY[0]==snakeY[i]){
isFail = true;
}
}
repaint(); //重新绘制
}
timer.start(); //定时器启动
}
//以下是未使用到的键盘重构
@Override
public void keyReleased(KeyEvent e) { }
@Override
public void keyTyped(KeyEvent e) { }
}
总结
GUI编程
- 定义
- AWT
- 组件
- 容器
- 面板
- 事件监听
- 文本框监听
- 画图类paint(g)
- 鼠标监听器
- 窗口监听器
- 键盘监听器
- Swing
- 容器
- 面板(可带有滚动条)
- label
- 普通标签
- 图片标签
- 图像标签
- 按钮
- 普通按钮
- 图片按钮
- 单选框
- 多选框
- 列表
- 下拉框
- 列表框
- 文本框
- 普通文本框
- 密码框
- 文本域
- 贪吃蛇
- 定时器
- 面板绘制
- 键盘监听
- 事件监听