整體的思路和博主其他博文java實作貪吃蛇小游戲(原始碼+注釋)和java實作2048小游戲(原始碼+注釋)是一樣的,都是利用Frame創建表單,利用Panel添加組件,提前規劃好布局,呼叫滑鼠和鍵盤監聽,參考圖片元素,
此處的思路在于不斷的重繪敵機集合和子彈集合來實作動態效果,
文章目錄
- 一.工程檔案
- 二.Main.java
- 三.GameFrame.java
- 四.GamePanel.java
- 五.FlyObject.java
- 六.Hero.java
- 七.Ep.java
- 八.Fire.java
- 九.App.java
- 十.效果演示
一.工程檔案

二.Main.java
主函式,實作類
package ui;
//主函式實作
public class Main {
public static void main(String[] args) {
//創建表單
GameFrame frame = new GameFrame();
//創建面板
GamePanel panel = new GamePanel(frame);
//呼叫開始游戲的方法啟動游戲
panel.action();
//將面板加入到表單中
frame.add(panel);
//設定表單可見
frame.setVisible(true);
}
}
三.GameFrame.java
表單類,繪制表單
package ui;
import javax.swing.*;
//創建表單
public class GameFrame extends JFrame {
//構造方法,初始化表單屬性
public GameFrame(){
//設定標題,來源于JFrame
setTitle("飛機大戰");
//設定大小
setSize(512,768);
//設定居中
setLocationRelativeTo(null);
//設定表單可見
//setVisible(true);
//不允許玩家修改界面大小
setResizable(false);
//設定默認的關閉選項
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
四.GamePanel.java
畫布類,用于勾勒元素
package ui;
import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
//自定義游戲面板(創建畫布)
public class GamePanel extends JPanel {
//定義背景圖
BufferedImage bg;
//構造游戲機
Hero hero = new Hero();
//敵機集合
List<Ep> eps = new ArrayList<Ep>();
//彈藥集合
List<Fire> fs = new ArrayList<Fire>();
//定義分數
int score;
//設定游戲開關
Boolean gameover=false;
//設定火力
int power = 1;
//動作函式,描繪場景內飛行物的運動狀態
public void action(){
//創建執行緒(基本模板)
new Thread(){
public void run(){
//無線回圈創建
while (true){
//判斷如果游戲沒有失敗,則執行以下操作
if(!gameover){
//敵機進場
epEnter();
//呼叫敵機移動方法
epMove();
//發射子彈
shoot();
//子彈移動
fireMove();
//判斷子彈是否擊中敵機
shootEp();
//檢測敵機是否撞到游戲機
hit();
}
//每執行一次,執行緒休眠一會兒
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
//重繪界面
repaint();
}
}
}.start();//讓執行緒開始運行
}
//每執行20次,釋放一個敵機,創建計數器計數
int index = 0;
protected void epEnter(){
index++;
//創建敵機
if(index>=20){
//創建敵機
Ep e = new Ep();
//加入集合
eps.add(e);
//重置計數器
index = 0;
}
}
//讓敵機移動
protected void epMove(){
//遍歷敵機集合,依次移動
for (int i = 0; i < eps.size(); i++) {
//獲取集合中敵機
Ep e = eps.get(i);
//呼叫敵機類中的移動方法
e.move();
}
}
//每執行20次,創建一顆子彈,創建計數器計數
int findex = 0;
protected void shoot(){
findex++;
if(findex>=20){
//根據火力判斷子彈行數
//一排子彈
if(power==1){
//創建子彈
Fire fire1 = new Fire(hero.x+45,hero.y,1);
//將子彈存入子彈集合中
fs.add(fire1);
}
//兩排子彈
else if(power==2){
//創建子彈
Fire fire1 = new Fire(hero.x+15,hero.y,0);
//將子彈存入子彈集合中
fs.add(fire1);
//創建子彈
Fire fire2 = new Fire(hero.x+75,hero.y,2);
//將子彈存入子彈集合中
fs.add(fire2);
}
//三排子彈
else{
//創建子彈
Fire fire1 = new Fire(hero.x+15,hero.y,0);
//將子彈存入子彈集合中
fs.add(fire1);
//創建子彈
Fire fire2 = new Fire(hero.x+75,hero.y,2);
//將子彈存入子彈集合中
fs.add(fire2);
//創建子彈
Fire fire3 = new Fire(hero.x+45,hero.y-10,1);
//將子彈存入子彈集合中
fs.add(fire3);
}
//使計數器歸0
findex = 0;
}
}
//讓子彈移動
protected void fireMove(){
//遍歷子彈集合
for (int i = 0; i < fs.size(); i++) {
//獲取每一顆子彈位置
Fire f = fs.get(i);
//依次移動每一顆子彈
f.move();
}
}
//判斷子彈是否擊中敵機
protected void shootEp(){
//遍歷所有子彈
for (int i = 0; i < fs.size(); i++) {
//獲取每一顆子彈
Fire f = fs.get(i);
//判斷一顆子彈是否擊中敵機
bang(f);
}
}
//判斷一顆子彈是否擊中敵機
protected void bang(Fire f){
for (int i = 0; i < eps.size(); i++) {
//取出每一張敵機
Ep e = eps.get(i);
//判斷這個子彈是否擊中敵機
if(e.shootBy(f)&&e.type!=15){
//判斷游戲機機是否擊中道具機
if(e.type==12){
//火力增加
power++;
//如果火力值大于三,增加血量
if(power>3){
//恢復血量
if(hero.hp<3){
hero.hp++;
}
//使游戲機血量不超過3
power = 3;
}
}
//如果敵機被子彈擊中
//敵機消失
eps.remove(e);
//洗掉子彈
fs.remove(f);
//增加分數
score += 10;
}
}
}
//檢測敵機是否撞到主機
protected void hit() {
for (int i = 0; i < eps.size(); i++) {
//獲取每一個敵機
Ep e = eps.get(i);
//呼叫敵機的方法判斷
if(e.shootBy(hero)){
//洗掉敵機
eps.remove(e);
//主機血量減少
hero.hp--;
//火力恢復初始值
power = 1;
//分數增加
score += 10;
//當主機血量減少到0時游戲結束
if(hero.hp==0){
gameover = true;
}
}
}
}
//建構式
public GamePanel(GameFrame frame){
//設定背景
bg = App.getImg("/img/bg2.jpg");
//創建滑鼠監聽和滑鼠配接器
MouseAdapter adapter = new MouseAdapter() {
//點擊滑鼠時會執行的代碼
@Override
public void mouseClicked(MouseEvent e) {
//游戲結束時候,點擊螢屏時重新開始游戲
if(gameover){
//重新初始化主機
hero = new Hero();
//重置游戲開關
gameover = false;
//分數清0
score = 0;
//清空敵機集合
eps.clear();
//隨機背景圖
Random random = new Random();
int index = random.nextInt(5)+1;
bg = App.getImg("/img/bg"+index+".jpg");
//重新繪制
repaint();
}
}
//確定需要監聽的事件,此處監聽滑鼠移動事件
@Override
public void mouseMoved(MouseEvent e) {
//讓游戲機的橫縱坐標等于滑鼠的移動坐標
//獲取滑鼠的橫縱坐標
int mx = e.getX();
int my = e.getY();
//傳遞坐標
if(!gameover){
//使滑鼠坐標正好位于圖片中央
hero.moveToMouse(mx-114/2,my-93/2);
}
//重新繪制界面
repaint();
}
};
//將配接器加入到監聽器中
addMouseListener(adapter);
addMouseMotionListener(adapter);
//使用鍵盤監聽,創建鍵盤配接器
KeyListener kd = new KeyListener() {
@Override
public void keyTyped(KeyEvent e) {
}
//當鍵盤被按下是觸發
@Override
public void keyPressed(KeyEvent e) {
int keyCode = e.getKeyCode();
//上鍵
if(keyCode == KeyEvent.VK_UP){
hero.y-=10;
}
//下鍵
else if(keyCode == KeyEvent.VK_DOWN){
hero.y+=10;
}
//左鍵
else if(keyCode == KeyEvent.VK_LEFT){
hero.x-=10;
}
//右鍵
else if(keyCode == KeyEvent.VK_RIGHT){
hero.x+=10;
}
repaint();
}
@Override
public void keyReleased(KeyEvent e) {
}
};
//將配接器加入表單的監聽器中
frame.addKeyListener(kd);
}
//畫圖方法
@Override
public void paint(Graphics g) {
//呼叫父類中的一些渲染方法
super.paint(g);
//畫背景
g.drawImage(bg,0,0,null);
//畫敵機
for (int i = 0; i < eps.size(); i++) {
Ep ep = eps.get(i);
g.drawImage(ep.img,ep.x,ep.y,null);
}
//畫子彈
for (int i = 0; i < fs.size(); i++) {
Fire fire = fs.get(i);
g.drawImage(fire.img,fire.x,fire.y,fire.w,fire.h,null);
}
//畫分數
g.setColor(Color.white);
//設定字體型號,設定加粗,設定字體大小
g.setFont(new Font("\u6977\u4F53",Font.BOLD,30));
//顯示分數
g.drawString("分數:"+score,10,30);
//畫游戲機
g.drawImage(hero.img,hero.x,hero.y,null);
//畫游戲機血量
for (int i = 0; i < hero.hp; i++) {
g.drawImage(hero.img,380+i*35,5,30,30,null);
}
//畫游戲結束
if(gameover){
//設定字體顏色為紅色
g.setColor(Color.red);
//設定字體型號,設定加粗,設定字體大小
g.setFont(new Font("楷體",Font.BOLD,35));
//顯示字體
g.drawString("GAMEOVER",170,300);
//設定字體顏色為綠色
g.setColor(Color.green);
//設定字體型號,設定加粗,設定字體大小
g.setFont(new Font("楷體",Font.BOLD,29));
//顯示字體
g.drawString("yh提醒你點擊螢屏任意位置重新開始",10,350);
}
//重新繪制界面
repaint();
}
}
五.FlyObject.java
飛行物類,設定飛行物特性
package ui;
import java.awt.image.BufferedImage;
//飛行物具有共同特點,故抽離成父類
public class FlyObject {
//均采用照片素材
BufferedImage img;
//位置的橫坐標
int x;
//位置的縱坐標
int y;
//圖片元素的寬度
int w;
//圖片元素的高度
int h;
}
六.Hero.java
主機類,設定游戲時候操控的飛機屬性
package ui;
import java.awt.image.BufferedImage;
//游戲機
public class Hero extends FlyObject{
//設定游戲機血量
int hp;
//建構式
public Hero(){
//獲取游戲機元素
img = App.getImg("/img/hero.png");
//確認初始位置
x = 200;
y = 500;
//獲取游戲機圖片元素的寬和高
w = img.getWidth();
h = img.getHeight();
//設定初始血量為3
hp = 3;
}
//根據傳入引數移動相應位置
public void moveToMouse(int mx,int my){
x = mx;
y = my;
}
}
七.Ep.java
敵機類
package ui;
import javax.swing.*;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
//敵機類
public class Ep extends FlyObject{
//設定敵機速度
int sp;
//設定敵機型別,不同的敵機型別有不同的屬性
int type;
//建構式
public Ep(){
//引入亂數隨機呼叫敵機
Random random = new Random();
//呼叫[1,15]范圍內的敵機
int index = random.nextInt(15)+1;
//保存敵機型別
type = index;
//如果序號小于10,則補充前導0,實質符合圖片命名規律
String path = "/img/ep" + (index<10?"0":"")+index+".png";
//根據路徑呼叫方法類函式獲取圖片io流
img = App.getImg(path);
//確定敵機位置
//獲取敵機照片元素寬度引數
w = img.getWidth();
//邊界長減去照片寬度,防止照片越界
x = random.nextInt(512-w);
y = 0;
//設定速度
sp = 17-index;
}
//設定敵機移動方法
public void move() {
//如果敵機型別為5,則向左方傾斜移動
if(type==5){
x -= 5;
y += sp;
}
//如果敵機型別為5,則向右方傾斜移動
else if(type==6){
x += 5;
y += sp;
}
//如果是其他型別,則正常向下移動
else {
y+=sp;
}
}
//判斷敵機是否被子彈擊中
public boolean shootBy(Fire f) {
//獲取圖片元素屬性,確定相應的坐標演算法,判斷是否滿足條件,滿足則被擊中
Boolean hit = x <= f.x+f.w &&x>f.x-w&&y<=f.y+f.h&&y>f.y-h;
return hit;
}
//判斷敵機是否被玩家機擊中
public boolean shootBy(Hero f) {
//獲取圖片元素屬性,確定相應的坐標演算法,判斷是否滿足條件,滿足則被擊中
Boolean hit = x <= f.x+f.w &&x>f.x-w&&y<=f.y+f.h&&y>f.y-h;
return hit;
}
}
八.Fire.java
子彈類
package ui;
public class Fire extends FlyObject{
//子彈當前移動方向,0為左上角飛,1垂直飛,2右上角飛
int dir;
//構造方法,初始化子彈
public Fire(int hx,int hy,int dir){
//獲取子彈的圖片
img = App.getImg("/img/fire.png");
//確定圖片的大小,此處把子彈大小縮小了4倍
w = img.getWidth()/4;
h = img.getHeight()/4;
//根據建構式傳進來的引數設定子彈的位置以及子彈的方向
x = hx;
y = hy;
this.dir=dir;
}
//子彈的移動方法
public void move() {
//左上角飛
if(dir==0){
x -= 1;
y -= 10;
}
//垂直上飛
else if(dir == 1){
y -= 10;
}
//右上角飛
else if(dir == 2){
x += 1;
y -= 10;
}
}
}
九.App.java
方法類
package ui;
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.InputStream;
//處理圖片的工具類
//此處我定義了兩種獲取圖片的方法,可以對照參考
public class App {
//static可以公用所有物件都共用該方法,并且可以不依賴物件實作
public static BufferedImage getImg(String path){
//用try方法捕獲例外
try {
//io流,輸送資料的管道
BufferedImage img = ImageIO.read(App.class.getResource(path));
return img;
}
//例外處理,列印例外
catch (IOException e) {
e.printStackTrace();
}
//沒找到則回傳空
return null;
}
//此處與貪吃蛇小游戲的呼叫方法是一樣的
public static ImageIcon getImg2(String path){
InputStream is;
//從主類檔案所在的路徑尋找相應路徑的圖片
is = App.class.getClassLoader().getResourceAsStream(path);
//用try方法捕獲例外
try {
return new ImageIcon(ImageIO.read(is));
}
//例外處理,列印例外
catch (IOException e) {
e.printStackTrace();
}
//沒找到則回傳空
return null;
}
}
十.效果演示



轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/280285.html
標籤:其他
上一篇:簡單三子棋 游戲 (C語言實作)
