目錄
3.1 顯示不同的人物圖片
3.2?顯示玩家ID
3.3?顯示玩家對話內(nèi)容
3.4?完整代碼下載地址
本節(jié)只是在上一節(jié)內(nèi)容的基礎上加一些小功能:顯示不同的人物圖片、在人物頭頂上顯示玩家ID以及人物頭頂上顯示一個聊天對話框。大家可以把這一節(jié)內(nèi)容當做一個過渡,用來鞏固下多人游戲程序中pickle的用法。程序完成后的運行結果如下:
本項目結構顯示如下:
├── SimHei.ttf # 字體文件
├── client.py # 客戶端代碼
├── pics # 圖片文件夾
│?? ├── 1.png
│?? ├── 2.png
│?? ├── 3.png
│?? ├── 4.png
│?? ├── 5.png
│?? └── 6.png
├── player.py # 包含Player類
└── server.py # 服務端代碼
在client.py中我們一共導入了以下模塊或庫:
import sys
import pygame
import pickle
import socket
from player import Player
from random import randint
在player.py中我們一共導入了以下模塊或庫:
import pygame
import random
在server.py中我們一共導入了以下模塊或庫:
import socket
import pickle
from player import Player
from threading import Thread
3.1 顯示不同的人物圖片
pics文件夾下有6個人物方位圖,玩家打開游戲窗口時,程序都會從這6個方位圖中隨機選擇一張進行顯示。因為是隨機的,所以其他玩家的人物圖片可能跟當前玩家的一樣,也可能不一樣。
首先修改Player類:
# player.py
class Player:
def __init__(self, p_id, x, y, pic_num, frame_width, frame_height):
self.id = p_id
self.dis = 3
self.x = x
self.y = y
self.pic_num = pic_num # 1
self.frame_width = frame_width
self.frame_height = frame_height
self.frame_num = 0
self.frame_rect = (self.frame_num * self.frame_width, 0 * self.frame_height,
self.frame_width, self.frame_height)
self.current_dir = "下"
self.last_dir = self.current_dir
...
代碼解釋如下:
1. 在初始化函數(shù)中加一個pic_num變量用來保存玩家顯示的人物圖片編號,這樣就能從服務端傳送過來的數(shù)據(jù)中知道某個玩家用的什么人物圖了。
接著修改GameWindow類:
# client.py
class GameWindow:
def __init__(self):
...
self.pic_dict = { # 1
1: pygame.image.load("./pics/1.png"),
2: pygame.image.load("./pics/2.png"),
3: pygame.image.load("./pics/3.png"),
4: pygame.image.load("./pics/4.png"),
5: pygame.image.load("./pics/5.png"),
6: pygame.image.load("./pics/6.png")
}
frame_width = self.pic_dict[1].get_width() // 4 # 2
frame_height = self.pic_dict[1].get_height() // 4
self.player = Player(p_id=None,
x=randint(0, self.width-frame_width),
y=randint(0, self.height-frame_height),
pic_num=randint(1, 6), # 3
frame_width=frame_width,
frame_height=frame_height)
...
...
def update_window(self):
self.window.fill((255, 255, 255))
self.player.move()
self.player.draw(self.window, self.pic_dict[self.player.pic_num]) # 4
other_players_data = pickle.loads(self.send_player_data())
self.update_other_players_data(other_players_data)
pygame.display.update()
def update_other_players_data(self, data):
for player in data.values():
player.draw(self.window, self.pic_dict[player.pic_num]) # 5
...
代碼解釋如下:
1. 創(chuàng)建一個pic_dict字典變量,用來保存各個人物方位圖對象,字典的鍵就是圖片編號。
2. 因為所有人物方位圖的大小都是一樣的,所以這里就直接通過第一張方位圖獲取幀的寬高值。
3. 隨機獲取1-6之間的整數(shù),這樣就可以隨機選擇一張人物方位圖了。
4. & 5. 根據(jù)pic_num值從pic_dict字典中選擇對應的人物方位圖,然后繪制到窗口上。
運行結果如下:
3.2?顯示玩家ID
很多游戲會把玩家的id或名稱顯示在人物圖片上方,并跟隨人物移動,如下圖所示。
這點其實很好實現(xiàn),因為我們已經(jīng)將玩家id值保存在Player對象的id屬性中,所以只需要將這個id值繪制到窗口上就可以了。
將Player類的draw()函數(shù)修改如下:
# player.py
def draw(self, win, pic):
win.blit(pic, (self.x, self.y), self.frame_rect)
font = pygame.font.SysFont("Arial", 10) # 1
id_text = font.render(self.id, True, (150, 150, 150))
win.blit(id_text, (self.x + round(self.frame_width/2) - round(id_text.get_width()/2), self.y - id_text.get_height()))
代碼解釋如下:
1. 設置文字字體并將文本繪制到人物圖片的正上方。
運行結果如下:
3.3?顯示玩家對話內(nèi)容
如果要聊天的話,玩家就會在文本輸入框中輸入消息,然后按下回車鍵發(fā)送,其他玩家隨后也會收到該玩家發(fā)送的消息。Pygame沒有提供一個文本輸入框控件,如果要自己實現(xiàn)的話會增加很多跟本教程主題無關的代碼。所以為了保持代碼簡潔,筆者就預先設置好一些聊天內(nèi)容,然后隨機發(fā)送一條。
修改Player類:
# player.py
class Player:
def __init__(self, p_id, x, y, pic_num, frame_width, frame_height):
...
self.message = "" # 1
...
def speak(self): # 2
messages_list = ["你好", "最近咋樣", "我在打怪呢", "你說的有道理", "你哪里人", "不玩了,去吃飯了", "待會再玩", "今天很開心"]
self.message = random.choice(messages_list)
代碼解釋如下:?
1. message變量用來存儲玩家要發(fā)送消息。
2. speak()函數(shù)會隨機生成一條聊天消息,并保存在message變量中。
修改GameWindow類:
# client.py
class GameWindow:
def __init__(self):
...
self.all_players_messages = [] # 1
self.max_messages_shown = 6 # 2
self.port = 5000
self.host = "127.0.0.1"
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.connect()
...
def send_player_data(self):
data = {
"id": self.player.id,
"player": self.player
}
self.sock.send(pickle.dumps(data))
self.player.message = "" # 3
return self.sock.recv(2048)
def update_window(self):
self.window.fill((255, 255, 255))
self.player.move()
self.player.draw(self.window, self.pic_dict[self.player.pic_num])
if randint(0, 1000) < 50: # 4
self.player.speak()
self.update_messages(self.player) # 5
other_players_data = pickle.loads(self.send_player_data())
self.update_other_players_data(other_players_data)
pygame.display.update()
def update_other_players_data(self, data):
for player in data.values():
player.draw(self.window, self.pic_dict[player.pic_num])
self.update_messages(player) # 6
def update_messages(self, player):
if player.message:
self.all_players_messages.insert(0, f"{player.id}: {player.message}")
if len(self.all_players_messages) > self.max_messages_shown:
self.all_players_messages.pop()
font_size = 12
font = pygame.font.Font("SimHei.ttf", font_size)
for i, msg in enumerate(self.all_players_messages):
msg_text = font.render(msg, True, (150, 150, 150))
self.window.blit(msg_text, (0, self.height-(font_size*(i+1))))
代碼解釋如下:
1. 所有玩家的消息都會存儲在all_players_messages列表變量中。
2. max_messages_shown變量用來控制在窗口上顯示的聊天消息數(shù)。
3. 當前玩家的數(shù)據(jù)被發(fā)送到服務器后,就要清空Player對象的message屬性,否則其他玩家會重復收到一條不變的消息。
4. 使用隨機數(shù)來模擬玩家聊天。
5. update_messages()函數(shù)是重點,在該函數(shù)中,我們首先判斷玩家數(shù)據(jù)中的message變量是否有值,有的話說明有發(fā)送消息,那就將這個值插到all_players_messages列表開頭。如果消息總數(shù)大于max_messages_shown變量的值,那就把列表中最后一條聊天消息刪除掉,不再顯示。最后將所有聊天內(nèi)容都顯示到窗口左下角。為了解決Pygame中文顯示的問題,筆者這里使用了另外的SimHei.ttf字體,已放入到項目文件夾中。
6. 接收到其他玩家的數(shù)據(jù)后,要記得調(diào)用update_messages()函數(shù)更新聊天內(nèi)容。
運行結果如下:
3.4?完整代碼下載地址
鏈接:https://pan.baidu.com/s/1chQ5c94X07Oi3Iv_eX3xDg ?文章來源:http://www.zghlxwxcb.cn/news/detail-411887.html
密碼:9qbz文章來源地址http://www.zghlxwxcb.cn/news/detail-411887.html
到了這里,關于《Python多人游戲項目實戰(zhàn)》第三節(jié) 在窗口上顯示玩家ID以及對話內(nèi)容的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!