用pygame寫像素遊戲地圖編輯器
像素遊戲的地圖
我使用一個矩陣來存儲地圖,像下面這樣:
[[1,0,0],[0,1,0],[1,2,0]]
不同的數字代表不同的物體,比如1代表一個房子,0代表路面。
不同區間之間的物體的類型不同,比如
區間 | 類型 |
---|---|
<1 | 代表路面、草坪等可以通過的地方 |
≥1且<2 | 代表牆面、等 |
≥2 | 代表可以交互的地方 |
功能
創建後是這樣的,按動按鍵可以改變下面的圖片,點擊上面的矩陣將上面的圖片改變成下面的圖片
建立地圖類
初始化地圖類
我用一個字典self.dic
來保存地圖的矩陣中的數對應儲存地圖圖片,鍵是是儲存的數,值是儲存的文件名,self.dic_l
則是用於字典的鍵的值便於後續對它操作,self.un_maps
則是儲存地圖的矩陣。同時我還初始化了一個表面self.s_map
用於繪製地圖。
class MapMaker:
def __init__(self):
"""
用字典來保存圖片位置
<1 代表路面、草坪等可以通過的地方
≥1且<2 代表牆面、等
≥2 代表可以交互的地方
"""
self.dic = {0: "road", 0.1: "roadv", 0.11: "roadc1", 0.12: "roadc2", 0.13: "roadc3", 0.14: "roadc4",
0.15: "hospital_road2", 0.16: "hospital_road3",
0.2: "glass", 0.21: "hospital_f1", 0.22: "hospital_f2",
1: "wall", 1.1: "wallv", 1.11: "wallc", 1.12: "wallc1", 1.13: "wallc2", 1.14: "wallc3",
1.2: "hospital_wall1", 1.21: "hospital_wall2", 1.22: "hospital_wall3", 1.23: "hospital_wall4",
1.24: "hospital_wall5", 1.25: "hospital_wall6"}
self.s_map = pygame.Surface(screen.get_size())
self.s_map.fill([255, 255, 255])
self.dic_l = list(self.dic)
# 遊戲地圖 un_maps
self.un_maps = [[1,0,0],[0,1,0],[1,2,0]]
更新表面
這個函數用於將表面更新到屏幕上。
def r_show(self):
# 再現地圖
screen.blit(self.s_map, (0, 0))
繪製地圖
這個函數用於根據行列拆分地圖,然後根據矩陣中每個元素的位置確定要繪製的地圖的位置並更新表面。最後調用self.r_show()
來更新顯示。
def get_map(self):
# 放置下方的橫條
img_b = pygame.image.load(r"s\bang.png")
self.s_map.blit(img_b, [0, -1])
# 讀取數組中位置的圖片並更新
ci, ri = 0, 0
for c in self.un_maps:
for r in c:
# 按行繪製
image = pygame.image.load(r"s\{}.png".format(self.dic[r]))
px, py = image.get_size()
self.s_map.blit(image, (ri * px, ci * py))
ri = ri + 1
ci = ci + 1
ri = 0 # 初始化行標識
self.r_show()
實現的效果是
更新地圖中的元素
這個函數用於更新地圖中的元素,需要元素的行索引、列索引和改變後的值
def c_map(self, inx, iny, change):
self.un_maps[iny][inx] = change
self.get_map()
顯示當前的圖像
這個函數根據在字典中的順序來顯示當前值對應的文件名。
def show_now(self, r):
image = pygame.image.load(r"s\{}.png".format(self.dic[self.dic_l[r]]))
self.s_map.blit(image, (100, 600))
self.r_show()
實現的效果
儲存地圖文件
保存在map.txt上
def write_map(self):
fo = open("map.txt", "w")
fo.write(str(self.un_maps))
初始化
初始化地圖類,並繪製地圖
設置一個變量now_talent
用來保存當前位置的值。
# 遊戲初始化
pygame.init()
# 創建窗口
screen = pygame.display.set_mode([1080, 720])
screen.fill([255, 255, 255])
pygame.display.set_caption("Map Maker")
mp = MapMaker()
mp.get_map()
now_talent = 0
處理事件
下面用於獲取鼠標的位置,並且如果鼠標按鍵動了,就更新鼠標所在位置元素塊的圖片。
if event.type == pygame.MOUSEBUTTONDOWN:
print(pygame.mouse.get_pos())
x, y = pygame.mouse.get_pos()
if x < 1080 and y < 540:
x, y = int(x / 36), int(y / 36)
mp.c_map(x, y, mp.dic_l[now_talent])
mp.show_now(now_talent)
如果按動鍵盤按鍵,就更新索引值。
if event.type == pygame.KEYDOWN:
if now_talent < len(mp.dic_l) - 1:
now_talent = now_talent + 1
mp.show_now(now_talent)
else:
now_talent = 0
mp.show_now(now_talent)
pygame.display.update()
完整代碼
import pygame
# 本例用於完成二維像素地圖的編輯
class MapMaker:
def __init__(self):
"""
用字典來保存圖片位置
<1 代表路面、草坪等可以通過的地方
≥1且<2 代表牆面、等
≥2 代表可以交互的地方
"""
self.dic = {0: "road", 0.1: "roadv", 0.11: "roadc1", 0.12: "roadc2", 0.13: "roadc3", 0.14: "roadc4",
0.15: "hospital_road2", 0.16: "hospital_road3",
0.2: "glass", 0.21: "hospital_f1", 0.22: "hospital_f2",
1: "wall", 1.1: "wallv", 1.11: "wallc", 1.12: "wallc1", 1.13: "wallc2", 1.14: "wallc3",
1.2: "hospital_wall1", 1.21: "hospital_wall2", 1.22: "hospital_wall3", 1.23: "hospital_wall4",
1.24: "hospital_wall5", 1.25: "hospital_wall6",
2: "hospital_home1", 2.1: "hospital_home2", 2.11: "hospital_home3", 2.12: "hospital_road1",
3: "SCUT"}
self.s_map = pygame.Surface(screen.get_size())
self.s_map.fill([255, 255, 255])
self.dic_l = list(self.dic)
# 遊戲地圖 un_maps
self.un_maps = [[0.15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.25, 1, 0.21, 0.13, 1.22], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.21, 0.15, 2, 0.15, 1.21], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.21, 2, 2.1, 2.11, 1.21], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.21, 0.12, 2.12, 0.16, 1.21], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1.24, 1.2, 0.16, 1.2, 1.23], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]
def get_map(self):
# 放置下方的橫條
img_b = pygame.image.load(r"s\bang.png")
self.s_map.blit(img_b, [0, -1])
# 讀取數組中位置的圖片並更新
ci, ri = 0, 0
for c in self.un_maps:
for r in c:
# 按行繪製
image = pygame.image.load(r"s\{}.png".format(self.dic[r]))
px, py = image.get_size()
self.s_map.blit(image, (ri * px, ci * py))
ri = ri + 1
ci = ci + 1
ri = 0 # 初始化行標識
self.r_show()
def r_show(self):
# 再現地圖
screen.blit(self.s_map, (0, 0))
def c_map(self, inx, iny, change):
self.un_maps[iny][inx] = change
self.get_map()
def write_map(self):
fo = open("map.txt", "w")
fo.write(str(self.un_maps))
def show_now(self, r):
image = pygame.image.load(r"s\{}.png".format(self.dic[self.dic_l[r]]))
self.s_map.blit(image, (100, 600))
self.r_show()
# 遊戲初始化
pygame.init()
# 創建窗口
screen = pygame.display.set_mode([1080, 720])
screen.fill([255, 255, 255])
pygame.display.set_caption("Map Maker")
mp = MapMaker()
mp.get_map()
now_talent = 0
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
mp.write_map()
# 退出遊戲
pygame.quit()
break
elif event.type == pygame.MOUSEBUTTONDOWN:
print(pygame.mouse.get_pos())
x, y = pygame.mouse.get_pos()
if x < 1080 and y < 540:
x, y = int(x / 36), int(y / 36)
mp.c_map(x, y, mp.dic_l[now_talent])
mp.show_now(now_talent)
elif event.type == pygame.KEYDOWN:
if now_talent < len(mp.dic_l) - 1:
now_talent = now_talent + 1
mp.show_now(now_talent)
else:
now_talent = 0
mp.show_now(now_talent)
pygame.display.update()