Java坦克大戰(四)

来源:https://www.cnblogs.com/1693977889zz/archive/2018/02/13/8445905.html
-Advertisement-
Play Games

這是我的坦克游戲大戰的最後一版,裡面添加很多新的功能。這個坦克大戰的有很多不足之處,但是對於初學者來說依然是一個很好的練習項目,從中我們可以學習Java基礎知識,將知識與項目結合,學習面向對象編程思想,最主要的是編程的邏輯練習,代碼往往不像是寫文章從上到下一氣呵成完成,中間很可能為增加一個功能來添加 ...


這是我的坦克游戲大戰的最後一版,裡面添加很多新的功能。這個坦克大戰的有很多不足之處,但是對於初學者來說依然是一個很好的練習項目,從中我們可以學習Java基礎知識,將知識與項目結合,學習面向對象編程思想,最主要的是編程的邏輯練習,代碼往往不像是寫文章從上到下一氣呵成完成,中間很可能為增加一個功能來添加一個類一個方法等,中間有很多細節需要我們考慮。文章最後會附加該坦克大戰涉及的相關素材。

功能:

1.防止坦克重疊

2.可以分關(閃爍效果)

3.記錄成績(小型游戲都是寫在文件中)

4.存檔退出,可以記錄但是敵人坦克的坐標

5.可以恢覆上局,繼續玩

6.坦克的聲音

坦克大戰最終版本(2.1)

MyTanKGame類:

/*
 * 功能:
 * 1.防止坦克重疊
 * 2.可以分關(閃爍效果)
 * 3.記錄成績(小型游戲都是寫在文件中)
 * 4.存檔退出,可以記錄但是敵人坦克的坐標
 * 5.可以恢覆上局,繼續玩
 * 6.坦克的聲音
 */
package com.fanghua6;

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.util.Vector;
import javax.swing.*;

public class MyTankGame1_7 extends JFrame implements ActionListener {

    Mypanel1_2 mp = null;

    // 定義開始面板
    MyStartPanel msp = null;
    // 做出菜單
    JMenuBar jmb = null;
    // 開始游戲
    JMenu jm1 = null;
    JMenuItem jmi1 = null;
    // 退出游戲
    JMenuItem jmi2 = null;
    // 存檔退出
    JMenuItem jmi3 = null;
    JMenuItem jmi4 = null;

    public static void main(String[] args) {
        new MyTankGame1_7();
    }

    // 構造函數
    public MyTankGame1_7() {
        // mp = new Mypanel1_2();

        // 啟動mp線程
        // Thread t = new Thread(mp);
        // t.start();

        // this.add(mp);
        // 註冊監聽
        // this.addKeyListener(mp);
        // 創建菜單及菜單選項
        jmb = new JMenuBar();
        jm1 = new JMenu("游戲(G)");
        jm1.setMnemonic('G');
        jmi1 = new JMenuItem("開始新游戲(N)");
        jmi1.setMnemonic('N');

        jmi2 = new JMenuItem("退出游戲(E)");
        jmi2.setMnemonic('E');

        jmi3 = new JMenuItem("存檔退出(C)");
        jmi3.setMnemonic('C');

        jmi4 = new JMenuItem("繼續上局(S)");
        jmi4.setMnemonic('S');

        // jmi1相應
        jmi1.addActionListener(this);
        jmi1.setActionCommand("newgame");
        jmi2.addActionListener(this);
        jmi2.setActionCommand("exit");
        jmi3.addActionListener(this);
        jmi3.setActionCommand("saveExit");
        jmi4.addActionListener(this);
        jmi4.setActionCommand("conGame");

        jm1.add(jmi1);
        jm1.add(jmi2);
        jm1.add(jmi3);
        jm1.add(jmi4);

        jmb.add(jm1);

        // 加了開始面板(上面的全註釋掉)
        msp = new MyStartPanel();
        this.add(msp);
        // 啟動msp面板
        Thread t = new Thread(msp);
        t.start();

        this.setJMenuBar(jmb);

        this.setSize(600, 500);
        this.setTitle("我的坦克大戰");
        ImageIcon icon = new ImageIcon("images\\tanke.png");
        this.setIconImage(icon.getImage());
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setVisible(true);

    }

    @Override
    public void actionPerformed(ActionEvent e) {
        // TODO Auto-generated method stub
        // 對用戶不同的點擊做出不同的處理
        if (e.getActionCommand().equals("newgame")) {

            // 創建戰場面板
            mp = new Mypanel1_2("newGame");
            // 啟動mp線程
            Thread t = new Thread(mp);
            t.start();
            // 先把msp刪掉,再加mp
            this.remove(msp);
            this.add(mp);
            // 註冊監聽
            this.addKeyListener(mp);
            // 顯示,刷新JFrame(這個很重要)
            this.setVisible(true);
        } else if (e.getActionCommand().equals("exit")) {

            // 用戶退出系統的菜單(保存擊毀敵人數量)
            Recorder.keepRecording();

            System.exit(0);
        }// 對存檔退出的處理
        else if (e.getActionCommand().equals("saveExit")) {

            /*
             * 當時這裡這樣處理的,大錯特錯。new兩次 工作 new Recorder().setEts(mp.ets);new
             * 保存擊毀敵人的數量和敵人的坐標 Recorder().keepRecAndEnemyTank();
             */

            // 工作
            Recorder rd = new Recorder();
            rd.setEts(mp.ets);
            // 保存擊毀敵人的數量和敵人的坐標
            rd.keepRecAndEnemyTank();

            // 退出
            System.exit(0);
        } else if (e.getActionCommand().equals("conGame")) {
            // 繼續游戲
            // 創建戰場面板
            mp = new Mypanel1_2("con");

            // 不在這:mp.nodes = new Recorder().getNodesAndEnNums();
            // 啟動mp線程
            Thread t = new Thread(mp);
            t.start();
            // 先把msp刪掉,再加mp
            this.remove(msp);
            this.add(mp);
            // 註冊監聽
            this.addKeyListener(mp);
            // 顯示,刷新JFrame(這個很重要)
            this.setVisible(true);

        }
    }
}

// 提示面板(用線程來實現閃爍效果)
class MyStartPanel extends JPanel implements Runnable {
    // 做一個開關
    int times = 0;

    public void paint(Graphics g) {
        super.paint(g);
        g.fillRect(0, 0, 400, 300);
        // 提示信息
        if (times % 2 == 0) {
            g.setColor(Color.yellow);
            // 開關信息的字體
            Font myFont = new Font("華文新魏", Font.BOLD, 30);
            g.setFont(myFont);// 別忘了
            g.drawString("stage: 1", 140, 200);
        }
    }

    @Override
    public void run() {
        // TODO Auto-generated method stub
        while (true) {
            // 休眠
            try {
                Thread.sleep(500);
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            times++;
            // 重畫
            this.repaint();
        }
    }

}

// 我的面板,拓寬思路:Panel本身就是一個刷新體
class Mypanel1_2 extends JPanel implements java.awt.event.KeyListener, Runnable {

    // 定義我的坦克
    Hero1_2 hero = null;

    // 判斷是續上局,還是新游戲

    // 定義敵人的坦克(不止一輛,線程安全,集合)
    Vector<EnemyTank> ets = new Vector<EnemyTank>();
    Vector<Node> nodes = new Vector<Node>();

    // 定義炸彈集合
    Vector<Bomb> bombs = new Vector<Bomb>();

    int enSize = 4;// 敵人坦克保持4個

    // 定義三張圖片(三張圖片才能組成一顆炸彈)
    Image image1 = null;
    Image image2 = null;
    Image image3 = null;

    // 構造函數(續局,變成含參的構造函數)
    public Mypanel1_2(String flag) {

        // 恢復記錄(寫在這裡)
        Recorder.getRecoring();

        hero = new Hero1_2(70, 100);

        if (flag.equals("newGame")) {
            // 初始化敵人的坦克
            for (int i = 0; i < enSize; i++) {
                // 創建一輛敵人的坦克
                EnemyTank et = new EnemyTank((i + 1) * 50, 0);
                et.setColor(0);
                // 坦克預設反向是0(向上),這裡改一下
                et.setDirect(2);

                // 將MyPanel的敵人坦克向量交給該敵人坦克
                et.setEts(ets);

                // 啟動敵人的坦克
                Thread t = new Thread(et);
                t.start();
                // 給敵人坦克添加一顆子彈
                Shot s = new Shot(et.x + 10, et.y + 30, 2);
                // 加入給敵人的坦克
                et.ss.add(s);

                Thread t2 = new Thread(s);
                t2.start();
                ets.add(et);
            }
        } else {

            nodes = new Recorder().getNodesAndEnNums();

            for (int i = 0; i < nodes.size(); i++) {

                Node node = nodes.get(i);
                // 創建一輛敵人的坦克
                EnemyTank et = new EnemyTank(node.x, node.y);
                et.setColor(0);
                et.setDirect(node.direct);

                // 將MyPanel的敵人坦克向量交給該敵人坦克
                et.setEts(ets);

                // 啟動敵人的坦克
                Thread t = new Thread(et);
                t.start();
                // 給敵人坦克添加一顆子彈
                Shot s = new Shot(et.x + 10, et.y + 30, 2);
                // 加入給敵人的坦克
                et.ss.add(s);

                Thread t2 = new Thread(s);
                t2.start();
                ets.add(et);
            }
        }
        // 初始話圖片,這樣做擊中第一個坦克,爆炸的效果不明顯。下麵優化
        image1 = Toolkit.getDefaultToolkit().getImage(
                Panel.class.getResource("/bomb_1.gif"));
        image2 = Toolkit.getDefaultToolkit().getImage(
                Panel.class.getResource("/bomb_2.gif"));
        image3 = Toolkit.getDefaultToolkit().getImage(
                Panel.class.getResource("/bomb_3.gif"));

        // 引包:import javax.imageio.ImagesssIO;
        // try {
        // image1=ImageIO.read(new File("/bomsb_1.gif"));
        // image2=ImageIO.read(new File("/bomb_2.gif"));
        // image3=ImageIO.read(new File("/bomb_3.gif"));
        // } catch (IOException e) {
        // // TODO Auto-generated catch block
        // e.printStackTrace();
        // }

        // 在Mypanel1_2初始化里,放置開戰音效,載入即播放
        // 以後再添加爆炸效果的聲音也是這樣做的思路
        AePlayWave apw = new AePlayWave("E:\\111.wav");
        apw.start();

    }

    // 提示信息(只需要畫筆即可)
    public void showInfo(Graphics g) {
        // 畫出提示信息坦克
        this.drawTank(70, 310, g, 0, 0);
        g.setColor(Color.black);
        g.drawString(Recorder.getEnNum() + "", 100, 330);

        this.drawTank(70, 360, g, 0, 1);
        g.setColor(Color.black);
        g.drawString(Recorder.getMyLife() + "", 100, 380);

        // 畫出玩家的總成績
        g.setColor(Color.black);
        Font f = new Font("宋體", Font.BOLD, 20);
        g.setFont(f);
        g.drawString("你的總成績", 410, 30);
        this.drawTank(410, 60, g, 0, 0);

        g.setColor(Color.black);
        g.drawString(Recorder.getAllEnNum() + "", 440, 80);
    }

    // 重寫paint函數
    public void paint(Graphics g) {
        // 一定要調用
        super.paint(g);
        g.fillRect(0, 0, 400, 300);
        // 畫出提示信息
        this.showInfo(g);

        // 畫出自己的坦克(將方向填進去)
        if (hero.isLive == true) {
            this.drawTank(hero.getX(), hero.getY(), g, this.hero.direct, 1);
        }
        // 從ss中取出每一顆子彈,並畫出
        for (int i = 0; i < hero.ss.size(); i++) {

            Shot myShot = hero.ss.get(i);
            if (myShot != null && myShot.isLive == true) {
                g.draw3DRect(myShot.x, myShot.y, 1, 1, false);

                /*
                 * 畫出一顆子彈(後添加 hero.s.isLive==true,節省資源) if (hero.s != null
                 * &&hero.s.isLive == true) { g.draw3DRect(hero.s.x, hero.s.y,
                 * 1, 1,false); }
                 */
            }
            if (myShot.isLive == false) {
                // 從ss(向量)中刪除該子彈
                // hero.ss.remove(i);會報異常。
                hero.ss.remove(myShot);
            }
        }

        // 畫出炸彈
        for (int i = 0; i < bombs.size(); i++) {
            // 取出炸彈
            Bomb b = bombs.get(i);
            if (b.life > 6) {
                g.drawImage(image1, b.x, b.y, 30, 30, this);
            } else if (b.life > 4) {
                g.drawImage(image2, b.x, b.y, 30, 30, this);
            } else {
                g.drawImage(image3, b.x, b.y, 30, 30, this);
            }
            // 讓b的生命值減小
            b.lifeDown();
            // 如果炸彈生命值為零,就把該炸彈從bombs向量中去掉
            if (b.life == 0) {
                bombs.remove(b);
            }

        }

        // 畫出敵人的坦克
        for (int i = 0; i < ets.size(); i++) {
            EnemyTank et = ets.get(i);
            if (et.isLive) {
                this.drawTank(et.getX(), et.getY(), g, et.getDirect(), 0);

                // 畫出敵人的子彈
                for (int j = 0; j < et.ss.size(); j++) {
                    // 取出子彈
                    Shot enemyShot = et.ss.get(j);
                    if (enemyShot != null && enemyShot.isLive == true) {
                        g.draw3DRect(enemyShot.x, enemyShot.y, 1, 1, false);
                    }
                    if (enemyShot.isLive == false) {
                        // 如果敵人的坦剋死亡了,就從Vector中刪除
                        et.ss.remove(enemyShot);
                    }
                }
            }
        }
    }

    // 敵人的坦克是否擊中我
    public void hitMe() {
        // 取出每一個敵人的坦克
        for (int i = 0; i < this.ets.size(); i++) {
            // 取出坦克
            EnemyTank et = ets.get(i);

            // 取出每一顆子彈
            for (int j = 0; j < et.ss.size(); j++) {
                // 取出子彈
                Shot enemyShot = et.ss.get(j);
                if (hero.isLive) {
                    if (this.hitTank(enemyShot, hero)) {

                    }
                }
            }
        }
    }

    // 判斷我的子彈是否擊中敵人的坦克
    public void hitEnemyTank() {
        // 判斷是否擊中敵人的坦克
        for (int i = 0; i < hero.ss.size(); i++) {
            // 取出子彈
            Shot myShot = hero.ss.get(i);
            // 判斷子彈是否有效
            if (myShot.isLive) {
                // 取出每個坦克,與它判斷
                for (int j = 0; j < ets.size(); j++) {
                    // 取出坦克
                    EnemyTank et = ets.get(j);

                    if (et.isLive) {
                        if (this.hitTank(myShot, et)) {

                            // 減少敵人數量
                            Recorder.reduceEnNum();
                            // 增加我的記錄
                            Recorder.addEnNumRec();
                        }
                    }

                }
            }
        }
    }

    // 寫一個函數 專門判斷是否擊中敵人坦克(原來第二參數: EnemyTank et)
    // void改成boolean 判斷擊中的目標是誰

    public boolean hitTank(Shot s, Tank1_2 et) {
        boolean b2 = false;

        // 判斷該坦克的方向
        switch (et.direct) {
        // 如果敵人坦克的方向是上或者是下
        case 0:
        case 2:
            if (s.x > et.x && s.x < et.x + 20 && s.y > et.y && s.y < et.y + 30) {
                // 擊中
                // 子彈死亡
                s.isLive = false;
                // 敵人坦剋死亡
                et.isLive = false;
                b2 = true;
                // 創建一顆炸彈,放入Vector
                Bomb b = new Bomb(et.x, et.y);
                // 放入Vector
                bombs.add(b);

            }

            break;
        case 1:
        case 3:
            if (s.x > et.x && s.x < et.x + 30 && s.y > et.y && s.y < et.y + 20) {
                // 擊中
                // 子彈死亡
                s.isLive = false;
                // 敵人坦剋死亡
                et.isLive = false;
                b2 = true;
                // 創建一顆炸彈,放入Vector
                Bomb b = new Bomb(et.x, et.y);
                // 放入Vector
                bombs.add(b);

            }
            break;
        }

        return b2;

    }

    // 畫出坦克的函數
    public void drawTank(int x, int y, Graphics g, int direct, int type) {
        // 坦克類型
        switch (type) {
        case 0:
            g.setColor(Color.green);
            break;
        case 1:
            g.setColor(Color.yellow);
            break;
        }
        // 方向設置
        switch (direct) {
        // 向上
        case 0:
            g.fill3DRect(x, y, 5, 30, false);
            g.fill3DRect(x + 15, y, 5, 30, false);
            g.fill3DRect(x + 5, y + 5, 10, 20, false);
            g.fillOval(x + 5, y + 10, 10, 10);
            g.drawLine(x + 10, y + 15, x + 10, y);
            break;
        // 向右
        case 1:
            g.fill3DRect(x, y, 30, 5, false);
            g.fill3DRect(x, y + 15, 30, 5, false);
            g.fill3DRect(x + 5, y + 5, 20, 10, false);
            g.fillOval(x + 10, y + 5, 10, 10);
            g.drawLine(x + 15, y + 10, x + 30, y + 10);
            break;
        // 向下
        case 2:
            g.fill3DRect(x, y, 5, 30, false);
            g.fill3DRect(x + 15, y, 5, 30, false);
            g.fill3DRect(x + 5, y + 5, 10, 20, false);
            g.fillOval(x + 5, y + 10, 10, 10);
            g.drawLine(x + 10, y + 15, x + 10, y + 30);
            break;
        // 向左
        case 3:
            g.fill3DRect(x, y, 30, 5, false);
            g.fill3DRect(x, y + 15, 30, 5, false);
            g.fill3DRect(x + 5, y + 5, 20, 10, false);
            g.fillOval(x + 10, y + 5, 10, 10);
            g.drawLine(x + 15, y + 10, x, y + 10);
            break;
        }

    }

    @Override
    public void keyPressed(KeyEvent e) {
        // TODO Auto-generated method stub
        // 已更正為順時針
        if (e.getKeyCode() == KeyEvent.VK_UP || e.getKeyCode() == KeyEvent.VK_W) {
            this.hero.moveUp();
            this.hero.setDirect(0);
        } else if (e.getKeyCode() == KeyEvent.VK_RIGHT
                || e.getKeyCode() == KeyEvent.VK_D) {
            this.hero.setDirect(1);
            this.hero.moveRight();
        } else if (e.getKeyCode() == KeyEvent.VK_DOWN
                || e.getKeyCode() == KeyEvent.VK_S) {
            this.hero.moveDown();
            this.hero.setDirect(2);
        } else if (e.getKeyCode() == KeyEvent.VK_LEFT
                || e.getKeyCode() == KeyEvent.VK_A) {
            this.hero.moveLeft();
            this.hero.setDirect(3);
        } else if (e.getKeyCode() == KeyEvent.VK_J) {
            // 將J鍵設置為發出子彈
            // 子彈連發,J被按幾下,發幾顆:this.hero.shotEnemy();
            // this.repaint();在run函數里,不應該設計在這裡
            if (this.hero.ss.size() <= 4) {
                this.hero.shotEnemy();
            }
        }
        // 必須重新繪製Panel
        this.repaint();
    }

    @Override
    public void keyReleased(KeyEvent e) {
        // TODO Auto-generated method stub

    }

    @Override
    public void keyTyped(KeyEvent e) {
        // TODO Auto-generated method stub

    }

    @Override
    public void run() {
        // TODO Auto-generated method stub
        // 每隔100毫秒去重繪
        while (true) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

            // 謹記這裡:由於這裡多寫了這些,線程每次都被重新調用
            // showInfo的信息不會動態改變 調了好久好久。苦笑臉
            // 判斷是否擊中(寫在這裡,雖然在每次重繪的時候都要調用,但是沒辦法)
            // 每一顆子彈都要和每個坦克進行匹配
            // for (int i = 0; i < hero.ss.size(); i++) {
            // // 取出子彈
            // Shot myShot = hero.ss.get(i);
            // // 判斷子彈是否有效
            // if (myShot.isLive) {
            // // 取出每個坦克,與它判斷
            // for (int j = 0; j < ets.size(); j++) {
            // // 取出坦克
            // EnemyTank et = ets.get(j);
            //
            // if (et.isLive) {
            // this.hitTank(myShot, et);
            // }
            // }
            // }
            // }
            this.hitEnemyTank();

            this.hitMe();

            // 重繪
            this.repaint();
        }
    }
}

Menbers類:

package com.fanghua6;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Vector;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.SourceDataLine;

//播放聲音的類
class AePlayWave extends Thread {

    private String filename;

    public AePlayWave(String wavfile) {
        filename = wavfile;

    }

    public void run() {

        File soundFile = new File(filename);

        AudioInputStream audioInputStream = null;
        try {
            audioInputStream = AudioSystem.getAudioInputStream(soundFile);
        } catch (Exception e1) {
            e1.printStackTrace();
            return;
        }

        AudioFormat format = audioInputStream.getFormat();
        SourceDataLine auline = null;
        DataLine.Info info = new DataLine.Info(SourceDataLine.class, format);

        try {
            auline = (SourceDataLine) AudioSystem.getLine(info);
            auline.open(format);
        } catch (Exception e) {
            e.printStackTrace();
            return;
        }

        auline.start();
        int nBytesRead = 0;
        // 這是緩衝
        byte[] abData = new byte[512];

        try {
            while (nBytesRead != -1) {
                nBytesRead = audioInputStream.read(abData, 0, abData.length);
                if (nBytesRead >= 0)
                    auline.write(abData, 0, nBytesRead);
            }
        } catch (IOException e) {
            e.printStackTrace();
            return;
        } finally {
            auline.drain();
            auline.close();
        }
    }
}

// 繼續上一局的記記錄點的類
class Node {
    int x;
    int y;
    int direct;

    public Node(int x, int y, int direct) {
        this.x = x;
        this.y = y;
        this.direct = direct;
    }
}

// 記錄類,同時也可以保存玩家的設置(一般都是事先寫在緩存裡面的)
class Recorder {
    // 記錄每關有多少敵人
    private static int enNum = 20;
    // 設置我有多少可以用的坦克
    private static int myLife = 3;
    // 記錄一共消滅多少敵人
    private static int allEnNum = 0;

    // 從文件中恢復記錄點
    static Vector<Node> nodes = new Vector<Node>();

    private static FileWriter fw = null;
    private static BufferedWriter bw = null;
    private static FileReader fr = null;
    private static BufferedReader br = null;

    private Vector<EnemyTank> ets = new Vector<EnemyTank>();

    // 完成讀取的函數(記錄點和敵人的數量)
    public Vector<Node> getNodesAndEnNums() {
        try {
            fr = new FileReader("E:/Tanke.txt");
            br = new BufferedReader(fr);
            String n = "";
            n = br.readLine();// 設置先讀第一行
            allEnNum = Integer.parseInt(n);
            // 接著讀
            while ((n = br.readLine()) != null) {
                String[] xyz = n.split(" ");
                // 在知道只有三條數據的情況下,用了這個方法。否則要用for迴圈
                Node node = new Node(Integer.parseInt(xyz[0]),
                        Integer.parseInt(xyz[1]), Integer.parseInt(xyz[2]));
                nodes.add(node);
            }

        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            try {
                br.close();
                fr.close();
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        return nodes;
    }

    public Vector<EnemyTank> getEts() {
        return ets;
    }

    public void setEts(Vector<EnemyTank> ets) {
        this.ets = ets;
    }

    // 保存擊毀敵人的數量和擊毀敵人坦克的坐標、方向
    public void keepRecAndEnemyTank() {
        try {
            fw = new FileWriter("E:/Tanke.txt");
            bw = new BufferedWriter(fw);

            bw.write(allEnNum + "\r\n");

            // 保存當前的敵人坦克的坐標和方向
            for (int i = 0; i < ets.size(); i++) {
                // 取出第一個坦克
                EnemyTank et = ets.get(i);
                if (et.isLive) {
                    	   

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一、前言 上一章學習完了Js的一些基本內容,本章開始學習JQuery語法。JQuery的基礎語法是: 那麼重要的兩個元素,一個是選擇器,另一個是行為!本章開始學習JQuery的選擇器。 二、內容 ...
  • 在前端的開發過程中,免不了進行各種調試和測試。 在不同的平臺,不同的環境下的調試方法也不盡相同,這個系列文章將探索常見的一些前端調試場景,較為系統地整理出一些調試方法。 主要包含在 PC上的 IE、FireFox、Chrome、Safari、Edge瀏覽器開發工具調試,遠程真機 安卓微信頁面、安卓常 ...
  • 一、前言 這章非常重要,由於之後需要負責平臺手機APP的日後維護,如何讓用戶在離線狀態下正常使用,以及聯網後的數據合併變得非常重要。 二、內容 離線檢測 數據存儲 ...
  • Factory負責處理生命周期的開始,而Repository幫助管理生命周期的中間和結束。 通俗的來說,Factory用於創建一個對象的新的實例,而Repository用於從資料庫中查找數據。 ...
  • 協程 協程又稱為微線程,協程是一種用戶態的輕量級線程 協程擁有自己的寄存器和棧。協程調度切換的時候,將寄存器上下文和棧都保存到其他地方,在切換回來的時候,恢復到先前保存的寄存器上下文和棧,因此:協程能保留上一次調用狀態,每次過程重入時,就相當於進入上一次調用的狀態。 協程的好處: 1.無需線程上下文 ...
  • 記憶體限制:256 MiB時間限制:500 ms標準輸入輸出 題目類型:傳統評測方式:文本比較 上傳者: hzwer 記憶體限制:256 MiB時間限制:500 ms標準輸入輸出 題目類型:傳統評測方式:文本比較 上傳者: hzwer 提交提交記錄統計討論 1 測試數據 題目描述 給出一個長為 nnn  ...
  • 在最早學習四則運算的過程中,我們其實就已經掌握了進位演算法,這一次我將對二進位運用這個進位演算法來實現四則運算。 四則運算 math.c 從遞歸角度看待代碼 遞歸是函數調用,考慮值的傳遞過程,適合閱讀。 迭代是具體的實現過程,往往代碼效率更加充分。 通常我們在寫代碼時,往往註重代碼的效率和正確性,而忽略 ...
  • jdk1.8.0_144 Object類作為Java中的頂級類,位於java.lang包中。所有的類直接或者間接都繼承自它。所以Object類中的方法在所有類中都可以直接調用。在深入介紹它的API時,先插一句它和泛型之間的關係。 在JDK1.5之前是沒有泛型的,集合能夠裝下任意的類型,這就導致了一個 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...