Pygame 实战(行动代号(单机版)):(二). 游戏编程
當(dāng)前系列歷史文章:
- Pygame 實戰(zhàn)(行動代號(單機版)):(一). 游戲簡介
這一部分就開始講實現(xiàn)的代碼啦!因為之前寫代碼的時候沒什么經(jīng)驗,所以可能有不少冗余的部分和可以簡化的地方命名也不是很規(guī)范,歡迎大家討論交流和改進。
這一部分代碼并不適合Pygame初學(xué)者,所以如果對Pygame還不熟的人可以自行學(xué)習(xí)一下基本的 Surface, Rect, Sprite, SpriteGroup,event等等,這些資源在網(wǎng)上有好多我就不一一敘說了,當(dāng)然有什么問題也是可以向我提問噠~
廢話不多說,直接開始講吧。
目錄
1. 游戲?qū)崿F(xiàn)
1.1. 代碼設(shè)計
1.1.1. 展示部分
游戲demo
1.1.2. 代號(命名)設(shè)計
1.2. 功能實現(xiàn)
Button
ButtonKeyboard
CardButton
初始化詞和顏色布局
1.3. 主程序
1.4. 運行程序
1. 游戲?qū)崿F(xiàn)
1.1. 代碼設(shè)計
其實也算不上什么設(shè)計啦,就是跟大家講講主要的一些思路。
1.1.1. 展示部分
游戲主要的界面應(yīng)該用于顯示25個卡牌?CardButton,我們稱這個區(qū)域為為 area_cards;
在游戲開始前,我們有兩個功能按鈕 Button 分別用于用于換詞和開始游戲,這兩個按鈕我們將放在?prepare_btn_grp?中;
游戲開始后,我們在顯示卡牌的區(qū)域下顯示一些游戲狀態(tài)信息,我們稱這個區(qū)域為 area_tips;
游戲開始后,每一方回合開始時,需要隊長說出一個詞和一個數(shù)量,這一數(shù)量需要輸入到游戲中,以便我們的游戲程序可以正常的實施游戲規(guī)則邏輯,輸入數(shù)量時我們用顯示1到9的9個按鈕 ButtonKeyboard 輔助輸入,這些按鈕放在?input_card_grp?中
游戲demo
以下是一些實際截圖
準(zhǔn)備時
游戲開始隊長選擇此輪猜詞個數(shù)
猜詞階段
游戲結(jié)束
?
1.1.2. 代號(命名)設(shè)計
因為游戲中我們將分為紅藍(lán)兩隊,卡牌有黑、黃、藍(lán)、紅四個顏色,于是我們分別用 id = 0,1,2,3帶指這四個顏色,當(dāng) id = 2 時游戲信息顯示中對應(yīng)“藍(lán)方”,id = 3時游戲信息顯示中對應(yīng)“紅方”
ID_COLOR = {0: (0, 0, 0), 1: (255, 255, 0), 2: (0, 0, 255), 3: (255, 0, 0)} ID_TIPS = {2: '藍(lán)方', 3: '紅方'}游戲有三個狀態(tài),一個是開始前的準(zhǔn)備階段?phase_prepare ,一個是開始后的游戲階段?phase_gaming ,和一個一整盤游戲是否結(jié)束的狀態(tài)?game_over
# 初始時的狀態(tài)初始值 phase_prepare = True phase_gaming = False game_over = False開始游戲后,第一個回合的隊伍對應(yīng) begin_id, 當(dāng)前隊伍對應(yīng) now, 我們用 DISCOVERED 代表當(dāng)前沒展示顏色的卡牌數(shù)量,方便?area_tips?中的信息展示
DISCOVERED = {0: 1, 1: 7, begin_id: 9, 2 if begin_id == 3 else 3: 8} # 初始化DISCOVERED1.2. 功能實現(xiàn)
這一小部門講講上面提到的各類按鈕如何實現(xiàn). 先來一個基本的按鈕類
Button
class Button(py.sprite.Sprite):def __init__(self, text, font=None, size=(100, 40), position=(0, 0), id=None, name=None, text_color=(0, 0, 0),clicked_color=(192, 192, 192), bg_color=(255, 255, 255), shadow_color=(0, 0, 0), shadow=True):''':param text: 文本:param font: 字體:param size: 大小:param position: 位置:param id: id:param name: 按鈕名:param text_color: 文本顏色:param clicked_color: 點擊時背景顏色:param bg_color: 背景顏色:param shadow_color: 邊框顏色:param shadow: 是否有邊框'''py.sprite.Sprite.__init__(self)self.id = idself.name = nameself.width, self.height = sizeself.text_color = text_colorself.bg_color = bg_colorself.clicked_color = clicked_colorself.shadow_color = shadow_colorself.shadow = shadowself.clicked = Falseself.text = textself.font = fontself.load(text, font=font, position=position)def _set_pos(self, pos):self.rect.topleft = posdef _get_pos(self):return self.rect.topleftdef _set_x(self, x):self.rect.x = xdef _get_x(self):return self.rect.xdef _set_y(self, y):self.rect.y = ydef _get_y(self):return self.rect.yposition = property(_get_pos, _set_pos)x = property(_get_x, _set_x)y = property(_get_y, _set_y)def load(self, text, font=None, position=(0, 0)):# 渲染按鈕圖片if not font:self.font = py.font.Font(None, 20)else:self.font = fontself.rect = Rect(position[0], position[1], self.width, self.height)image_text = self.font.render(text, True, self.text_color)centerx, centery = image_text.get_rect().centercoord_image_text = (self.width // 2 - centerx, self.height // 2 - centery)image = py.Surface(self.rect.size)image.fill(self.bg_color)image.blit(image_text, coord_image_text)image_clicked = py.Surface(self.rect.size)image_clicked.fill(self.clicked_color)image_clicked.blit(image_text, coord_image_text)if self.shadow:py.draw.rect(image, self.shadow_color, (0, 0, self.width, self.height), 2)py.draw.rect(image_clicked, self.shadow_color, (0, 0, self.width, self.height), 2)# self.images = [原始圖片,被點擊時的圖片]self.images = [image, image_clicked]def update(self):if self.clicked:self.image = self.images[1]else:self.image = self.images[0]def collide_mouse(self, x, y):return self.rect.collidepoint(x, y)ButtonKeyboard
用于選擇 1~9 的按鈕:
class ButtonKeyboard(Button):def __init__(self, text, size=(20, 20), position=(0, 0), font=None, id=None, name=None):Button.__init__(self, text, size=size, font=font, position=position, id=id, name=name)CardButton
用于展示卡牌的按鈕:
class CardButton(Button):def __init__(self, text, size=(20, 20), position=(0, 0), font=None, id=0, name=None, shadow=False, locked=False):if id not in [0, 1, 2, 3]:raise ValueErrorButton.__init__(self, text, size=size, font=font, position=position, id=id, name=name, shadow=shadow)self.reload(text, font)self.locked = locked # 卡牌是否被猜到def reload(self, text, font=None):# 渲染游戲過程中,卡牌被猜到時顯示的圖片if not font:self.font = py.font.Font(None, 20)else:self.font = font# 黑色卡牌需要用白字,其它卡牌用黑字if self.text_color == ID_COLOR[self.id]:if self.text_color == (0, 0, 0):image_text = self.font.render(text, True, (255, 255, 255))else:image_text = self.font.render(text, True, (0, 0, 0))else:image_text = self.font.render(text, True, self.text_color)centerx, centery = image_text.get_rect().centercoord_image_text = (self.width // 2 - centerx, self.height // 2 - centery)image_locked = py.Surface(self.rect.size)image_locked.fill(ID_COLOR[self.id])image_locked.blit(image_text, coord_image_text)if self.shadow:py.draw.rect(image_locked, self.shadow_color, (0, 0, self.width, self.height), 2)self.images.append(image_locked)def update(self):if self.locked:self.image = self.images[2]elif self.clicked:self.image = self.images[1]else:self.image = self.images[0]初始化詞和顏色布局
我們將所有詞語文件都存放 words_dir 中,詞語文件中詞語用utf-8編碼“,”作為分隔符
words_dir = './dat'class HandleWords():def __init__(self):try:self.word_list = []for filename in os.listdir(words_dir):try:with open(os.path.join(words_dir, filename), 'r', encoding='utf-8') as f:self.word_list.extend(f.read().split(','))except:passexcept:raise FileNotFoundErrordef get_words(self):words_index = set()while len(words_index) < 25:words_index.add(randint(0, len(self.word_list) - 1))words = [self.word_list[i] for i in words_index]shuffle(words)return words為每一個詞生成一個 id
def get_maps():begin_id = randint(2, 3)second_id = 2 if begin_id == 3 else 3maps = [0] + [1] * 7 + [second_id] * 8 + [begin_id] * 9shuffle(maps)generate_map_image(maps)return maps, begin_iddef generate_map_image(maps):# 生成圖像global ID_COLORimage_file_path = 'img/text.png'size_img = 600, 600img = py.Surface(size_img)img.fill((255, 255, 255))padx, pady = 30, 30int_x, int_y = 10, 10w, h = 100, 100i = 0py.draw.rect(img, (0, 0, 0), (padx // 2, pady // 2, size_img[0] - padx, size_img[1] - pady), 1)while i < 25:x, y = i % 5, i // 5temp_surf = py.Surface((w, h))temp_surf.fill(ID_COLOR[maps[i]])img.blit(temp_surf, (padx + x * w + x * int_x, pady + y * h + y * int_y, w, h))i += 1py.image.save(img, image_file_path)1.3. 主程序
import pygame as py from pygame.locals import * import sys from random import randint, shuffle import os def menu_game():global screen, cards_grp, tips_font, area_tips_position, padyglobal phase_prepare, phase_gaming, game_over, cursor_click, cursor_click_object, init, now, waiting_input, count, total, continuer, DISCOVEREDglobal word_generator# 生成詞語和顏色圖word_generator = HandleWords()words = get_words()maps, begin_id = get_maps()# 初始化相關(guān)大小參數(shù)card_font = py.font.Font('SimHei.ttf', 50)card_size = (150, 80)blank_x, blank_y = card_size[1] // 2, card_size[1] // 2padx, pady = 5, 5area_cards_bg = (255, 228, 181)prepare_btn_size = (100, 60)prepare_btn_font = py.font.Font('SimHei.ttf', 30)prepare_btn_blank_x = prepare_btn_size[0] // 10area_cards_size = padx * 2 + card_size[0] * 5 + blank_x * 4, pady * 2 + card_size[1] * 5 + blank_y * 4area_cards_position = (screen.get_rect().width - area_cards_size[0]) // 2, (screen.get_rect().height - area_cards_size[1]) // 5area_cards = py.Surface(area_cards_size)# 初始化25個詞語按鈕cards_grp = py.sprite.Group()start_x, start_y = padx, padyi = 0y = start_ywhile i < 25:for x in range(start_x, area_cards_size[0], card_size[0] + blank_x):if i < 25:cards_grp.add(CardButton(words[i], size=card_size, font=card_font, position=(x, y), id=maps[i]))i += 1y += card_size[1] + blank_yarea_tips_position = area_cards_position[0], area_cards_position[1] + area_cards_size[1] + 10 * padytips_font = py.font.Font('SimHei.ttf', 20)# 初始化“準(zhǔn)備”、“換牌”按鈕prepare_btn_grp = py.sprite.Group()btn_change_cards_position = (area_tips_position[0] + area_cards_size[0] - prepare_btn_size[0], area_tips_position[1])btn_prepare_position = (btn_change_cards_position[0] - prepare_btn_size[0] - prepare_btn_blank_x, area_tips_position[1])prepare_btn_grp.add(Button('換牌', font=prepare_btn_font, size=prepare_btn_size, position=btn_change_cards_position, id='change'))prepare_btn_grp.add(Button('準(zhǔn)備', font=prepare_btn_font, size=prepare_btn_size, position=btn_prepare_position, id='prepare'))# 初始化 input_card_grp input_card_grp = py.sprite.Group()input_card_size = (40, 40)pad_input_card = 10start_x, start_y = area_cards_position[0] + padx, area_tips_position[1] + tips_font.size('一')[1] + padyx = start_xfor i in range(1, 10):input_card_grp.add(ButtonKeyboard(str(i), size=input_card_size, position=(x, start_y), id=i))x += pad_input_card + input_card_size[0]def change_side():# 當(dāng)前方回合結(jié)束,換邊global now, init, waiting_inputif not init:now = 2 if now == 3 else 3else: # 若游戲剛開始,則換邊后行動方為 begin_idinit = Falsewaiting_input = Truedef change_words():# 點擊換牌按鈕global cards_grpwords = get_words()for card, word in zip(cards_grp, words):card.text = wordcard.load(card.text, card.font, card.position)card.reload(card.text, card.font, card.position)def init_game():# 重新初始化游戲global phase_prepare, phase_gaming, game_over, cursor_click, cursor_click_object, init, now, waiting_input, count, total, cards_grp, continuer, DISCOVEREDmaps, begin_id = get_maps()phase_prepare = Truephase_gaming = Falsegame_over = Falsecursor_click = Falsecursor_click_object = Nonenow = begin_idinit = Truecontinuer = Falsecount = 0total = 0waiting_input = Falsefor c, m in zip(cards_grp, maps):c.id = mc.locked = FalseDISCOVERED = {0: 1, 1: 7, begin_id: 9, 2 if begin_id == 3 else 3: 8}def show_current_info():# 可視化DISCOVERED信息global tips_font, DISCOVERED, screen, padyassert isinstance(tips_font, py.font.FontType)tips_height = tips_font.size('一')[1]x, y = area_tips_position[0], area_tips_position[1] + tips_height + padyfor id in [2, 3]:screen.blit(tips_font.render(ID_TIPS[id] + '剩余%d' % DISCOVERED[id], True, ID_COLOR[id]), (x, y))y += tips_height + padyphase_prepare = Truephase_gaming = Falsegame_over = Falsecursor_click = Falsecursor_click_object = Nonenow = begin_idinit = Truecount = 0total = 0waiting_input = Falsecontinuer = FalseDISCOVERED = {0: 1, 1: 7, begin_id: 9, 2 if begin_id == 3 else 3: 8}img_copyright = tips_font.render('Contact : CSDN: Apoca——20200202, Email:785016240@qq.com',True, (255, 255, 255), (0, 0, 0)).convert()while True:if not game_over:for event in py.event.get():if event.type in (QUIT,):sys.exit()elif event.type == MOUSEBUTTONDOWN:mouse_x, mouse_y = event.posif phase_prepare:for b in prepare_btn_grp:if b.collide_mouse(mouse_x, mouse_y):b.clicked = Truecursor_click_object = bcursor_click = Truebreakelif phase_gaming:if waiting_input:for b in input_card_grp:if b.collide_mouse(mouse_x, mouse_y):b.clicked = Truecursor_click_object = bcursor_click = Truebreakelse:for b in cards_grp:if b.collide_mouse(mouse_x - area_cards_position[0], mouse_y - area_cards_position[1]):if not b.locked:b.clicked = Truecursor_click_object = bcursor_click = Truebreakelif event.type == MOUSEBUTTONUP:if cursor_click:cursor_click = Falsecursor_click_object.clicked = Falseif phase_gaming:# 游戲階段if waiting_input:# 等待玩家選擇本輪猜詞個數(shù)階段if b.collide_mouse(mouse_x, mouse_y):# 玩家選擇本輪猜 b.id個詞total = b.idb.clicked = Falsecount = 0waiting_input = Falseelse:# 猜詞階段# 此時回合進行方為 now,隊長指定猜total個詞,已經(jīng)猜對了count個,目前隊員猜詞b(b為一個CardButton)if b.collide_mouse(mouse_x - area_cards_position[0], mouse_y - area_cards_position[1]):b.locked = TrueDISCOVERED[b.id] -= 1# 猜詞結(jié)束后的邏輯if now == b.id:# 若猜詞為本方顏色詞if DISCOVERED[b.id] == 0:# 若所有本方顏色都已經(jīng)被猜到,游戲結(jié)束game_over = Truegame_over_message = tips_font.render(ID_TIPS[b.id] + '勝利', True,ID_COLOR[b.id])else:count += 1if count == total:# 若已達到此回合最大猜詞個數(shù),則換邊change_side()else:# 若猜詞不為本方顏色詞if b.id == 0:# 若猜詞為黑色,游戲結(jié)束game_over = Truegame_over_message = tips_font.render(ID_TIPS[now] + '錯誤識別黑色暗號,游戲失敗!', True,ID_COLOR[now])else:if DISCOVERED[b.id] == 0 and b.id != 1:# 若猜到了對方顏色詞,且對方顏色的所有詞都被揭露,游戲結(jié)束game_over = Truegame_over_message = tips_font.render(ID_TIPS[b.id] + '勝利', True,ID_COLOR[b.id])else:# 其余猜錯詞的情況,換邊change_side()elif phase_prepare:# 準(zhǔn)備階段if b.collide_mouse(mouse_x, mouse_y):b.clicked = Falseif b.id == 'prepare': # 點擊準(zhǔn)備按鈕# 游戲開始phase_prepare = Falsephase_gaming = Truechange_side()elif b.id == 'change': # 點擊換牌按鈕change_words()cursor_click_object = Noneelif event.type == MOUSEMOTION:mouse_x, mouse_y = event.poselse:# 整局游戲結(jié)束,按任意鍵將重新初始化游戲for event in py.event.get():if event.type in (MOUSEBUTTONUP, KEYUP):continuer = True# 繪制屏幕screen.fill((0, 0, 0))# 作顯示詞語的區(qū)域cards_grp.update()area_cards.fill(area_cards_bg)cards_grp.draw(area_cards)screen.blit(area_cards, area_cards_position)if phase_prepare:# 準(zhǔn)備階段顯示“準(zhǔn)備”和“換邊”按鈕prepare_btn_grp.update()prepare_btn_grp.draw(screen)elif phase_gaming:# 游戲階段if waiting_input:# 回合開始等待選擇此輪猜詞個數(shù),顯示input_card_grpscreen.blit(tips_font.render(ID_TIPS[now] + '選擇此輪猜詞個數(shù)', True, ID_COLOR[now]), area_tips_position)input_card_grp.update()input_card_grp.draw(screen)else:# 猜詞階段if not game_over:# 若游戲未結(jié)束,顯示當(dāng)前游戲信息screen.blit(tips_font.render(ID_TIPS[now] + ' : ' + '此輪剩余個數(shù)(%d) !' % (total - count), True, ID_COLOR[now]),area_tips_position)show_current_info()else:# 游戲結(jié)束if not continuer:# 顯示勝利提示screen.blit(py.font.SysFont('SimHei', 100).render('按任意鍵繼續(xù)', True, (139, 139, 122)), (200, 500))screen.blit(game_over_message, area_tips_position)else:# 重新初始化游戲init_game()screen.blit(img_copyright, (0, 0))py.display.update()1.4. 運行程序
if __name__ == '__main__':py.init()screen = py.display.set_mode((1000, 1000))py.display.set_caption('行動代號')menu_game()?
下一部分鏈接:
Pygame 實戰(zhàn)(行動代號(單機版)):(三). 程序的完善補充
?
總結(jié)
以上是生活随笔為你收集整理的Pygame 实战(行动代号(单机版)):(二). 游戏编程的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 计算机应用专业可以考哪些证,计算机应用技
- 下一篇: input submit中value值字