python遊戲開發實戰:網路遊戲Demo(客戶端)
一.執行效果
二.介紹
原始碼github:https://github.com/zxf20180725/pygame-online-demo.git
這只是一個簡單的聯網程式Demo,程式碼有很多不嚴謹的地方,僅當拋磚引玉了。
執行客戶端程式,會隨機取一個名字進入遊戲。使用wsad移動頭像(藍葵~)。
三.程式碼解析
注意,這裡只會貼出部分核心程式碼,完整程式碼請在上面的github連結中下載。
全域性部分的程式碼,這些都有註釋了,具體作用,後面會講到。foxyball.cn是我的伺服器域名,這一年內應該都是有效的。
import random
import sys
import time
from random import randint
from threading import Thread
import pygame
import socket # 匯入 socket 模組
from base import Protocol
ADDRESS = ('127.0.0.1', 8712) # ('foxyball.cn', 8712) # 如果服務端在本機,請使用('127.0.0.1', 8712)
WIDTH, HEIGHT = 640, 480 # 視窗大小
g_font = None
g_screen = None # 視窗的surface
g_sur_role = None # 人物的role
g_player = None # 玩家操作的角色
g_other_player = [] # 其他玩家
g_client = socket.socket() # 建立 socket 物件
看一個程式的程式碼,應該從它的入口開始看。
if __name__ == '__main__':
# 初始化
init_game()
# 遊戲迴圈
main_loop()
入口很簡單,就呼叫了兩個函式,那麼我們先看看init_game()做了什麼。
def init_game():
"""
初始化遊戲
"""
global g_screen, g_sur_role, g_player, g_font
# 初始化pygame
pygame.init()
pygame.display.set_caption('網路遊戲Demo')
g_screen = pygame.display.set_mode([WIDTH, HEIGHT])
g_sur_role = pygame.image.load("./role.png").convert_alpha() # 人物圖片
g_font = pygame.font.SysFont("fangsong", 24)
# 初始化隨機種子
random.seed(int(time.time()))
# 建立角色
# 隨機生成一個名字
last_name = ['趙', '錢', '孫', '李', '周', '吳', '鄭', '王', '馮', '陳', '褚', '衛',
'蔣', '沈', '韓', '楊', '朱', '秦', '尤', '許', '何', '呂', '施', '張',
'孔', '曹', '嚴', '華', '金', '魏', '陶', '姜', '戚', '謝', '鄒', '喻', ]
first_name = ['夢琪', '憶柳', '之桃', '慕青', '問蘭', '爾嵐', '元香', '初夏', '沛菡',
'傲珊', '曼文', '樂菱', '痴珊', '孤風', '雅彤', '宛筠', '飛鬆', '初瑤',
'夜雲', '樂珍']
name = random.choice(last_name) + random.choice(first_name)
print("你的暱稱是:", name)
g_player = Role(randint(100, 500), randint(100, 300), name)
# 與伺服器建立連線
g_client.connect(ADDRESS)
# 開始接受服務端訊息
thead = Thread(target=msg_handler)
thead.setDaemon(True)
thead.start()
# 告訴服務端有新玩家
send_new_role()
從與伺服器建立連線開始講吧(28行)。如果對python的socket不太熟悉的話,可以先看看這兩篇文章:https://blog.csdn.net/qq_39687901/article/details/81531101,https://blog.csdn.net/qq_39687901/article/details/81536641,g_client是一個socket物件,與指定的服務端建立連線。
接收服務端訊息部分,我新開了一個執行緒進行處理(因為recv是阻塞執行緒的)。處理服務端訊息的函式是msg_handler,這個函式稍後再講,我們繼續往下看send_new_role函式。
def send_new_role():
"""
告訴服務端有新玩家加入
"""
# 構建資料包
p = Protocol()
p.add_str("newrole")
p.add_int32(g_player.x)
p.add_int32(g_player.y)
p.add_str(g_player.name)
data = p.get_pck_has_head()
# 傳送資料包
g_client.sendall(data)
Protocol是我們自定義的遊戲資料包協議,關於Protocol的設計思路都在這篇文章:https://blog.csdn.net/qq_39687901/article/details/81541967
這裡,我們構造了一個名字叫“newrole”的資料包,並且加入了玩家的資訊(座標和暱稱),最後把這個資料包傳送給服務端。這個“newrole”的作用就是告訴服務端有一個新玩家加入遊戲啦,然後服務端又會告訴其他玩家有個新玩家加入了(這就實現了可以在視窗裡看到其他玩家的功能)。我會在下一篇文章詳細的講解服務端的設計,這裡就不多說了。
回到我們的程式入口來,接下來就該執行main_loop啦。
def main_loop():
"""
遊戲主迴圈
"""
while True:
# FPS=60
pygame.time.delay(32)
# 邏輯更新
update_logic()
# 檢視更新
update_view()
每個遊戲都必不可少的遊戲主迴圈。迴圈裡很簡單,就呼叫了3個函式。pygame.time.delay(32)讓每次迴圈間隔32毫秒,也就是說每秒迴圈執行60次左右。然後就是邏輯更新和檢視更新了,這兩個函式請儘可能的解耦。
那我們繼續看邏輯更新,這個demo的遊戲邏輯很簡單,就是用wasd控制角色移動。
def update_logic():
"""
邏輯更新
"""
# 事件處理
handler_event()
def handler_event():
# 事件處理
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_w:
g_player.y -= 5
elif event.key == pygame.K_s:
g_player.y += 5
elif event.key == pygame.K_a:
g_player.x -= 5
elif event.key == pygame.K_d:
g_player.x += 5
send_role_move() # 告訴伺服器,自己移動了
角色每次移動之後,要把最新的座標告訴給服務端,服務端再把這個角色的最新座標傳送給其他客戶端,這樣其他客戶端就能看到你在移動了。send_role_move函式就是把當前座標傳送給服務端。
def send_role_move():
"""
傳送角色的座標給服務端
"""
# 構建資料包
p = Protocol()
p.add_str("move")
p.add_int32(g_player.x)
p.add_int32(g_player.y)
data = p.get_pck_has_head()
# 傳送資料包
g_client.sendall(data)
回到我們的遊戲主迴圈,繼續看檢視更新。
def update_view():
"""
檢視更新
"""
g_screen.fill((0, 0, 0))
# 畫角色
g_screen.blit(g_player.sur_name, (g_player.x, g_player.y - 20))
g_screen.blit(g_sur_role, (g_player.x, g_player.y))
# 畫其他角色
for r in g_other_player:
g_screen.blit(r.sur_name, (r.x, r.y - 20))
g_screen.blit(g_sur_role, (r.x, r.y))
# 重新整理
pygame.display.flip()
其中,g_other_player是一個存著其他線上玩家的列表。那麼這個列表中的內容是從哪裡來的呢?內容當然是從服務端發過來的。還記得本文最開始提到的新開一個執行緒處理服務端訊息嗎?就是那個msg_handler函式,現在來研究研究它。
def msg_handler():
"""
處理服務端返回的訊息
"""
while True:
bytes = g_client.recv(1024)
# 以包長度切割封包
while True:
# 讀取包長度
length_pck = int.from_bytes(bytes[:4], byteorder='little')
# 擷取封包
pck = bytes[4:4 + length_pck]
# 刪除已經讀取的位元組
bytes = bytes[4 + length_pck:]
# 把封包交給處理函式
pck_handler(pck)
# 如果bytes沒資料了,就跳出迴圈
if len(bytes) == 0:
break
外層的while迴圈是用來接收服務端的訊息,內層的while迴圈是用來切割資料包的(tcp粘包分包瞭解一下)。但這裡還有個問題,是我在程式碼裡沒有去處理的。那就是tcp分包問題,這裡內層while迴圈只解決了粘包。分包的問題,在以後的文章中會講。內層while迴圈的邏輯為什麼要這麼寫,大家還是去看看我之前發的那篇文章吧。https://blog.csdn.net/qq_39687901/article/details/81541967
資料包切割好了之後,就呼叫pck_handler函式處理資料包。
def pck_handler(pck):
p = Protocol(pck)
pck_type = p.get_str()
if pck_type == 'playermove': # 玩家移動的資料包
x = p.get_int32()
y = p.get_int32()
name = p.get_str()
for r in g_other_player:
if r.name == name:
r.x = x
r.y = y
break
elif pck_type == 'newplayer': # 新玩家資料包
x = p.get_int32()
y = p.get_int32()
name = p.get_str()
r = Role(x, y, name)
g_other_player.append(r)
elif pck_type == 'logout': # 玩家掉線
name = p.get_str()
for r in g_other_player:
if r.name == name:
g_other_player.remove(r)
break
我們這個小demo一共就設計了三個協議型別,"playermove"、"newplayer"和"logout"。"playermove"是在其他玩家移動的時候,服務端給我們的,讓我們更新其他玩家的位置(這樣就能看到其他玩家的移動效果了)。剩下的兩個就不用多說了吧。
四.總結
網路流程:
登入流程:
1.客戶端登入,傳送"newrole"資料包給服務端
2.服務端收到"newrole"資料包,然後傳送"newplayer"資料包給其他客戶端
3.其他客戶端收到"newplayer",向g_other_player列表中新增一個玩家
移動流程:
1.客戶端移動,傳送"move"資料包給服務端
2.服務端收到"move"資料包,然後傳送"playermove"資料包給其他客戶端
3.其他客戶端收到"playermove",更新g_other_player的相關資料
下線流程:
1.服務端檢測到有客戶端掉線,傳送"logout"資料包給其他線上客戶端
2.其他客戶端收到"playermove",刪除g_other_player中掉線的玩家
相關文章
- 實戰Flash遊戲開發遊戲開發
- 從客戶端遊戲漏洞看開發中的安全隱患客戶端遊戲
- 如何建立一個Java遊戲客戶端Java遊戲客戶端
- python 編寫遊戲測試機器人客戶端 (二)Python遊戲機器人客戶端
- python 編寫遊戲測試機器人客戶端 (三)Python遊戲機器人客戶端
- python 編寫遊戲測試機器人客戶端 (一)Python遊戲機器人客戶端
- Python 實戰開發俄羅斯方塊遊戲Python遊戲
- python開發植物大戰殭屍遊戲Python遊戲
- 網路開發基礎客戶端001客戶端
- TechFinger遊戲搬磚系統開發demo遊戲
- 遊戲發展史:《全面戰爭》系列(1):開端遊戲
- go語言遊戲服務端開發(二)——網路通訊Go遊戲服務端
- Python遊戲開發工程師的起步,幾款遊戲開發案例Python遊戲開發工程師
- python可以開發遊戲嗎Python開發遊戲
- 【Unity3D開發小遊戲】《戰棋小遊戲》Unity開發教程Unity3D遊戲
- FDF智慧合約迴圈互助遊戲開發demo遊戲開發
- 遊戲開發入門(一)遊戲開發概述遊戲開發
- unity3d開發的大型網路遊戲Unity3D遊戲
- NFT遊戲系統開發/遊戲開發技術遊戲開發
- 遊戲開發者怎麼做出一個成功的demo?遊戲開發
- 遊戲開發經驗談(二):對戰類全球服遊戲的設計與實現遊戲開發
- 雜湊遊戲競猜系統開發原始碼(DEMO)hash遊戲競猜系統開發瞭解方案遊戲原始碼
- 03:遊戲主角動起來啦!#python遊戲開發#紅傘傘Python遊戲開發
- 遊戲開發者應如何處理網路危機?遊戲開發
- python專案開發例項-Python專案案例開發從入門到實戰——爬蟲、遊戲Python爬蟲遊戲
- Android遊戲開發示例——彈幕+戰棋Android遊戲開發
- Unity遊戲示例來了,用Unity開源遊戲資源做遊戲,遊戲開發不再難!Unity遊戲開發
- 微信小程式--遊戲demo微信小程式遊戲
- 遊戲開發流程遊戲開發
- 皇家國際官網遊戲開戶vq-44138926遊戲
- 網路遊戲侵權頻繁爆發,遊戲廠商該如何應對?遊戲
- 劍網3雲遊戲首次測試開放 移動端瀏覽器雲遊戲2020實現遊戲瀏覽器
- 用 socket 代理監聽 h5 遊戲的 websocket 請求,轉發伺服器的二進位制給客戶端,看控制檯列印客戶端是收到了請求了,但是客戶端後續列印載入遊戲配置都超時了導致載入卡住進不去遊戲了H5遊戲Web伺服器客戶端
- 悠遊世界合成遊戲系統技術開發解析/合成遊戲/小遊戲遊戲
- 小鎮青年的網遊實踐與現實生活:從“遊戲即生活”到“遊戲只是遊戲”遊戲
- Python遊戲開發!Mac完美安裝pygamePython遊戲開發MacGAM
- Python開發遊戲的正確姿勢Python開發遊戲
- 遊戲開發中遊戲效能的最佳化遊戲開發