🌈博客主页:屠一乐的博客
📅 发文时间:2022.3.26
🎈 一定存在只有你才能做成的事
🌹 博主水平有限,如有错误,欢迎指正
欢迎给位👍收藏💎评论✉
📒📒简述
此小项目是实现一个弹球小游戏,通过球拍接球反弹,保证球不落地,落地则游戏结束。
🎏🎏所需技术
主要运用awt和一点点swing。
学完awt就可用来练练手,巩固所学知识(真的非常简单啦🤣🤣)
🎰🎰实现原理
如何让小球和球拍运动起来尼
其实动画是由一张张连续的静止图画通过快速切换在人眼视觉暂留效果实现
基于人眼的视觉暂留效果。 动画是采用逐帧拍摄对象并连续播放而形成运动的影像技术。 不论拍摄对象是什么,只要它的拍摄方式是采用的逐格方式,观看时连续播放形成了活动影像,它就是动画。
而在awt中我们可以利用repaint方法不断重绘让小球动起来
💻💻代码实现
1.基本信息
首先是确定各种参数
//桌面的宽和高度
private final int TABLE_WIDTH = 300;
private final int TABLE_HEIGHT = 400;
//球拍和球尺寸
private final int RACKET_WIDTH = 60;
private final int RACKET_HEIGHT = 20;
private final int BALL_SIZE = 16;
//球位置信息和速度
private int ballX = 120;
private int ballY = 60;
private int speedY = 10;
private int speedX = 5;
//拍位置
private int racketX = 120;
private final int racketY = 340;
//标记是否结束
private boolean isOver = false;
//用来计数
2.绘制球和拍
画小球前先判断游戏是否结束,未结束才画小球
//画笔
private class MyCanvas extends Canvas {
@Override
public void paint(Graphics g) {
if (isOver) {//游戏结束时行为
g.setColor(Color.blue);
g.setFont(new Font("Times", Font.BOLD, 30));
g.drawString("游戏结束", 50, 200);
} else {//游戏中行为
g.setColor(Color.red);//球
g.fillOval(ballX, ballY, BALL_SIZE, BALL_SIZE);
g.setColor(Color.black);//拍
g.fillRect(racketX, racketY, RACKET_WIDTH, RACKET_HEIGHT);
}
}
}
3.监听器及小球具体变化
让球拍能根据键盘左右键移动起来就需要设置一个监听器监听键盘情况并采取行动让球拍重绘,也就是移动起来
public void init() {
KeyListener listener = new KeyAdapter() {
@Override//判断键盘行为做出反应
public void keyPressed(KeyEvent e) {
int keyCode = e.getKeyCode();
if (keyCode == KeyEvent.VK_LEFT) {
if (racketX > 0) {
racketX -= 15;
}
} else if (keyCode == KeyEvent.VK_RIGHT) {
if (racketX < TABLE_WIDTH - RACKET_WIDTH) {
racketX += 15;
}
}
}
};
frame.addKeyListener(listener);
drawArea.addKeyListener(listener);
//监听器,作为时间源
ActionListener task = new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
//球位置变化
if (ballX <= 0 || ballX > TABLE_WIDTH - BALL_SIZE) {
speedX = -speedX;
}
if (ballY <= 0 || (ballY >= racketY - BALL_SIZE && ballX > racketX && ballX < racketX + RACKET_WIDTH)) {
speedY = -speedY;
}
//游戏结束的情况
if (ballY > racketY - BALL_SIZE && (ballX < racketX || ballX > racketX + RACKET_WIDTH)) {
timer.stop();
isOver = true;
drawArea.repaint();
}
ballX += speedX;
ballY += speedY;
drawArea.repaint();
}
};
这里要注意小球运动方向的变化,当水平方向碰到墙壁时,水平速度相反竖直速度不变;当竖直方向碰到墙壁则Y方向上速度speedY相反;
并且,当没接到球时游戏结束,也就是ballY > racketY - BALL_SIZE && (ballX < racketX || ballX > racketX + RACKET_WIDTH)这种情况
4.计数器
多久重绘一次,这里就需要用到timer计数器来计数了
//定时器:每隔多久来执行指定代码
Timer timer = new Timer(100, task);
timer.start();
5.组装所有代码
将所有代码组装起来也就是
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class PinBall {
private Frame frame = new Frame("弹球游戏");
//桌面的宽和高度
private final int TABLE_WIDTH = 300;
private final int TABLE_HEIGHT = 400;
//球拍和球尺寸
private final int RACKET_WIDTH = 60;
private final int RACKET_HEIGHT = 20;
private final int BALL_SIZE = 16;
//球位置信息和速度
private int ballX = 120;
private int ballY = 60;
private int speedY = 10;
private int speedX = 5;
//拍位置
private int racketX = 120;
private final int racketY = 340;
//标记是否结束
private boolean isOver = false;
//用来计数
private Timer timer;
//画笔
private class MyCanvas extends Canvas {
@Override
public void paint(Graphics g) {
if (isOver) {//游戏结束时行为
g.setColor(Color.blue);
g.setFont(new Font("Times", Font.BOLD, 30));
g.drawString("游戏结束", 50, 200);
} else {//游戏中行为
g.setColor(Color.red);//球
g.fillOval(ballX, ballY, BALL_SIZE, BALL_SIZE);
g.setColor(Color.black);//拍
g.fillRect(racketX, racketY, RACKET_WIDTH, RACKET_HEIGHT);
}
}
}
MyCanvas drawArea = new MyCanvas();//相当于画布
public void init() {
KeyListener listener = new KeyAdapter() {
@Override//判断键盘行为做出反应
public void keyPressed(KeyEvent e) {
int keyCode = e.getKeyCode();
if (keyCode == KeyEvent.VK_LEFT) {
if (racketX > 0) {
racketX -= 15;
}
} else if (keyCode == KeyEvent.VK_RIGHT) {
if (racketX < TABLE_WIDTH - RACKET_WIDTH) {
racketX += 15;
}
}
}
};
frame.addKeyListener(listener);
drawArea.addKeyListener(listener);
//监听器,作为时间源
ActionListener task = new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
//球位置变化
if (ballX <= 0 || ballX > TABLE_WIDTH - BALL_SIZE) {
speedX = -speedX;
}
if (ballY <= 0 || (ballY >= racketY - BALL_SIZE && ballX > racketX && ballX < racketX + RACKET_WIDTH)) {
speedY = -speedY;
}
//游戏结束的情况
if (ballY > racketY - BALL_SIZE && (ballX < racketX || ballX > racketX + RACKET_WIDTH)) {
timer.stop();
isOver = true;
drawArea.repaint();
}
ballX += speedX;
ballY += speedY;
drawArea.repaint();
}
};
//定时器:每隔多久来执行指定代码
Timer timer = new Timer(100, task);
timer.start();
drawArea.setPreferredSize(new Dimension(TABLE_WIDTH, TABLE_HEIGHT));
frame.add(drawArea);//画布尺寸,并放入
frame.addWindowStateListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
new PinBall().init();
}
}
6.完善、优化代码
测试完看项目能否正常运行,之后就是优化代码了,timer中的delay就是多久重绘一次,数值越小球看到的情况就是越快
当然,在球生成时还可以设置成随机生成等等。。。
大家可以试试完善一下
🎃🎃 总结
这个弹球小游戏还是挺简单的,刚学awt的可以试试哈
awt 内容还挺多的,但不能死记,代码得多写,记住框架之后多练
一起加油吧!