用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()