Python Pygame實戰之紅心大戰遊戲的實現

導語

還記得那些年,我們玩過的Windows小遊戲嗎?

說起Windows自帶的遊戲,相信許多80、90後的朋友都不陌生。

在很早的那個遊戲貧瘠的年代,《紙牌》、《掃雷》等遊戲幫助我們在微機課上帶來瞭許多歡樂的時光。但在這些遊戲中,有一款遊戲似乎玩懂的人,甚至知道玩法的人並不多。這款遊戲就是《紅心大戰》。

最近小編心血來潮仔細鉆研瞭一下之後,發現這款遊戲玩起來卻比其他的幾款遊戲更帶感一些。因為這款遊戲的玩法簡單概括就是兩個字:“坑人”,而且是明著坑的那種。

那大傢猜到瞭哈——今天跟著木木子一起開啟《紅心大戰》紙牌小遊戲吧!

一、 紅心大戰用戶手冊

1.打開遊戲:雙擊hongxindazhan.py 主程序運行即可!

2.開始遊戲:鍵入玩傢姓名,創建新ID,點確認進入遊戲。

3.遊戲流程:

1)換牌:選擇三張手牌,點擊上方按鈕完成交換;

2)出牌:輪到玩傢出牌時,選擇手牌單擊便可打出。(具體出牌規則詳見附錄)註:當此時機不能打出此牌時,下方提示欄會顯示無法打出原因。

4.統分階段:一輪遊戲過後,會彈出得分表,顯示玩傢和三名電腦每輪積分和總積分,並顯示玩傢當前名次。

5.菜單欄:

1)遊戲欄:新遊戲(F2):單擊開啟新遊戲。得分(F4):單擊顯示得分表。背景音樂:單擊切換音樂開關。選項(F5):單擊修改電腦出牌速度。退出:單擊退出遊戲。

2)幫助欄:規則介紹(F1):單擊顯示簡要規則和獲勝條件。名言:單擊彈出一則名言。

6.背景音樂:更換:可用自己的wav格式音樂重命名為‘m1.wav’替換程序目錄下的同名文件。

二、紅心大戰遊戲規則

1、在玩遊戲前,需要決定莊傢。在電腦中,莊傢坐南。

2、拿到一手牌(共計13張)後,莊傢首先須選出三張牌傳給其他對手。第一局把牌傳給左手邊的玩傢;第二局把牌傳給右手邊的玩傢;第三局把牌傳給坐在對面的玩傢;第四局不傳牌,依此類推。接到莊傢的傳牌後,也需要任意傳回給莊傢三張牌。在電腦中,如要選牌,單擊相應牌張即可。如要取消選定的牌,請再次單擊。

3、抓有梅花2 的玩傢必須首先出梅花2,謂首攻。

4、然後按順時針方向出牌。每位玩傢依次必須跟同花色牌。如果已經沒有與發牌花色相同的牌,則可以出任何一張牌。唯一例外是不能在第一圈牌中出紅桃或黑桃Q(通常稱為“豬”)。註意:出的同一花色牌中最大的牌會贏取這一圈,贏牌的玩傢在下一圈中先出牌。隻有前面出過紅桃以後,才可以拿紅桃領出(除非手中隻剩下紅桃一種花色的牌張)。

5、每一輪遊戲結束時,每張紅心計1 分,“黑桃皇後(豬)”計13 分。遊戲將持續到有人得100 分或更多分或者莊傢退出遊戲時結束。如果在一輪牌中贏得瞭所有的紅心和“黑桃皇後”(稱之為“全收”),則“全收”者得零分,其餘玩傢每人得26 分。該遊戲的得分越低越好。

三、準備中

1)環境安裝

環境安裝 本文用到的運行環境:Python3.7、Pycharm社區版2020、tkinter模塊、部分自帶模塊直接導入不需要安裝。

模塊安裝:

pip install -i pypi.douban.com/simple/ +模塊名 

2)背景選擇最原始的綠色背景。(僅展示背景,其餘圖片比較多不展示)

四、代碼演示

​僅展示主程序源碼。每行代碼都有註釋所以直接展示!

from Tkinter import *
from tkFont import *
import winsound
from tkMessageBox import *
from inner import *
from dialog import *
#遊戲主界面創建
class GameFrame:
    def __init__(self,game,bgimg):#game,Game類對象;bgimg,背景圖片
        self.master = game.root
        #創建畫佈,繪制背景
        self.c = Canvas(self.master,width = 1024,height = 640)
        self.c.create_image(514,322,image=bgimg)
        self.c.pack()
        #創建狀態條
        self.status = Label(self.master,text=" 歡迎參加紅心大戰!",
                            bd=1,relief=SUNKEN,anchor=W)
        self.status.pack(fill = X)
        #打開開始對話框
        startdialog = StartDialog(self.master,"紅心大戰")
        if startdialog.isCancel:
            game.cancel()
        else:
            self.gamemodetext = ['向左傳','向右傳','交叉換牌']
            self.name = [startdialog.name,'西','北','東']
            self.handXY = [[346.5,490,1,0],[20,135,0,1],
                           [586.5,20,-1,0],[913,375,0,-1]]
            self.nameXY = [[-20,130,SE],[0,-20,SW],[91+20,0,NW],[91,130+20,NE]]
            self.middleXY = [[466.5,330],[411,255],[466.5,180],[522,255]]
            self.img = 53 * ['']
            for i in range(52):
                self.img[i] = PhotoImage(file = 'card\\%s.pgm' % (i))
            self.img[52] = PhotoImage(file = 'back.pgm')
            
            self.scorelist = []
            self.cards = []
            self.gamemode = 0
            self.speed = 100
            self.wait = self.speed
            self.isChanging = False
            self.iswait = False
            #繪制名字
            for i in range(4):
                self.c.create_text(self.handXY[i][0]+self.nameXY[i][0],
                                   self.handXY[i][1]+self.nameXY[i][1],
                                   fill = 'white',text = self.name[i],
                                   anchor = self.nameXY[i][2],
                                   font = Font(size=15,weight="bold"))
            #創建手牌
            self.l = 52 * ['']
            for i in range(52):
                self.l[i] = Label(self.master,image=self.img[52],bd = -1)
            for i in range(13):
                self.l[i]['text'] = str(i)
                self.l[i].bind("<Button-1>",self.cardEvent)
            #創建中央牌
            self.ml = 4 * ['']
            for i in range(4):
                self.ml[i] = Label(self.master,image=self.img[52],bd = -1)
            
            self.b = Button(self.master,width=15,command=self.buttonEvent)
            #一輪遊戲開始
            self.oneGameStart()
    def oneGameStart(self):
        #創建Onegame對象,用來獲取出牌信息
        self.onegame = OneGame()
        #獲取玩傢手牌,顯示
        hand = self.onegame.getPlayerHand(0)
        for i in range(13):
            self.l[i]['image'] = self.img[hand[i].id]
        for i in range(4):
            for j in range(13):
                self.moveCard(i,j,0)
        #遊戲模式為0,1,2時進入換牌階段        
        if self.gamemode != 3:
            self.changeHands()
        else:
            self.onegame.changeCards([],3)
            self.isChanging = False
            self.leftCards = 13
            #進入出牌階段,玩傢前的電腦出牌
            self.playpreCards()
    def changeHands(self):
        #換牌階段相應初始化
        self.select = []#所選的牌
        self.isChanging = True
        self.isOK = False
        s = [1,3,2]
        self.status['text'] = ' 請選三張牌傳給'+self.name[s[self.gamemode]]+'。'
        #提示按鈕顯示
        self.b['text'] = self.gamemodetext[self.gamemode]
        self.b.place(x = 460,y = 400)
        self.b['state'] = DISABLED
    def cardEvent(self,event):
        #牌的事件
        #獲取牌的位置
        i = int(event.widget['text'])
        if not self.isChanging:
            #出牌階段的牌事件
            #等待中不出牌
            if self.iswait:
                return
            #出不瞭的牌不出
            if not self.onegame.available(i):
                self.status['text'] = self.onegame.errorString
                return
            self.onegame.playCard(i)
            #所出牌顯示到中央
            event.widget.place_forget()
            self.ml[self.turn]['image'] = event.widget['image']
            self.ml[self.turn].place(x = self.middleXY[0][0],y = self.middleXY[0][1])
            self.turn += 1
            self.leftCards -= 1
            #玩傢後的電腦出牌
            self.iswait = True
            self.playlaterCards()
            self.status['text'] = ' 正在等候……'
            self.wait += 500 + 5 * self.speed
            #等待一段時間後,中央牌清空,玩傢前的電腦出牌
            self.master.after(self.wait,self.playpreCards)
            self.wait = self.speed
        else:
            #換牌階段的牌事件,彈起的落下,落下的彈起
            if not self.isOK:
                if i in self.select:
                    self.select.remove(i)
                    self.moveCard(0,i,0)
                    self.b['state'] = DISABLED
                else:
                    if len(self.select) < 3:
                        self.select.append(i)
                        self.moveCard(0,i,1)
                        if len(self.select) == 3:
                            self.b['state'] = NORMAL
    def buttonEvent(self):
        #提示按鈕事件
        if not self.isOK:
            #換牌前獲取電腦換的牌進行交換
            self.select = self.onegame.changeCards(self.select,self.gamemode)
            hand = self.onegame.getPlayerHand(0)
            for i in range(13):
                self.l[i]['image'] = self.img[hand[i].id]
                self.moveCard(0,i,0)
            for i in self.select:
                self.moveCard(0,i,1)
            self.status['text'] = ' 請按"確定"接受傳來的牌。'
            self.b['text'] = '確定'
            self.isOK = True
        else:
            #換牌後進行確認,進入出牌階段,玩傢前的電腦出牌
            for i in self.select:
                self.moveCard(0,i,0)
            self.b.place_forget()
            self.isChanging = False
            self.leftCards = 13
            self.playpreCards()
    def playpreCards(self):
        if self.leftCards == 0:
            #牌出完瞭進行統分,顯示得分對話框
            for i in range(4):
                hand = self.onegame.p[i].scoreHand
                for j in range(len(hand)):
                    self.l[i*13+j]['image'] = self.img[hand[j].id]
                    self.moveCard(i,j,0)
            score = self.onegame.getScore()
            self.scorelist.append(score)
            if len(self.scorelist) != 1:
                for i in range(4):
                    self.scorelist[-1][i] += self.scorelist[-2][i]
            self.status['text'] = ' 得分'
            scoredialog = self.showScoreDialog()
            #得分確認後初始化,開始新一輪遊戲
            if scoredialog.isover:
                self.scorelist = []
                self.gamemode = 0
            else:
                self.gamemode = (self.gamemode + 1) % 4
            for i in range(52):
                self.l[i].place_forget()
                self.l[i]['image'] = self.img[52]
            for i in range(4):
                self.ml[i].place_forget()
            self.oneGameStart()
        else:
            #獲取玩傢之前的電腦出牌,進行顯示
            for i in range(4):
                self.ml[i].place_forget()
            self.turn = 0
            preCards = self.onegame.preCard
            if len(preCards) == 0:
                self.end()
            else:
                for i in range(len(preCards)):
                    p,j = preCards[i][0],preCards[i][1]
                    self.cards.append([self.turn,p,j])
                    self.master.after(self.wait,self.showMiddleCard)
                    if p == 3:
                        self.master.after(self.wait,self.end)
                        self.wait = self.speed
                    else:
                        self.wait += self.speed
                    self.turn += 1
    def playlaterCards(self):
        #獲取玩傢之後的電腦出牌,進行顯示
        laterCards = self.onegame.laterCard
        for i in range(len(laterCards)):
            p,j = laterCards[i][0],laterCards[i][1]
            self.cards.append([self.turn,p,j])
            self.master.after(self.wait,self.showMiddleCard)
            self.wait += self.speed
            self.turn += 1
    def moveCard(self,i,j,state):#i,玩傢;j,第幾張牌;state,彈起還是放下
        #牌的移動
        self.l[i*13+j].place_forget()
        x0 = self.handXY[i][0] + self.handXY[i][2]*j*20
        y0 = self.handXY[i][1] + self.handXY[i][3]*j*20
        self.l[i*13+j].place(x = x0,y = y0 - state * 20)
    def newGame(self):
        #新遊戲
        self.scorelist = []
        self.gamemode = 0
        for i in range(52):
                self.l[i].place_forget()
                self.l[i]['image'] = self.img[52]
        for i in range(4):
            self.ml[i].place_forget()
        self.oneGameStart()
    def showScoreDialog(self):
        #顯示分數對話框
        scoredialog = ScoreDialog(self.master,self.scorelist,self.name)
        return scoredialog
    def showMiddleCard(self):
        #中央牌顯示
        i = self.cards[0][0]
        p = self.cards[0][1]
        j = self.cards[0][2]
        del self.cards[0]
        self.l[p*13+j].place_forget()
        hand = self.onegame.getPlayerHand(p)
        self.ml[i]['image'] = self.img[hand[j].id]
        self.ml[i].place(x = self.middleXY[p][0],
                         y = self.middleXY[p][1])
    def end(self):
        #電腦出完牌至玩傢出牌的切換
        self.iswait = False
        self.status['text'] = ' 請出一張牌。'

#遊戲窗口創建,並建立遊戲菜單項
class Game:
    def __init__(self):
        #建立根窗口,設置
        self.root = Tk()
        self.root.title("紅心大戰")
        self.root.geometry('+150+10')
        self.root.resizable(False, False)
        #播放背景音樂
        self.s = winsound.PlaySound('m1.wav',
                                    winsound.SND_ASYNC+winsound.SND_LOOP)
        #建立菜單
        m = Menu(self.root)
        self.root['menu'] = m
        gamemenu = Menu(m)
        helpmenu = Menu(m)
        m.add_cascade(label = '遊戲',menu = gamemenu)
        m.add_cascade(label = '幫助',menu = helpmenu)
        gamemenu.add_command(label="新遊戲     F2",command = self.gameEvent1)
        gamemenu.add_separator()
        gamemenu.add_command(label="得分...    F4",command = self.gameEvent2)
        gamemenu.add_command(label="選項...    F5",command = self.gameEvent4)
        self.v = IntVar()
        self.v.set(1)
        gamemenu.add_checkbutton(label="背景音樂",variable = self.v,
                                 command = self.gameEvent3)
        gamemenu.add_separator()
        gamemenu.add_command(label="退出",command = self.cancel)
        helpmenu.add_command(label="規則介紹...    F1",command = self.helpEvent1)
        helpmenu.add_command(label="名言...",command = self.helpEvent2)

        self.root.bind('<F2>',self.gameEvent1)
        self.root.bind('<F4>',self.gameEvent2)
        self.root.bind('<F5>',self.gameEvent4)
        self.root.bind('<F1>',self.helpEvent1)
        self.root.protocol("WM_DELETE_WINDOW",self.cancel)
        #導入背景圖片
        bgimg = PhotoImage(file = 'bg.gif')
        #創建主界面
        self.frame = GameFrame(self,bgimg)
        #主循環
        self.root.mainloop()
    def gameEvent1(self,event=None):
        #遊戲菜單項”新遊戲“
        flag = askokcancel('新遊戲','你確定要放棄當前遊戲開始新遊戲麼?')
        if flag:
            self.frame.newGame()
    def gameEvent2(self,event=None):
        #遊戲菜單項”得分“
        self.frame.showScoreDialog()
    def gameEvent3(self):
        #遊戲菜單項”背景音樂“
        if self.v.get() == 0:
            winsound.PlaySound(self.s,winsound.SND_PURGE)
        else:
            self.s = winsound.PlaySound('m1.wav',
                                    winsound.SND_ASYNC+winsound.SND_LOOP)
    def gameEvent4(self,event=None):
        #遊戲菜單項”選項“
        optionDialog = OptionDialog(self.root,self.frame.speed / 100 - 1)
        if not optionDialog.isCancel:
            self.frame.speed = 100 + optionDialog.v.get() * 100
    def helpEvent1(self,event=None):
        #幫助菜單項”規則介紹“
        HelpDialog(self.root)
    def helpEvent2(self):
        #幫助菜單項”名言“
        SayDialog(self.root)
    def cancel(self):
        #關閉音樂,退出遊戲
        winsound.PlaySound(self.s,winsound.SND_PURGE)
        self.root.destroy()

       
def main():
    Game()

    
if __name__ == '__main__': 
    main()

五、效果展示

1)遊戲開始

2)遊戲界面

​3)左上角幫助菜單

4)遊戲結束排名

到此這篇關於Python Pygame實戰之紅心大戰遊戲的實現的文章就介紹到這瞭,更多相關Python Pygame 紅心大戰內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: