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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > python >内容正文

python

[python3]坦克大战

發布時間:2023/12/10 python 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 [python3]坦克大战 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

坦克大戰完整版[Python3]

英文注釋版


由https://www.cnblogs.com/lwj-jz/articles/TankWarGame.html轉載

【寫在前面】

還記得小時候玩過的坦克大戰嘛~想當年幾個小伙伴擠在一起,恨不得把鍵盤分成幾瓣……

好了,廢話不多說,直入主題。今天咱們要基本實現坦克大戰的小游戲,主要利用第三方庫pygame,不了解的友友們可以參考官方文檔。由于最近http://www.pygame.org成了這鬼樣子

害,就煩人,不過還好之前下載了文檔,鏈接在這里pygame官方文檔

如果你不想跟著學,想要完整代碼點贊后私聊我;如果你想跟著學,我相信,你不用私聊我也可以做出來,并且會隨手給我一個小小的贊~

【運行結果】

先上結果!!!

【準備工作】

結果滿意不~

滿意的話就去點個小小的贊,不要錢的哈。

不滿意也不要緊,嘿嘿,看清楚了,這只是Tank War 1.0哦,這意味著什么?對,升級更新。不過,我相信,這些夠你用的了,想升級的話,私聊我吧。

  • 編輯環境:Pycharm。
  • 解釋器:Python3。
  • 需要按步驟導入相關模塊,一定核對好。
  • 相關素材資源:鏈接我就直接給了哈,別回頭說我不厚道……坦克大戰素材
  • 【項目需求】

    首先我們得分析下,做這個《坦克大戰》小游戲需要什么東西。

    """ Here are the project requirements for the Tank Wars game.1. What classes are in the project?a) MainGameb) Tank(OurTank, EnemyTank)c) Bulletd) Walle) Explosionf) Musicg) BaseItem --> Sprite class2. What are the methods in each class?a) methods in MainGame class1. startGame2. gameOver3. getEvent4. setTextSurfaceb) methods in Tank class1. shooting2. moveTank3. displayTank4. isCollidec) methods in Bullet class1. moveBullet2. displayBllet3. isCollided) methods in Wall class1. displayWalle) methods in Explosion class1. displayExplosionf) methods in Music class1. playMusicg) methods in BaseItem class """

    啊?英文的看不懂?不能吧,我已經很中文了。如果實在不想看、看不懂,那就翻譯一下嘛。麻利給你一個翻譯網址吧,免得你嘀咕我……谷歌翻譯

    【搭建框架】

    有了項目需求,那么接下來就是搭建框架了。按照項目需求,咱們把框架立起來。

    class BaseItem(Sprite):passclass MainGame:passclass Tank(BaseItem):passclass OurTank(Tank):passclass EnemyTank(Tank):passclass Bullet(BaseItem):passclass Wall(BaseItem):passclass Explosion:passclass Music:pass

    【完善MainGame類】

    這個類主要功能是:

    • 啟動游戲窗口
    • 顯示部分文本信息
    • 實時檢測按鍵并做出響應
    • 結束游戲

    先導入這些模塊的方法:

    from time import sleep from pygame import display from pygame import Color

    首先設置窗口大小及背景顏色:

    SCREEN_WIDTH = 700 SCREEN_HEIGHT = 500 BG_COLOR = Color(0, 0, 0)

    完善MainGame類:

    class MainGame:window = Nonedef __init__(self):passdef startGame(self):display.init()MainGame.window = display.set_mode(size=[SCREEN_WIDTH, SCREEN_HEIGHT])display.set_caption("Tank War 1.0")while True:sleep(0.002)MainGame.window.fill(color=BG_COLOR)display.update()

    在所有代碼最下方添加:

    if __name__ == "__main__":my_game = MainGame()my_game.startGame()

    運行截圖:

    啊!點擊關閉不管用,還卡死……別慌,沒完呢。

    繼續導入以下模塊的方法:

    from sys import exit from pygame import event from pygame import QUIT from pygame import quit

    在MainGame類里添加gameOver方法:

    @staticmethod def gameOver():quit()exit()

    在MainGame類里添加getEvent方法:

    def getEvent(self):for e in event.get():if e.type == QUIT:self.gameOver()

    在MainGame類的startGame方法中的while循環中添加一句:

    self.getEvent()

    所以MainGame類變成了:

    class MainGame:window = Nonedef __init__(self):passdef startGame(self):display.init()MainGame.window = display.set_mode(size=[SCREEN_WIDTH, SCREEN_HEIGHT])display.set_caption("Tank War 1.0")while True:sleep(0.002)MainGame.window.fill(color=BG_COLOR)self.getEvent()display.update()@staticmethoddef gameOver():quit()exit()def getEvent(self):for e in event.get():if e.type == QUIT:self.gameOver()

    運行截圖:

    這下可以關閉啦~嘿嘿,就是這么皮……

    不過,黑乎乎的,啥也不是……接著往下搞。

    【完善BaseItem類】

    問題來了,這個類是干嘛用的呢?哎,我告訴你,這個類是用來檢測是否發生碰撞(坦克與坦克、坦克與子彈、坦克與墻壁)。原理是什么呢,請移步pygame官方文檔查看pygame.sprite的相關內容,這里就不展開說了哈。

    繼續導入以下模塊的方法:

    from pygame.sprite import Sprite from pygame.sprite import AbstractGroup

    補充BaseItem類:

    class BaseItem(Sprite):def __init__(self, *groups: AbstractGroup):super().__init__(*groups)

    【完善Tank類】

    坦克有四個方向:上下左右

    UP = 1 DOWN = 2 LEFT = 3 RIGHT = 4

    還有速度:

    SPEED = 1

    由于Tank類是OurTank類和EnemyTank類的父類,所以具體構造方法稍后講解。

    在Tank類里添加displayTank方法:

    def displayTank(self):self.my_image = self.images.get(self.direction, None)MainGame.window.blit(source=self.my_image, dest=self.rect)

    此時Tank類為:

    class Tank(BaseItem):UP = 1DOWN = 2LEFT = 3RIGHT = 4SPEED = 1def __init__(self, *groups: AbstractGroup):super().__init__(*groups)self.images = {}self.direction = Tank.UPself.my_image = Noneself.rect = Noneself.move_switch = Noneself.bullets = []def displayTank(self):self.my_image = self.images.get(self.direction, None)MainGame.window.blit(source=self.my_image, dest=self.rect)

    先別運行哈,還沒完善OurTank類呢。

    【完善OurTank類】

    導入以下模塊的方法:

    from pygame import image

    在OurTank類里添加屬性,我方坦克陣營及其數量:

    tanks = [] count = 0

    先簡單點,設定我方坦克陣營只有一個坦克。考慮到我方坦克的無限復活,應該設置單例模式。單例模式的介紹以及python3的實現這里就不展開了,提供學習單例模式的參考文章:Python單例模式(Singleton)的N種實現

    在OurTank類里添加屬性:

    __obj = None __init_flag = True

    在OurTank類里添加__new__方法:

    def __new__(cls, *args, **kwargs):if cls.__obj is None:cls.__obj = object.__new__(cls)return cls.__obj

    在OurTank類里添加__init__方法:

    def __init__(self, left, top):super().__init__()if OurTank.__init_flag:OurTank.__init_flag = False

    加載我方陣營的坦克的圖片,由于方向有四個,對應就有四個圖片。在OurTank類里的__init__方法中添加:

    注意

  • img文件夾是從坦克大戰素材解壓出來的,注意你的路徑問題,我用的是相對路徑,建議你使用絕對路徑。

  • 想要使用你自己的素材也可以,但圖片后綴必須是.gif,否則會出問題。

  • self.images = {Tank.UP: image.load(r"img/p1tankU.gif"),Tank.DOWN: image.load(r"img/p1tankD.gif"),Tank.LEFT: image.load(r"img/p1tankL.gif"),Tank.RIGHT: image.load(r"img/p1tankR.gif"), }

    在OurTank類里的__init__`方法中繼續添加:

    self.my_image = self.images[self.direction] self.rect = self.my_image.get_rect() self.rect.left = left self.rect.top = top OurTank.count += 1 OurTank.tanks.append(self)

    自上往下分別表示:

    • 加載默認方向對應的圖片
    • 獲取圖片的rect屬性
    • 設置圖片相對于窗口左端的位置
    • 設置圖片相對于窗口頂端的位置
    • 我方坦克陣營的數量加一
    • 我方坦克陣營的對象列表增一

    此時,OurTank類的__init__方法為:

    def __init__(self, left, top):super().__init__()if OurTank.__init_flag:OurTank.__init_flag = Falseself.images = {Tank.UP: image.load(r"img/p1tankU.gif"),Tank.DOWN: image.load(r"img/p1tankD.gif"),Tank.LEFT: image.load(r"img/p1tankL.gif"),Tank.RIGHT: image.load(r"img/p1tankR.gif"),}self.my_image = self.images[self.direction]self.rect = self.my_image.get_rect()self.rect.left = leftself.rect.top = topOurTank.count += 1OurTank.tanks.append(self)

    【完善Tank類】

    接下來,要考慮在游戲窗口生成我方陣營的坦克,我們使用隨機位置生成坦克。由于位置是隨機的,無法保證多個坦克圖片之間不重合,因此,需要檢測坦克是否發生碰撞。(我們這里認為,重合即碰撞)

    導入以下模塊的方法:

    from inspect import getmro from pygame.sprite import collide_rect

    在Tank類里添加isCollide方法:

    def isCollide(self, collided_type):if "Tank" in [i.__name__ for i in getmro(cls=collided_type)]:for tank in collided_type.tanks:if tank != self and collide_rect(tank, self):return Truereturn Falseelse:return False

    【完善MainGame類】

    導入以下模塊的方法:

    from random import randint

    在MainGame類里的startGame方法中,在display.set_caption("Tank War 1.0")下一行添加:

    while OurTank.count < 1:OurTank(randint(60, 640), randint(60, 440))if OurTank.tanks[-1].isCollide(OurTank):OurTank.tanks.pop()OurTank.count -= 1

    在MainGame類里的startGame方法中,在MainGame.window.fill(color=BG_COLOR)下一行添加:

    for tank in OurTank.tanks:tank.displayTank()

    此時,MainGame類里的startGame方法為:

    def startGame(self):display.init()MainGame.window = display.set_mode(size=[SCREEN_WIDTH, SCREEN_HEIGHT])display.set_caption("Tank War 1.0")while OurTank.count < 1:OurTank(randint(60, 640), randint(60, 440))if OurTank.tanks[-1].isCollide(OurTank):OurTank.tanks.pop()OurTank.count -= 1while True:sleep(0.002)MainGame.window.fill(color=BG_COLOR)for tank in OurTank.tanks:tank.displayTank()self.getEvent()display.update()

    運行截圖:

    可能你的坦克位置不一樣,不要緊,因為是隨機位置嘛~而且每次運行后,位置會發生隨機變化哦……

    【完善MainGame類】

    話說,有圖也沒啥,得能動啊……

    我們玩這個游戲,肯定要用到鍵盤,習慣呢,是“上下左右”鍵,也就是Up、Down、Left、Right鍵,于是,我們需要回到MainGame類。為啥?我們按下鍵,希望得到對應的響應,誰來檢測呢?還是我們的getEvent方法,回到MainGame類。

    導入以下模塊的方法:

    from pygame import KEYDOWN from pygame import K_LEFT from pygame import K_RIGHT from pygame import K_UP from pygame import K_DOWN from pygame import KEYUP

    在MainGame類里的getEvent方法中,在if e.type == QUIT: self.gameOver()下一行(與if e.type == QUIT并列)添加:

    if e.type == KEYDOWN:if (e.key == K_UP ore.key == K_DOWN ore.key == K_LEFT ore.key == K_RIGHT):for tank in OurTank.tanks:tank.move_switch = e.key if e.type == KEYUP:if (e.key == K_UP ore.key == K_DOWN ore.key == K_LEFT ore.key == K_RIGHT):for tank in OurTank.tanks:tank.move_switch = None

    到此,我們的按鍵就設置好了,接著安排按鍵對應的響應。

    【完善Tank類】

    在Tank類里添加moveTank方法,考慮四個方向哦:

    def moveTank(self, my_key):if my_key == K_UP:self.direction = self.UPif self.rect.top > 0:self.rect.top -= 1if not self.isCollide(OurTank):self.rect.top += 1self.rect.top -= self.SPEEDelse:self.rect.top += 1elif my_key == K_DOWN:self.direction = self.DOWNif self.rect.top < SCREEN_HEIGHT - self.rect.height:self.rect.top += 1if not self.isCollide(OurTank):self.rect.top -= 1self.rect.top += self.SPEEDelse:self.rect.top -= 1elif my_key == K_LEFT:self.direction = self.LEFTif self.rect.left > 0:self.rect.left -= 1if not self.isCollide(OurTank):self.rect.left += 1self.rect.left -= self.SPEEDelse:self.rect.left += 1elif my_key == K_RIGHT:self.direction = self.RIGHTif self.rect.left < SCREEN_WIDTH - self.rect.width:self.rect.left += 1if not self.isCollide(OurTank):self.rect.left -= 1self.rect.left += self.SPEEDelse:self.rect.left -= 1

    那么多的if是干嘛用的?其實是要保證坦克不會走出窗口、不會與我方陣營其他坦克相撞(如果有的話)。

    【完善MainGame類】

    按鍵的響應也做好了,那么就可以往主窗口添加啦。

    在MainGame類里的startGame方法中,在while True循環中的self.getEvent()下一行添加:

    for tank in OurTank.tanks:tank.moveTank(tank.move_switch)

    運行截圖:

    我就不上動圖了哈,不過,嘿嘿,你的坦克一定是在你的控制下亂跑,高興不?點個贊唄先~

    【完善EnemyTank類】

    一個坦克總是孤零零的……那就多加幾個唄~

    咱們給它添加個敵方陣營的坦克,6個吧,多點熱鬧。

    來到我們的EnemyTank類,添加幾個屬性:

    tanks = [] count = 0

    眼熟不?是的,前面寫OurTank類的時候,也添加了這兩個屬性,意思差不多,陣營不一樣而已。

    在EnemyTank類里添加__init__方法:

    def __init__(self, left, top):super().__init__()self.images = {Tank.UP: image.load(r"img/enemy1U.gif"),Tank.DOWN: image.load(r"img/enemy1D.gif"),Tank.LEFT: image.load(r"img/enemy1L.gif"),Tank.RIGHT: image.load(r"img/enemy1R.gif"),}self.direction = randint(1, 4)self.my_image = self.images[self.direction]self.rect = self.my_image.get_rect()self.rect.left = leftself.rect.top = topEnemyTank.count += 1EnemyTank.tanks.append(self)

    跟OurTank類的__init__方法差不多,只有self.direction = randint(1, 4)這里不一樣,隨機生成敵方坦克的初始方向。

    然后我們就可以在游戲窗口添加敵方陣營的坦克啦~

    【完善MainGame類】

    在MainGame類里的startGame方法中,在while True的上一行添加:

    while EnemyTank.count < 6:EnemyTank(randint(60, 640), randint(60, 220))if EnemyTank.tanks[-1].isCollide(EnemyTank):EnemyTank.tanks.pop()EnemyTank.count -= 1

    啊哈,隨機生成了6個敵方陣營的坦克,然后需要顯示出來。在while True循環中,在self.getEvent()的上一行添加:

    for tank in EnemyTank.tanks:tank.displayTank()

    運行截圖:

    哎,這就出來了。敵方陣營的坦克都不動?別急,接著往下看……

    【完善EnemyTank類】

    要想讓敵方陣營的坦克自己動起來,還是隨機性地移動,那么就需要對moveTank方法進行重載。

    在EnemyTank類里添加屬性:

    turn_flag = 0

    在EnemyTank類里添加moveTank方法:

    def moveTank(self, **kwargs):self.turn_flag += 1if self.turn_flag == 150:self.direction = randint(1, 4)self.turn_flag = 0

    這個if干嘛用的?這個是控制敵方陣營的坦克轉向的頻率(游戲窗口更新頻率較快,就是display.update()頻率較快),不要太快也不要太慢,然后就是給它隨機一個方向。

    接下來給它加上“上下左右”四個方向,繼續在EnemyTank類里的moveTank方法里添加:

    if self.direction == self.UP:if self.rect.top > 0:self.rect.top -= 1if not (self.isCollide(OurTank) orself.isCollide(EnemyTank)):self.rect.top += 1self.rect.top -= self.SPEEDelse:self.rect.top += 1 elif self.direction == self.DOWN:if self.rect.top < SCREEN_HEIGHT - self.rect.height:self.rect.top += 1if not (self.isCollide(OurTank) orself.isCollide(EnemyTank)):self.rect.top -= 1self.rect.top += self.SPEEDelse:self.rect.top -= 1 elif self.direction == self.LEFT:if self.rect.left > 0:self.rect.left -= 1if not (self.isCollide(OurTank) orself.isCollide(EnemyTank)):self.rect.left += 1self.rect.left -= self.SPEEDelse:self.rect.left += 1 elif self.direction == self.RIGHT:if self.rect.left < SCREEN_WIDTH - self.rect.width:self.rect.left += 1if not (self.isCollide(OurTank) orself.isCollide(EnemyTank)):self.rect.left -= 1self.rect.left += self.SPEEDelse:self.rect.left -= 1

    這里頭的if語句還是要保證坦克不與其他坦克碰撞、不跑出屏幕范圍。

    【完善MainGame類】

    敵方坦克陣營的移動設置好了,現在讓它們在游戲窗口里動起來。在MainGame類里的startGame中,在while True循環里的display.update()上一行添加:

    for tank in EnemyTank.tanks:tank.moveTank()

    運行截圖:

    很好,所有的坦克都動起來了!不過還有個bug——上面那張圖中,我方陣營的坦克可以主動與敵方坦克重合,我們希望所有的坦克不要重合,那需要修改下Tank類了。

    【完善Tank類】

    找到Tank類里的moveTank方法,將所有的檢測碰撞的語句if not self.isCollide(OurTank):修改為:

    if not (self.isCollide(OurTank) orself.isCollide(EnemyTank) ):

    還沒完呢,先別運行。

    【完善MainGame類】

    在MainGame類里的startGame方法中,修改

    while OurTank.count < 1:OurTank(randint(60, 640), randint(60, 440))if OurTank.tanks[-1].isCollide(OurTank) :OurTank.tanks.pop()OurTank.count -= 1

    為:

    while OurTank.count < 1:OurTank(randint(60, 640), randint(60, 440))if (OurTank.tanks[-1].isCollide(OurTank) orOurTank.tanks[-1].isCollide(EnemyTank)):OurTank.tanks.pop()OurTank.count -= 1

    修改

    while EnemyTank.count < 6:EnemyTank(randint(60, 640), randint(60, 220))if EnemyTank.tanks[-1].isCollide(EnemyTank):EnemyTank.tanks.pop()EnemyTank.count -= 1

    為:

    while EnemyTank.count < 6:EnemyTank(randint(60, 640), randint(60, 220))if (EnemyTank.tanks[-1].isCollide(OurTank) orEnemyTank.tanks[-1].isCollide(EnemyTank)):EnemyTank.tanks.pop()EnemyTank.count -= 1

    然后運行:

    好嘞,這下沒毛病了,誰也不會重合了……

    【完善Wall類】

    光有坦克有點單調了,那就加些墻壁唄。

    給Wall類添加屬性:

    walls = [] count = 0

    在Wall類里添加__init__方法:

    def __init__(self, left, top, *groups: AbstractGroup):super().__init__(*groups)self.image = image.load(r"img/walls.gif")self.rect = self.image.get_rect()self.rect.left = leftself.rect.top = topself.hp = 4Wall.walls.append(self)Wall.count += 1

    細心的你肯定發現,哎,好像多了點什么。是的,咱給墻壁加了個生命值self.hp,也就是說,子彈打到墻壁上,墻壁生命值就減少,最后會被打沒嘍~

    給Wall類添加displayWall方法:

    def displayWall(self):MainGame.window.blit(source=self.image, dest=self.rect)

    然后,咱就在游戲窗口里隨機生成6個墻壁吧。

    【完善MainGame類】

    在MainGame類里的startGame方法中,在while True循環中,在MainGame.window.fill(color=BG_COLOR)下一行添加:

    while Wall.count < 6:Wall(randint(60, 640), randint(60, 440))for tank in EnemyTank.tanks:if Wall.walls and collide_rect(tank, Wall.walls[-1]):Wall.walls.pop()Wall.count -= 1for tank in OurTank.tanks:if Wall.walls and collide_rect(tank, Wall.walls[-1]):Wall.walls.pop()Wall.count -= 1for wall in Wall.walls[:-1]:if Wall.walls and collide_rect(wall, Wall.walls[-1]):Wall.walls.pop()Wall.count -= 1

    這個while循環呢,就保證了每消失一個墻壁,就隨機位置生成一個墻壁。當然,里頭的三個for循環是為了保證生成的墻壁不與其他墻壁、坦克重合。

    接著在游戲窗口顯示生成的墻壁,在下一行(與while Wall.count < 6:并列)添加:

    for wall in Wall.walls:wall.displayWall()

    運行截圖:

    哎,墻壁有了。可問題又來了,坦克可以走過去跟墻壁重合……不慌,修改修改就好。

    【完善Tank類】

    找到Tank類的isCollide方法,在else: return False上一行(與if "Tank" in [i.__name__ for i in getmro(cls=collided_type)]并列)添加:

    elif "Wall" in [i.__name__ for i in getmro(cls=collided_type)]:for wall in collided_type.walls:if collide_rect(wall, self):return Truereturn False

    在Tank類里的moveTank方法中,修改所有的

    if not (self.isCollide(OurTank) orself.isCollide(EnemyTank) ):

    為:

    if not (self.isCollide(Wall) orself.isCollide(OurTank) orself.isCollide(EnemyTank) ):

    同理,還要修改敵方陣營坦克的移動。

    【完善EnemyTank類】

    在EnemyTank類里的moveTank方法中,修改所有的

    if not (self.isCollide(OurTank) orself.isCollide(EnemyTank) ):

    為:

    if not (self.isCollide(Wall) orself.isCollide(OurTank) orself.isCollide(EnemyTank) ):

    運行截圖:

    終于好了,這下坦克沒法穿墻了……

    上子彈!!!咱要殺他個片甲不留!!!

    【完善Bullet類】

    在Bullet類里添加__init__方法:

    def __init__(self, tank, *groups: AbstractGroup):super().__init__(*groups)self.my_image = image.load(r"img/enemymissile.gif")self.direction = tank.directionself.rect = self.my_image.get_rect()

    子彈的初始位置值得思考,我們必須在坦克正前方發射子彈。又考慮到坦克有四個方向,因此,子彈的位置分為四個情況,繼續在Bullet類里的__init__方法里添加:

    if self.direction == Tank.UP:self.rect.left = tank.rect.left + (tank.rect.width / 2) - (self.rect.width / 2)self.rect.top = tank.rect.top - self.rect.height elif self.direction == Tank.DOWN:self.rect.left = tank.rect.left + (tank.rect.width / 2) - (self.rect.width / 2)self.rect.top = tank.rect.top + tank.rect.height elif self.direction == Tank.LEFT:self.rect.left = tank.rect.left - self.rect.widthself.rect.top = tank.rect.top + (tank.rect.height / 2) - (self.rect.height / 2) elif self.direction == Tank.RIGHT:self.rect.left = tank.rect.left + tank.rect.widthself.rect.top = tank.rect.top + (tank.rect.height / 2) - (self.rect.height / 2)

    接著在Bullet類里添加displayBullet方法:

    def displayBullet(self):MainGame.window.blit(source=self.my_image, dest=self.rect)

    我們希望在游戲中,當按下空格的時候,我方陣營的坦克就會發射子彈。

    【完善Tank類】

    在Tank類里添加shooting方法:

    def shooting(self):self.bullets.append(Bullet(self))

    一旦調用shooting,就會在屬于自己的子彈列表里頭增加一顆子彈。

    然后,我們就去做個按鍵處理。

    【完善MainGame類】

    導入以下模塊的方法:

    from pygame import K_SPACE

    在MainGame類里的getEvent方法中,在

    if (e.key == K_UP ore.key == K_DOWN ore.key == K_LEFT ore.key == K_RIGHT):for tank in OurTank.tanks:tank.move_switch = e.key

    下一行(與if并列)添加:

    if e.key == K_SPACE:for tank in OurTank.tanks:tank.shooting()

    在MainGame類里的startGame方法中,在while True:循環中,在display.update()上一行添加:

    for tank in OurTank.tanks:for bullet in tank.bullets:bullet.displayBullet()

    運行截圖:

    哎,每按一次空格,我方陣營的坦克就會發射一顆子彈。

    但是,子彈咋都不動哎???

    哦,對,子彈應該沿著初始方向,直線運動哈……

    【完善Bullet類】

    在Bullet類添加moveBullet方法:

    if (0 <= self.rect.left <= (SCREEN_WIDTH - self.rect.width) and0 <= self.rect.top <= (SCREEN_HEIGHT - self.rect.height)):if self.direction == Tank.UP:self.rect.top -= Tank.SPEED * 2elif self.direction == Tank.DOWN:self.rect.top += Tank.SPEED * 2elif self.direction == Tank.LEFT:self.rect.left -= Tank.SPEED * 2elif self.direction == Tank.RIGHT:self.rect.left += Tank.SPEED * 2

    意思是,只要子彈被發射出去,就會一直以2倍坦克的移動速度直線移動。

    然后在Bullet類的displayBullet方法中,在MainGame.window.blit(source=self.my_image, dest=self.rect)上一行添加:

    self.moveBullet()

    運行截圖:

    害,子彈沒毛病,發射出去了……

    還有三個小問題:

    • 在游戲邊界不消失
    • 打不了敵方陣營坦克
    • 穿墻

    咱逐一解決哈……

    【完善MainGame類】

    子彈在邊界處消失,就需要遍歷下所有我方陣營坦克的子彈,只要到達邊界處,就刪掉該子彈。

    在MainGame中的startGame方法中,在while True:循環中,在display.update()上一行添加:

    for tank in OurTank.tanks:if tank.bullets:if not (0 <= tank.bullets[0].rect.left <=(SCREEN_WIDTH - tank.bullets[0].rect.width) and0 <= tank.bullets[0].rect.top <=(SCREEN_HEIGHT - tank.bullets[0].rect.height)):tank.bullets = tank.bullets[1:]

    運行截圖:

    這下就看到,子彈到了邊界就消失啦……

    再解決子彈消滅敵人和打碎墻壁這兩個問題。

    【完善Bullet類】

    在Bullet類里添加isCollide方法,思路與Tank類里的isCollide方法類似:

    def isCollide(self, collided_type):if "Tank" in [i.__name__ for i in getmro(cls=collided_type)]:for tank in collided_type.tanks:if collide_rect(tank, self):collided_type.tanks.remove(tank)del tankcollided_type.count -= 1return Truereturn Falseelif "Wall" in [i.__name__ for i in getmro(cls=collided_type)]:for wall in collided_type.walls:if collide_rect(wall, self):if wall.hp > 1:wall.hp -= 1return Trueelse:collided_type.walls.remove(wall)del wallcollided_type.count -= 1return Truereturn Falseelse:return False

    設置好后,需要在游戲窗口實時檢測是否發生碰撞。

    【完善MainGame類】

    在MainGame類里的startGame方法中,在while True:循環中,在

    for tank in OurTank.tanks:for bullet in tank.bullets:bullet.displayBullet()

    下一行(與bullet.displayBullet()并列)添加:

    if bullet.isCollide(EnemyTank) or bullet.isCollide(Wall):tank.bullets.remove(bullet)

    運行截圖:

    我就不上動圖啦,相信你可以發現,子彈打中坦克,坦克就消失了;子彈打四次墻壁,墻壁也消失了。高興不,到這里,你已經里成功不遠啦!!!

    接著給敵方陣營的坦克上子彈,讓它們隨機發射子彈。

    在MainGame類里的startGame方法中,在while True:循環中,在

    for tank in EnemyTank.tanks:tank.moveTank()

    下一行(與for循環并列)添加:

    for enemy_tank in EnemyTank.tanks:if randint(1, 2000) <= 10:enemy_tank.shooting()

    用來隨機發射敵方子彈。接著在MainGame類里的startGame方法中,在while True:循環中,在

    for tank in OurTank.tanks:for bullet in tank.bullets:bullet.displayBullet()if bullet.isCollide(EnemyTank) or bullet.isCollide(Wall):tank.bullets.remove(bullet)

    下一行(與for tank in并列)添加:

    for tank in EnemyTank.tanks:for bullet in tank.bullets:bullet.displayBullet()if bullet.isCollide(OurTank) or bullet.isCollide(Wall):tank.bullets.remove(bullet)

    到此,敵方坦克的子彈就顯示出來了。

    運行截圖:

    沒錯,哈哈哈哈,它把我方陣營給打沒了……

    不過,子彈到了邊界沒消失掉,沒關系,跟處理我方陣營的子彈差不多,在MainGame類里的startGame方法中,在while True:循環中,在display.update()上一行添加:

    for tank in EnemyTank.tanks:if tank.bullets:if not (0 <= tank.bullets[0].rect.left <=(SCREEN_WIDTH - tank.bullets[0].rect.width) and0 <= tank.bullets[0].rect.top <=(SCREEN_HEIGHT - tank.bullets[0].rect.height)):tank.bullets = tank.bullets[1:]

    運行截圖:

    這下子彈都沒問題啦!

    不過,嗚嗚嗚嗚,我方陣營死得太慘了……剛出來就被打死……我要無限復活!!!無限復活!!!

    安排,一般按下r鍵就可以復活,那就需要再添加點東西。

    導入以下模塊的方法:

    from pygame import K_r

    在MainGame類里的getEvent方法中,在

    if e.key == K_SPACE:for tank in OurTank.tanks:tank.shooting()

    下一行(與if并列)添加:

    if OurTank.count == 0 and e.key == K_r:OurTank(randint(60, 640), randint(60, 220))while (OurTank.tanks[-1].isCollide(Wall) orOurTank.tanks[-1].isCollide(EnemyTank)):OurTank.tanks.pop()OurTank.count -= 1OurTank(randint(60, 640), randint(60, 220))

    運行截圖:

    嘿嘿,無限復活,這下不怕死了!!!

    不過,我現在想在屏幕上顯示當前敵方陣營坦克的數量,怎么辦?

    來,接著往下看……

    在class BaseItem(Sprite):上一行添加:

    FONT_COLOR = Color(255, 255, 0)

    導入以下模塊的方法:

    from pygame import font

    在MainGame類中添加setTextSurface方法:

    @staticmethod def setTextSurface(text):font.init()my_font = font.SysFont(name="Times New Roman", size=18)text_surface = my_font.render(text, True, FONT_COLOR)return text_surface

    MainGame類里的startGame方法中,在while True:循環中,在MainGame.window.fill(color=BG_COLOR)下一行添加:

    MainGame.window.blit(source=self.setTextSurface("Enemy tanks: {0}.".format(EnemyTank.count)),dest=(10, 10) )

    運行截圖:

    哈哈,完美!!!

    完了嘛?沒有,這應該有爆炸效果吧……來,繼續添加爆炸效果。

    【完善Explosion類】

    在Explosion類里添加屬性:

    explosion = []

    在Explosion類里添加__init__方法:

    def __init__(self, bullet):self.rect = bullet.rectself.rect.left -= 40self.rect.top -= 40del bulletself.images = [image.load(r"img/blast1.gif"),image.load(r"img/blast2.gif"),image.load(r"img/blast3.gif"),image.load(r"img/blast4.gif"),image.load(r"img/blast5.gif"),image.load(r"img/blast6.gif"),image.load(r"img/blast7.gif"),image.load(r"img/blast8.gif"),]self.step = 0Explosion.explosion.append(self)

    爆炸呢,是從小圖片到大圖片依次切換出來的,所以有多張圖片。在Explosion類里添加displayExplosion方法:

    def displayExplosion(self):if self.step < 8:MainGame.window.blit(source=self.images[self.step], dest=self.rect)self.step += 1return Trueelse:return False

    然后需要在子彈與墻壁和坦克碰撞時發生爆炸,于是……

    【完善MainGame類】

    在MainGame類里的startGame方法中,在while True:循環中,在

    for tank in OurTank.tanks:for bullet in tank.bullets:bullet.displayBullet()if bullet.isCollide(EnemyTank) or bullet.isCollide(Wall):tank.bullets.remove(bullet)

    下一行(與tank.bullets.remove(bullet)并列)添加:

    Explosion(bullet=bullet)

    同理,在MainGame類里的startGame方法中,在while True:循環中,在

    for tank in EnemyTank.tanks:for bullet in tank.bullets:bullet.displayBullet()if bullet.isCollide(OurTank) or bullet.isCollide(Wall):tank.bullets.remove(bullet)

    下一行(與tank.bullets.remove(bullet)并列)添加:

    Explosion(bullet=bullet)

    在下一行(與for tank in EnemyTank.tanks:并列)添加:

    for explosion in Explosion.explosion:if not explosion.displayExplosion():Explosion.explosion.remove(explosion)del explosion

    運行截圖:

    終于截到爆炸時候的圖了……我太難了!!!

    好了,到這里就基本完成了,不過還少個音樂效果是吧,這簡單,來。

    【完善Music類】

    導入以下模塊的方法:

    from pygame.mixer import init from pygame.mixer import music

    在Music類里添加__init__方法:

    def __init__(self, filename):self.filename = filenameinit()music.load(self.filename)

    在Music類里添加playMusic方法:

    @staticmethod def playMusic():music.play()

    想了下,有這么幾個聲音需要添加:

    • 游戲開始聲音
    • 子彈發射聲音
    • 子彈爆炸聲音
    • 我方陣營坦克復活聲音

    好,挨個挨個添加……

    【完善Explosion類】

    在Explosion類里的displayExplosion方法中,在else里第一行添加:

    Music(r"img/blast.wav").playMusic()

    【完善MainGame類】

    在MainGame類里的getEvent方法中,在

    if OurTank.count == 0 and e.key == K_r:OurTank(randint(60, 640), randint(60, 220))while (OurTank.tanks[-1].isCollide(Wall) orOurTank.tanks[-1].isCollide(EnemyTank)):OurTank.tanks.pop()OurTank.count -= 1OurTank(randint(60, 640), randint(60, 220))

    的下一行(與while并列)添加:

    Music(r"img/add.wav").playMusic()

    在MainGame類里的getEvent方法中,在

    if e.key == K_SPACE:for tank in OurTank.tanks:tank.shooting()

    的下一行(與tank.shooting()并列)添加:

    Music(r"img/fire.wav").playMusic()

    在MainGame類里的startGame方法中,在display.set_caption("Tank War 1.0")下一行添加:

    Music(r"img/start.wav").playMusic()

    運行,大功告成!!!!!!!

    好激動!!!!!!恭喜你,學會了如何復現坦克大戰!!!!

    寫博客太不容易了,希望有心的你,點個贊~~~

    評論可不要捧我喲,畢竟是小白,咱確實沒那資格。

    有什么問題,記得私聊我哈,我會盡力幫助你的。

    usic.load(self.filename)

    在Music類里添加playMusic方法:

    @staticmethod def playMusic():music.play()

    想了下,有這么幾個聲音需要添加:

    • 游戲開始聲音
    • 子彈發射聲音
    • 子彈爆炸聲音
    • 我方陣營坦克復活聲音

    好,挨個挨個添加……

    【完善Explosion類】

    在Explosion類里的displayExplosion方法中,在else里第一行添加:

    Music(r"img/blast.wav").playMusic()

    【完善MainGame類】

    在MainGame類里的getEvent方法中,在

    if OurTank.count == 0 and e.key == K_r:OurTank(randint(60, 640), randint(60, 220))while (OurTank.tanks[-1].isCollide(Wall) orOurTank.tanks[-1].isCollide(EnemyTank)):OurTank.tanks.pop()OurTank.count -= 1OurTank(randint(60, 640), randint(60, 220))

    的下一行(與while并列)添加:

    Music(r"img/add.wav").playMusic()

    在MainGame類里的getEvent方法中,在

    if e.key == K_SPACE:for tank in OurTank.tanks:tank.shooting()

    的下一行(與tank.shooting()并列)添加:

    Music(r"img/fire.wav").playMusic()

    在MainGame類里的startGame方法中,在display.set_caption("Tank War 1.0")下一行添加:

    Music(r"img/start.wav").playMusic()

    運行,大功告成!!!!!!!

    [外鏈圖片轉存中…(img-hqFAgASO-1647272391768)]

    好激動!!!!!!恭喜你,學會了如何復現坦克大戰!!!!

    寫博客太不容易了,希望有心的你,點個贊~~~

    評論可不要捧我喲,畢竟是小白,咱確實沒那資格。

    有什么問題,記得私聊我哈,我會盡力幫助你的。

    注:完整代碼可私聊我哈。

    總結

    以上是生活随笔為你收集整理的[python3]坦克大战的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。