上午没事刷到网上最近炒热了一些简单的小游戏和爱心代码,单身8个月了,对爱心代码不是很感冒,所以想蹭个热度,写一个飞机大站来玩玩。
首先,分析小游戏需要那些技术与怎么设计:
窗体,因为是java小游戏,那么就需要用到java的swing或者是Fx包里的相关图形化方法。
多线程,因为不可能是只有我们的飞机在飞,敌方也有飞机,子弹也需要飞行。
图片读取:需要将图片放入窗体中,所以需要借助画布,但是前提是我们需要将图片解析出来。
实体设计:越成熟的游戏设计的敌方飞机与我方飞机的功能与属性越多,这都需要基于实体实现。
那么基于以上几个点,我们首先就是建立一个可视化的窗体出来:
借助所谓的JFrame窗体类实现(也可继承来实现):
public static void main(String[] args) throws IOException {
JFrame frame = new JFrame();
GamePanel gamePanel = new GamePanel();
frame.add(gamePanel);
frame.setSize(576, 840);
frame.setTitle("战机");
frame.setLocationRelativeTo(null);
frame.setVisible(true);
frame.setDefaultCloseOperation(3);
gamePanel.move();
frame.addMouseListener(gamePanel);
frame.addMouseMotionListener(gamePanel);
}
因为是一个窗体,所以我们需要借助画布对象来给窗体内部添加一些元素。也需要借助鼠标监听的相关接口对鼠标事件进行业务重写。
这里我们直接挂出来(相关代码的释疑都在注释里):
画布类:
package com.hlc.Game;
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.io.File;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
import static java.awt.Font.BOLD;
public class GamePanel extends JPanel implements MouseListener, MouseMotionListener {
Image backGround, boss, zu, me,mePlus, ziDan, destroy, startGame;//图片资源
int state;//控制游戏状态开关 变量 0未开始,1开始,2暂停,3退出
int mark = 0, count = 0;//分数与计数器
int mouseX = 180, mouseY = 500, blood = 100;//我方战斗机坐标X,Y与战斗机血量。
boolean boom = false;//爆炸开关 显示爆炸图片的控制开关
int badAirX, badAirY;//存储爆炸敌方飞机坐标便于画出爆炸图片
List badAirs = new LinkedList<>();//存储敌机对象
List ziDans = new LinkedList<>();//存储子弹对象
public GamePanel() throws IOException {
state = 0;
mark = 0;
backGround = ImageIO.read(new File("D:\\java项目\\Game\\Image\\back.png"));
boss = ImageIO.read(new File("D:\\java项目\\Game\\Image\\boss.png"));
startGame = ImageIO.read(new File("D:\\java项目\\Game\\Image\\start.png"));
me = ImageIO.read(new File("D:\\java项目\\Game\\Image\\mePlus.png"));
mePlus = ImageIO.read(new File("D:\\java项目\\Game\\Image\\me.png"));
zu = ImageIO.read(new File("D:\\java项目\\Game\\Image\\zu.png"));
ziDan = ImageIO.read(new File("D:\\java项目\\Game\\Image\\ziDan.png"));
destroy = ImageIO.read(new File("D:\\java项目\\Game\\Image\\destroy.png"));
}
@Override
public void paint(Graphics g) {
super.paint(g);
g.setFont(new Font("仿宋", BOLD, 20));
g.setColor(Color.YELLOW);
/*初始游戏状态*/
if (state == 0) {
g.drawImage(backGround, 0, 0, null);
g.drawString("分数:" + mark + "", 0, 20);
g.drawImage(boss, 204, 0, null);
g.drawImage(startGame, 258, 300, null);
g.drawString("开始游戏", 248, 400);
g.drawImage(mePlus, 237, 500, null);
}
/*开始游戏状态*/
else if (state == 1) {
g.drawImage(backGround, 0, 0, null);
g.drawString("分数:" + mark + "", 0, 20);
if(mark > 50){
g.drawImage(mePlus,mouseX-51,mouseY-63,null);
}
else
g.drawImage(me,mouseX-23,mouseY-28,null);
if (boom) {
g.drawImage(destroy, badAirX, badAirY, null);
boom = false;
}
for (int i = 0; i < ziDans.size(); i++) {
ziDans.get(i).drawZiDan(g);
}
for (int i = 0; i < badAirs.size(); i++) {
badAirs.get(i).drawPanel(g);
}
}
/*暂停游戏状态*/
else if (state == 2) {
g.drawImage(backGround, 0, 0, null);
g.drawString("分数:" + mark + "", 0, 20);
g.drawImage(boss, 156, 0, null);
g.drawImage(startGame, 210, 300, null);
g.drawString("开始游戏", 200, 400);
g.drawImage(me, 189, 500, null);
}
/*退出游戏状态(数据清空,等待重新开始游戏)*/
else {
state = 0;
repaint();
}
}
public void move() {
new Thread() {
@Override
public void run() {
super.run();
while (true) {
if (state == 1) {
count++;//计数器自增开始
if (count % 3 == 0) {
ziDans.add(new ZiDan(mouseX,mouseY,ziDan));//创建新子弹
}
for (int i = 0;i700){
state = 3;
mark = 0;
blood = 100;
}
}
GameJudgeDead judgeDead = new GameJudgeDead();//初始化判断碰撞对象
for (int i = 0;i
这里需要注意几个问题,之前用webp格式的图片下载之后强行改后缀为png之后再内部怎么写都不能加载出来图片显示,这是一个问题,因为浏览器对图片进行了压缩解码,所以一定要下载原图!!!
接下来我们挂出来碰撞判断类:
public class GameJudgeDead {
public boolean judgeBoomZiDan(ZiDan ziDan, BadAir badAir) {
return badAir.getX() < ziDan.getX() && badAir.getY() + badAir.height > ziDan.getY() && badAir.getX() + badAir.width > ziDan.getX();
}
public boolean judgeBoomAir(BadAir badAir, int mouseX, int mouseY) {
mouseX = mouseX - 51;
mouseY = mouseY - 63;
return badAir.getX() < mouseX && badAir.getY() + badAir.height > mouseY && badAir.getX() + badAir.width > mouseY;
}
}
这里面你需要计算碰撞的条件,以及里面的坐标代表的意思,尤其是你切换图片之后对应的尺寸会变化,所以最好用实体。
敌机实体:
public class BadAir {
int X;
int Y;
Image badAir;
int height;
int width;
public BadAir( Image badAir) {
X =(int) (Math.random()*480);
Y = -30;
this.badAir = badAir;
height = badAir.getHeight(null);
width = badAir.getWidth(null);
}
void drawPanel(Graphics g){
g.drawImage(badAir,X-27,Y-20,null);
}
public int getX() {
return X;
}
public void setX(int x) {
X = x;
}
public int getY() {
return Y;
}
public void setY(int y) {
Y = y;
}
}
注意这里将图片的尺寸写入到实体属性中去了,方便后续因为图片的切换来。
子弹实体类
public class ZiDan {
int x,y;
Image ZiDan;
public ZiDan(int mouseX,int mouseY,Image ZiDan){
this.x = mouseX;
this.y = mouseY;
this.ZiDan = ZiDan;
}
public void drawZiDan(Graphics g){
g.drawImage(ZiDan,x,y,null);
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
}
这里没有给敌机添加子弹。