日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > java >内容正文

java

基于Java实现的植物大战僵尸游戏

發(fā)布時間:2023/12/20 java 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 基于Java实现的植物大战僵尸游戏 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

資源下載地址:https://download.csdn.net/download/sheziqiong/86812910
資源下載地址:https://download.csdn.net/download/sheziqiong/86812910

基于Java設(shè)計的植物大戰(zhàn)僵尸游戲

一、植物大戰(zhàn)僵尸游戲規(guī)則

游戲簡介

玩家通過種植太陽花收取陽光來購買植物;通過種植不同的植物來抵御僵尸的攻擊。當(dāng)一個關(guān)卡里的僵尸全部被消滅時,玩家勝;當(dāng)僵尸越過地圖的右邊界時,僵尸勝利。

植物簡介

購買植物需要花費一定數(shù)量的陽光,每購買一次過后需要冷卻一段時間才能再次購買。每個關(guān)卡允許使用的植物各有不同,不同植物的特性也不同

植物主要分為:攻擊類,防御類和生產(chǎn)類。也可以分為夜間植物和白天植物(夜間植物只能在夜間出現(xiàn))

攻擊類

  • 發(fā)射類
  • 防御類
  • 攻擊增強類

發(fā)射類

當(dāng)僵尸進(jìn)入射手的射程內(nèi)時,射手會發(fā)射豌豆攻擊。

  • 豌豆射手

    • 單發(fā)射手
      • 攻擊:20
      • 耐久:300
      • 射程:正前方一整行
    • 雙發(fā)射手
      • 發(fā)射速度是單發(fā)射手的兩倍,其余同單發(fā)射手。
    • 三線射手
      • 該植物可同時向3排(植物所處排和左右排)同時發(fā)射出3顆豌豆 ,其余同單發(fā)射手。
    • 寒冰射手
      • 寒冰射手每次攻擊發(fā)射一顆冰豌豆,命中目標(biāo)后對僵尸造成傷害。其余同單發(fā)射手。
    • 機槍射手
      • 連續(xù)射出四發(fā)豌豆子彈
      • 四倍的快樂
    • 小噴菇(夜間植物)
      • 小噴菇免費
      • 射程短
    • 膽小菇(夜間植物)
      • 它是一種遠(yuǎn)程射手,敵人接近后會躲起來,不會攻擊。
      • 攻擊:20
      • 耐久:300
      • 射程:正前方一整行

爆炸類

  • 櫻桃炸彈
    • 種下0.6秒后爆炸,能炸死3*3范圍內(nèi)的僵尸
  • 火爆辣椒
    • 種下0.75秒后爆炸,能炸死同排的僵尸
  • 土豆雷
    • 種下后2s后長大,在此期間可以被僵尸吃掉。
    • 長大后進(jìn)入等待狀態(tài),當(dāng)同排僵尸距離土豆雷半格時,土豆雷爆炸,僵尸被炸死。
    • 耐久: 300

吞食類

  • 食人花
    • 能夠一口吞掉僵尸,然后要咀嚼消化一段時間,此時容易受到攻擊。
    • 耐久:300

攻擊增強類

  • 火炬樹樁
    • 用來增強豌豆植物發(fā)射的豌豆的火力,當(dāng)豌豆劃過樹樁后,會變成火球,豌豆的威力變成2倍
    • 但是如果穿過的是寒冰豌豆就會變成普通的豌豆了

防御類

  • 堅果墻
    • 攻擊性:0(無攻擊力)
    • 防御力:3000(較高)
    • 用于阻礙僵尸前進(jìn)的步伐
  • 高堅果
    • 巨大的堅果,可以更好的阻擋僵尸前行
    • 攻擊性:0(無攻擊力)
    • 防御力:8000

生產(chǎn)類

生產(chǎn)陽光,供拾取購買植物

  • 向日葵
    • 可生產(chǎn)陽光
    • 耐久:300
  • 陽光菇(夜間植物)
    • 白天睡覺,可在夜間生產(chǎn)陽光
    • 耐久:250
  • 雙子向日葵
    • 雙份的陽光,雙份的喜悅
    • 耐久:300

僵尸簡介

在游戲中,不同種類的僵尸會一波波的攻擊。不同僵尸的攻擊值,耐久,特性有所不同。

僵尸分為:

  • 普通僵尸
    • 游戲中最普通的花園僵尸
    • 血量:270(普通)
    • 攻擊:啃食攻擊,100/秒
    • 速度:約4.7秒/格(普通)
  • 旗幟僵尸
    • 該僵尸是領(lǐng)頭者,速度比普通僵尸快
    • 血量:270
  • 路障僵尸
    • 防御能力是普通僵尸的兩倍
    • 血量:640
  • 鐵桶僵尸
    • 防御能力比路障僵尸更強
    • 血量:1100
  • 橄欖球僵尸
    • 速度很快,防御強于鐵桶僵尸
    • 血量:1160
  • 讀報僵尸
    • 報紙可做防御,拿著報紙時速度很慢
    • 多次受到攻擊后失去報紙,防御變低,速度變快
    • 血量:420

附加道具簡介

  • 小推車
    • 位于最后防線的前方,當(dāng)僵尸瀕臨最后防線時,小推車出動,將同排僵尸碾壓致死。
  • 陽光
    • 可以靠天吃飯獲得
    • 可以生產(chǎn)類植物處獲得
    • 拾取后,可用來購買植物

關(guān)卡簡介

逐個關(guān)卡擊破,取得最終勝利。

關(guān)卡很有趣,請各位自行體驗,這里不再贅述。

二、文檔

1. 類圖

整體:

核心部分:

大圖見docs文件夾

2. 用例圖

3. 時序圖

I. 更新植物

II. 開始新游戲

III. 向僵尸總HP最少的行添加一個指定的僵尸

IV. 陽光下落

V. 向音頻池添加游戲音效

三、項目完成情況

這是一份項目開始時準(zhǔn)備的的TODO-List

游戲核心- [x] 單次派發(fā)系統(tǒng)- [x] 基于FSM的狀態(tài)機制- [x] 基于多線程的音頻池(使用.wav)- [x] 附帶(類似)回調(diào)函數(shù)的雜項GIF播放系統(tǒng)- [x] 交互界面- [x] 開始界面- [x] 游戲界面- [x] 后院- [x] 卡牌槽- [x] 陽光槽- [x] 卡牌槽- [x] 卡牌- [x] 關(guān)卡進(jìn)度- [x] 界面交互- [x] 放置植物- [x] 收集陽光- [x] 暫停界面- [x] 通關(guān)/失敗提示- [x] 關(guān)卡設(shè)計- 考慮一關(guān)總僵尸量一定- 每間隔一段時間放置- 原則:- 在僵尸總HP最少的行上放置 植物- [x] 普通植物- [x] 向日葵- [x] 雙子向日葵- [x] 豌豆射手- [x] 雙發(fā)射手- [x] 三線射手- [x] 機槍射手- [x] 寒冰射手- [x] 堅果墻- [x] 高堅果- [x] 食人花- [x] 櫻桃炸彈- [x] 火爆辣椒- [x] 土豆雷- [x] 火炬樹樁- [ ] 夜間植物- [x] 小噴菇- [x] 膽小菇- [ ] 大噴菇- [x] 陽光菇 僵尸- [x] 普通僵尸- [x] 旗幟僵尸- [x] 路障僵尸- [x] 鐵桶僵尸- [x] 橄欖球僵尸- [ ] 小丑僵尸- [x] 讀報僵尸- [ ] 撐桿跳僵尸 子彈類- [x] 豌豆- [x] 冰豌豆- [x] 燃燒豌豆- [x] 孢子- [ ] 大孢子(大噴菇)

四、附錄

(魔幻)植物大戰(zhàn)(成精)僵尸擴展編程不Van全指南

原理簡介

一、名詞解釋

  • FSM,有限狀態(tài)自動機,一個FSM相當(dāng)于一個獨立的AI系統(tǒng),每一個能夠獨立動作個體都擁有屬于自己的FSM系統(tǒng)。舉幾個例子
    • 豌豆射手擁有以下幾種狀態(tài)
      • 0:待機態(tài),沒有可以攻擊的僵尸
      • 1:攻擊態(tài),攻擊態(tài)=攻擊+CD
      • 2:HP耗盡,立即被回收
    • 普通僵尸擁有以下幾種狀態(tài)
      • 0 : 待機態(tài),未出場
      • 1 : 有頭行走
      • 2 : 有頭攻擊
      • 3 : 無頭行走
      • 4 : 無頭攻擊
      • 5 : 被炸死,立即被回收
      • 6 : 無頭死亡(正常死亡),立即被回收
    • 一個狀態(tài)又兩部分組成,一是表示狀態(tài)的數(shù)字,這個數(shù)字是這個狀態(tài)的唯一標(biāo)示,二是狀態(tài)附帶的動作,即個體被判定處于這個狀態(tài)后應(yīng)該執(zhí)行的操作。例子接上面
      • 對于豌豆射手
        • 0/1:
          • 當(dāng)HP耗盡 -> 2
        • 0:
          • 當(dāng)觀測到有可攻擊的僵尸 -> 1
        • 1:
          • 當(dāng)不再有可攻擊的僵尸(上面的檢測條件添加.negate()即可實現(xiàn)) -> 0
      • 對于普通僵尸
        • 1/2/3/4:
          • 當(dāng)受到足以致命的爆炸傷害 -> 5
        • 3/4:
          • 當(dāng)HP耗盡 -> 6
        • 1:
          • 觀測到可攻擊 -> 2
          • HP低于閾值 -> 3(掉頭行走)
        • 2:
          • 不再可攻擊(等價于(1->2).negate()) -> 1
          • HP低于閾值 -> 4(掉頭攻擊)
        • 3:
          • 觀測到可攻擊 -> 4
        • 4:
          • 不再可攻擊(等價于(3->4).negate()) -> 3
      • 要求:
        • 任何對于死亡的檢測必須寫在前面,因為沒有實現(xiàn)狀態(tài)轉(zhuǎn)移的優(yōu)先級,當(dāng)檢測到可滿足的轉(zhuǎn)移條件后就不再檢測其他條件
  • 函數(shù)式編程,本項目使用函數(shù)編程接口
    • Predicate:
      • 接受參數(shù)并返回true/false
      • 用作檢測是否滿足轉(zhuǎn)移條件
      • 程序中使用BiPredicate,接受兩個參數(shù),一是游戲棋盤的總體,二是實體本身
    • Consumer
      • 接受參數(shù)并執(zhí)行,無返回值
      • 用作狀態(tài)的執(zhí)行
      • 程序中使用BiConsumer,接受兩個參數(shù),同上
  • 音頻池,用來播放游戲中的音樂與音效
    • 背景音樂,同一時刻只允許存在一個背景音樂,且背景音樂自動設(shè)置為循環(huán)播放
    • 游戲音效,子彈擊中僵尸、僵尸啃噬植物等均為音效,一經(jīng)添加立即播放,播放完畢后釋放資源(由JVM接管)
  • 二、代碼組織形式

  • 庫組織形式
    • model 模型
      • base基本類型
      • bullets子彈
      • plants植物
      • sound音頻
      • zombies僵尸
      • level 關(guān)卡
    • view 視圖渲染部分
    • controller 用戶交互界面
  • 游戲棋盤GameBoard成分
    • 僵尸圖 zombieMap
    • 植物圖 plantMap
    • 子彈圖 bulletMap
    • 雜項圖 extraMap
    • 陽光圖 sumMap,原本設(shè)計在雜項里,但考慮到檢測的效率,故獨立之
  • 核心API講解

  • 注意,本部分代碼因項目后期沒有維護(hù),可能已過時,詳情請參考具體代碼

  • abstract void setStateTable(); //設(shè)置狀態(tài)表

    • 任何繼承Root的子類都必須實現(xiàn)的方法
    • 以豌豆射手Pershooter類為例:protected void setStateTable() {// 0 : 正常// 1 : 攻擊// 2 : HP耗盡BiConsumer<GameBoard, Root> attack = ((gameBoard, root) ->// 攻擊時應(yīng)該做什么{if ((intervalCount++) % attackPerTicks == 0){Plant pt = (Plant) root;for (Object ob : gameBoard.zombieMap.getRow(pt.getY())){Zombie zb = (Zombie) ob;if (zb.getX() - pt.getX() <= MAX_PROBE_RANGE){gameBoard.bulletMap.getRow(pt.getY()).add(new BeanBullet(pt.getX() + pt.getWidth() / 2, pt.getY()));SoundPool.addSound(GameRule.choice(GameRule.pea_shoot));return;}}}});addState(0, "peashooter.gif", null);addState(1, "peashooter.gif", attack);addState(2, "peashooter.gif", (gameBoard, root) -> finish = true); }
    • 類中的方法addState
      • 接受兩個參數(shù)
      • 方法簽名為void addState(int state, String fName, BiConsumer<GameBoard, Root> action)
        • state為當(dāng)前狀態(tài)碼
        • fName為狀態(tài)要播放的gif,可為null
        • action為BiConsumer,是該狀態(tài)要執(zhí)行的操作,可為null
  • abstract void setStateTransfer(); //設(shè)置轉(zhuǎn)移條件

    • 任何繼承Root的子類都必須實現(xiàn)的方法
    • 以豌豆射手Pershooter類為例:protected void setStateTransfer() {// BOTH -> HP耗盡死亡addTransfer(new int[] {0, 1}, 2, ((gameBoard, root) -> hp <= 0));// 待機 -> 開始攻擊addTransfer(0, 1, getAttackTransfer(MAX_PROBE_RANGE));// 攻擊 -> 待機addTransfer(1, 0, getAttackTransfer(MAX_PROBE_RANGE).negate()); }
    • 類中的方法addTransfer
      • 接受三個參數(shù)
      • 方法簽名為void addTransfer(int from, int to, BiPredicate<GameBoard, Root> cond)
        • from為來自的狀態(tài)
        • to為滿足cond后轉(zhuǎn)移到的狀態(tài)
        • cond為BiPredicate,是狀態(tài)轉(zhuǎn)移條件
        • 還定義有方法void addTransfer(int[] froms, int to, BiPredicate<GameBoard, Root> cond)
          • froms數(shù)組中各元素都會被展開成原方法形式
          • 旨在實現(xiàn)快速添加對象死亡的轉(zhuǎn)移條件
  • 音頻池SoundPool系統(tǒng)

    • 音頻池為游戲提供了背景音樂與游戲音效支持
    • public static void addSound(String fName)
      • 添加音效
      • 音效會被立刻播放
      • 播放結(jié)束后自動回收
      • 一時刻可能有很多很多音效在播放
    • public static void setBGmusic(String fName)
      • 設(shè)置背景音樂
      • 音樂會被立刻播放
      • 音樂循環(huán)
      • 每一時刻只能有一首正在播放的BGM,重設(shè)后會替換原BGM
    • 注意
      • 上述兩方法為靜態(tài)方法,調(diào)用方式為
        • SoundPool.addSound(xxxxx);
        • SoundPool.setBGmusic(xxxxx);
      • 編碼人員不用創(chuàng)建該類的任何實例,兩靜態(tài)方法會自動處理
    • 現(xiàn)狀:音頻系統(tǒng)是引起游戲很卡的罪魁禍?zhǔn)?
      • [完成]初步優(yōu)化:使用字典管理正在播放的音頻,限制同一音頻最多同時播放3個,稍有改善

      • [待進(jìn)行]進(jìn)一步構(gòu)思:

        • 使用線程池技術(shù),預(yù)先開辟線程,消除線程構(gòu)造與回收造成的系統(tǒng)資源消耗
  • 關(guān)卡Level & LevelManager & LevelFactory系統(tǒng)

    • Level: 保存一個關(guān)卡的信息
    • LevelManager: 組合一個Level并被多個類所傳遞,用于獲取關(guān)卡信息與處理游戲勝負(fù)
    • LevelFactory: 關(guān)卡工廠,想添加新的關(guān)卡就寫在這里
    • 如何寫一個新關(guān)卡:
      • 你需要提供
        • 關(guān)卡的編號
        • 出現(xiàn)在本關(guān)的所有僵尸與他們的數(shù)量
        • 總波數(shù)
        • 總時間
        • 下一關(guān)的編號(-1代表結(jié)束)
        • 可以使用的植物
        • 場景圖片
        • 背景音樂
        • 是否從天上掉落陽光
        • 掉落陽光的間隔是多少
        • 預(yù)先設(shè)置的植物
      • 編寫成代碼:Level level = new Level(); HashMap<String, Integer> zombieCount = new HashMap<>(); ArrayList<PlantInfo> cards = new ArrayList<>(); ArrayList<PreSetPlant> pres = new ArrayList<>(); zombieCount.put("normal_zombie", 10); // 10個普通僵尸 zombieCount.put("football_zombie", 10); // 10個橄欖球僵尸 zombieCount.put("buckethead_zombie", 5); // 5個鐵桶僵尸 zombieCount.put("conehead_zombie", 5); // 5個路障僵尸 zombieCount.put("newspaper_zombie", 5); // 5個讀報僵尸cards.add(new PlantInfo("Chomper", 50, 2)); // 可使用食人花, 花費50陽光,冷卻2s cards.add(new PlantInfo("Jalapeno", 50, 2)); // 火爆辣椒 cards.add(new PlantInfo("Peashooter", 100, 2)); // 豌豆射手 cards.add(new PlantInfo("Threepeater", 100, 2)); // 三發(fā)射手 cards.add(new PlantInfo("CherryBomb", 100, 2)); // 櫻桃炸彈 cards.add(new PlantInfo("ScaredyShroom", 100, 2)); // 膽小菇// 預(yù)設(shè)植物, new (name, col, row) pres.add(new PreSetPlant("PotatoMine", 5, 0)); pres.add(new PreSetPlant("PotatoMine", 5, 1)); pres.add(new PreSetPlant("PotatoMine", 5, 2)); pres.add(new PreSetPlant("PotatoMine", 5, 3)); pres.add(new PreSetPlant("PotatoMine", 5, 4));level.setLevelNumber(1) // 關(guān)卡編號1.setZombies(zombieCount) // 設(shè)置所有僵尸(見上方).setWaves(10) // 10波.setLevelTime(50) // 50秒(最后一波僵尸出現(xiàn)的時間).setLevelNext(2) // 下一關(guān)進(jìn)入編號2.setPlantInfos(cards) // 設(shè)置可使用的植物.setlevelImg(GameRule.backgroundDay) // 關(guān)卡背景.setLevelBgmusic(GameRule.dayBG) // 背景音樂.setDropSun(true) // 白天,從天上掉陽光.setDropSunPerSeconds(5) // 第一關(guān),陽光掉落頻繁.setPrePlants(pres); // 預(yù)設(shè)植物,可為空
      • 由于大量使用了Java的反射機制,使得程序具有特別強大的靈活性,可以看出,僅需要一個字符串便能調(diào)用一個類
      • 所以,新建一個關(guān)卡只需要填寫很少的代碼
      • 由于植物的花費與冷卻時間可控,我們還可以做出許多有趣的小游戲,比如:
        • 一關(guān)只允許使用爆炸物,且爆炸物冷卻時間極短而且花費很低
        • 一關(guān)的高堅果與堅果墻十分廉價,但攻擊方式只有普通豌豆射手
        • 更多腦洞任君開發(fā)
  • 僵尸、植物、子彈或雜項何時被系統(tǒng)刪除

    • 在Root類中有一名為finish的布爾型變量,一旦為true,則會在最近一次的更新中被移除
    • 對于動畫,例如僵尸的倒下死亡或被炸死,有兩種處理思路
      • 轉(zhuǎn)移到這個狀態(tài),播放這個gif,sleep對應(yīng)時間后在設(shè)置為finish=true
      • 轉(zhuǎn)移到這個狀態(tài),立刻設(shè)置為finish=true,在雜項map內(nèi)添加這樣的gif
    • 本程序在簡潔性與易擴展型的考量下決定使用后者,具體使用方法舉例如下:// 僵尸被炸死 addState(5, null, (gameBoard, root) -> {finish = true;gameBoard.extraMap.add(new Extra(getPath() + "boom_die.gif", 3500, getX(), getY())); });// 僵尸HP耗盡 addState(6, null, (gameBoard, root) -> {finish = true;gameBoard.extraMap.add(new Extra(getPath() + "nohead_die.gif", 1500, getX(), getY())); });
    • Extra類的構(gòu)造函數(shù)簽名如下
      • public Extra(String fName, int ms, int x, int y, boolean bullet)
      • 與public Extra(String fName, int ms, int x, int y)
      • 其中
        • fName為需要播放的gif文件
        • ms為gif所需執(zhí)行時間,用于Thread.sleep()
        • x, y,物體坐標(biāo)
        • bullet,是否為子彈,true代表是,不填為否
    • Extra類被構(gòu)造后會在最近一次的更新中被添加
    • 在延遲時間到后自動被回收,實現(xiàn)方法同為finish=true
  • raMap.add(new Extra(getPath() + “nohead_die.gif”, 1500, getX(), getY()));
    });
    ```
    - Extra類的構(gòu)造函數(shù)簽名如下
    - public Extra(String fName, int ms, int x, int y, boolean bullet)
    - 與public Extra(String fName, int ms, int x, int y)
    - 其中
    - fName為需要播放的gif文件
    - ms為gif所需執(zhí)行時間,用于Thread.sleep()
    - x, y,物體坐標(biāo)
    - bullet,是否為子彈,true代表是,不填為否
    - Extra類被構(gòu)造后會在最近一次的更新中被添加
    - 在延遲時間到后自動被回收,實現(xiàn)方法同為finish=true

    END

    資源下載地址:https://download.csdn.net/download/sheziqiong/86812910
    資源下載地址:https://download.csdn.net/download/sheziqiong/86812910

    總結(jié)

    以上是生活随笔為你收集整理的基于Java实现的植物大战僵尸游戏的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。