萧大佬JS游戏视频:https://www.bilibili.com/video/av12168808
这一次代码大变样,绕的我脑子都晕了,许多地方真的是写的太垃圾。
添加功能如下:
1.手动关卡编辑
2.把定时器新建了一个类
3.新增加了砖块和砖块的HP
4.加了双缓冲(不知道有没有用)
5.P键暂停(挡板移动的BUG还没有搞)
准备添加新功能:
1.不同生命值的方块颜色不同。
2.添加积分功能。
3.打完所有砖块,进入下一关。
4.可能会把draw的方块换成图片。
可以看到方块是有生命值的,但是还有个BUG没演示。
球会卡在挡板里,就这样了。装作什么都没发生
项目截图如下:
1.Ball类
新添加了rebound反弹函数
网上抄了一个矩形相交的代码
public class Ball {
/**
* @param BALL_WIDTH 球宽度
* @param BALL_HEIGHT 球高度
*/
private static final int BALL_WIDTH = 25;
private static final int BALL_HEIGHT = 25;
private int x = 175;
private int y = 200;
private int speedX = 5;
private int speedY = 5;
private boolean fired = false;
public void draw(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
//抗锯齿
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.drawOval(x, y, BALL_WIDTH, BALL_HEIGHT);
}
public void fire() {
fired = true;
}
public void move() {
if (fired) {
// 边界判定
if (x <= 0 || x + BALL_WIDTH >= 400)
speedX *= -1;
if (y <= 0 || y + BALL_HEIGHT >= 400)
speedY *= -1;
x += speedX;
y += speedY;
}
}
public void rebound(){
speedY *= -1;
}
public boolean collide(int x, int y, int width, int height) {
boolean code = false;
// 矩形相交
if (this.x + BALL_WIDTH > x && x + width > this.x && this.y + BALL_HEIGHT > y && y + height > this.y) {
code = true;
}
return code;
}
}
2.Block类
最为主要的就是存活状态和生命值
public class Block {
/**
* @param BALL_WIDTH 球宽度
* @param BALL_HEIGHT 球高度
*/
public static final int BLOCK_WIDTH = 75;
public static final int BLOCK_HEIGHT = 25;
/**
* @param alive 存活状态
* @param hp 生命 默认1
*/
private int x = 100;
private int y = 100;
private int hp = 2;
private boolean alive = true;
public void draw(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
g2.drawRect(x, y, BLOCK_WIDTH, BLOCK_HEIGHT);
}
public void kill() {
if (hp > 0) {
hp--;
if (hp == 0)
alive = false;
}
}
public int getHp() {
return hp;
}
public void setHp(int hp) {
this.hp = hp;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public void setY(int y) {
this.y = y;
}
public int getY() {
return y;
}
public boolean getBlockAlive() {
return alive;
}
}
3.Paddle类
这个挡板类好像没怎么动过。
package com.draw;
import java.awt.*;
/**
* Created by Administrator on 2018/4/25 0025.
*/
public class Paddle {
/**
* @param PADDLE_WIDTH 挡板宽度
* @param PADDLE_HEIGHT 挡板高度
*/
public static final int PADDLE_WIDTH = 125;
public static final int PADDLE_HEIGHT = 25;
private int x = 150;
private int y = 300;
private int speed = 15;
//绘图
public void draw(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
g2.drawRect(x, y, PADDLE_WIDTH, PADDLE_HEIGHT);
}
public void moveLeft(){
if(x > 0)
x -= speed;
}
public void moveRight(){
if(x < 400-PADDLE_WIDTH)
x += speed;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
}
4.StringUtil类
新添加的类,用于读取levels.properties文件返回 ArrayList<int[]>类型
public class StringUtil {
public ArrayList<int[]> readToList(String key,String fileName) {
Properties properties = new Properties();
ArrayList<int[]> arrayList = new ArrayList<>();
try {
InputStream in = new BufferedInputStream(new FileInputStream(fileName));
properties.load(in);
String value = properties.getProperty(key);
for (String s : value.split("\\|")) {
String[] s1 = s.split(",");
int[] array = new int[s1.length];
for (int i = 0; i < s1.length; i++) {
array[i] = Integer.valueOf(s1[i]);
}
arrayList.add(array);
}
} catch (IOException e) {
e.printStackTrace();
}
return arrayList;
}
}
5.levels.properties文件
用于存储关卡信息。如0,0,1。s = [0,0,1].
s[0] = X位置
s[1] = Y位置
s[2] = 方块生命值
1=0,0,1
2=0,0,1|30,30,2
3=0,0,1|30,30,2|60,60,3
4=0,0,1|30,30,3|60,60,3|90,90,4
6.RepaintTask类
这个类写的不好,太乱了。用于移动和碰撞的刷新。
public class RepaintTask extends TimerTask {
private Paddle paddle = new Paddle();
private Ball ball = new Ball();
private ArrayList<Block> blocks = new ArrayList<>();
private MyComponent component = null;
private boolean isTrue = true;
public RepaintTask(Ball ball, Paddle paddle, ArrayList<Block> blocks, MyComponent component) {
this.ball = ball;
this.paddle = paddle;
this.blocks = blocks;
this.component = component;
}
@Override
public void run() {
if (isTrue) {
// 重绘
component.repaint();
// 球移动
ball.move();
// 板子与球相撞
if (ball.collide(paddle.getX(), paddle.getY(), paddle.PADDLE_WIDTH, paddle.PADDLE_HEIGHT)) {
ball.rebound();
}
for (Block block : blocks) {
//是否存活
if (block.getBlockAlive()) {
// 球与方块相撞
if (ball.collide(block.getX(), block.getY(), block.BLOCK_WIDTH, block.BLOCK_HEIGHT)) {
block.kill();
ball.rebound();
}
}
//如果全部挂掉,就开始下一关
//nextLevel();
}
}
}
public boolean getIsTrue() {
return isTrue;
}
public void setTrue(boolean aTrue) {
isTrue = aTrue;
}
}
7.MyComponent类
主要功能双缓冲和调用Draw方法的绘图。
class MyComponent extends JComponent {
//初始化
private Ball ball = null;
private Paddle paddle = null;
private ArrayList<Block> blocks;
private Image ImageBuffer = null;
private Graphics GraImage = null;
// 获取对象
public MyComponent(Ball ball, Paddle paddle, ArrayList<Block> blocks) {
this.ball = ball;
this.paddle = paddle;
this.blocks = blocks;
}
@Override
public void update(Graphics g) {
super.update(g);
//创建图形缓冲区
ImageBuffer = createImage(this.getWidth(), this.getHeight());
//获取图形缓冲区的图形上下文
GraImage = ImageBuffer.getGraphics();
//用paint方法中编写的绘图过程对图形缓冲区绘图
paint(GraImage);
//释放图形上下文资源
GraImage.dispose();
g.drawImage(ImageBuffer, 0, 0, this);
}
@Override
public void paint(Graphics g) {
super.paint(g);
ball.draw(g);
paddle.draw(g);
for (Block block : blocks) {
if (block.getBlockAlive())
block.draw(g);
}
}
}
8.ListenerFrame类
主要功能:调用各种方法和键盘监听,载入配置。读取关卡信息。
class ListenerFrame extends JFrame implements KeyListener {
/**
* @param DEFAULT_WIDTH 组件宽
* @param DEFAULT_HEIGHT 组件高度
*/
private static final int DEFAULT_WIDTH = 400;
private static final int DEFAULT_HEIGHT = 400;
private Paddle paddle = new Paddle();
private Ball ball = new Ball();
private String level = "4";
private ArrayList<Block> blocks = loadLevel(level);
private MyComponent component = new MyComponent(ball, paddle, blocks);
private RepaintTask task = new RepaintTask(ball, paddle, blocks, component);
public ListenerFrame() {
//定时器 定时重绘组件
Timer t = new Timer();
t.schedule(task, 0, 1000/100);
//配置
setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);
add(component);
}
public ArrayList<Block> loadLevel(String level) {
ArrayList<Block> blocks = new ArrayList<>();
StringUtil stringUtil = new StringUtil();
ArrayList<int[]> arrayList = stringUtil.readToList(level, "src/com/levels.properties");
for (int[] k : arrayList) {
Block block = new Block();
block.setX(k[0]);
block.setY(k[1]);
block.setHp(k[2]);
blocks.add(block);
}
return blocks;
}
//键盘监听
@Override
public void keyPressed(KeyEvent e) {
switch (e.getKeyCode()) {
case KeyEvent.VK_LEFT:
paddle.moveLeft();
break;
case KeyEvent.VK_RIGHT:
paddle.moveRight();
break;
case KeyEvent.VK_A:
paddle.moveLeft();
break;
case KeyEvent.VK_D:
paddle.moveRight();
break;
case KeyEvent.VK_F:
ball.fire();
break;
case KeyEvent.VK_P:
if(task.getIsTrue())
task.setTrue(false);
else
task.setTrue(true);
break;
}
}
@Override
public void keyReleased(KeyEvent e) {
}
@Override
public void keyTyped(KeyEvent e) {
}
}
9.Main
没有动作,还是配置各类东西。
public class Main {
public static void main(String[] args) {
// 事件分配线程写法来自Java Core 1(408页)
// 没有记错的话这个是Java 8里的lambda表达式
EventQueue.invokeLater(() -> {
//创建对象
ListenerFrame frame = new ListenerFrame();
//添加关闭按钮
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//添加Title
frame.setTitle("打砖块");
//添加键盘监听事件
frame.addKeyListener(frame);
//设置可见
frame.setVisible(true);
});
}
}
``
网友评论