项目源码地址:https://github.com/zxf20180725/pygame-jxzj,求赞求星星~
工作太忙啦,没啥时间更新博客,大家有什么疑问,欢迎加q群讨论,刚创的:812095339
地图在游戏中是非常重要的一部分,几乎所有的游戏都有地图。比如梦幻西游中的长安城、建邺城、大雁塔等等都是游戏地图。
那么在我们的开发中,地图的组成部分有:
1.地图的背景图:一张完整的地图图片
2.地图的前景图:需要把人物遮挡住的地方
我们按照绘图顺序:画地图背景、画玩家、最后再画地图前景,这样就能将玩家遮挡住。
3.行走层数据:一个二维数组,将地图划分成一个个的小格子,记录着这些小格子是否可以行走。
就比如在我们的游戏开发中,将用32*32做为一个格子的大小。
上图是我很久以前做的地图编辑器,将地图划分成一个个小格子就是这个意思,这应该好理解了吧,黄色格子就是不可行走区域。
由于地图行走层就是一个二维数组(二维列表),所以我们先封装一个二维列表,方便以后的操作,core.py中增加:
class Array2D:
"""
说明:
1.构造方法需要两个参数,即二维数组的宽和高
2.成员变量w和h是二维数组的宽和高
3.使用:‘对象[x][y]’可以直接取到相应的值
4.数组的默认值都是0
"""
def __init__(self, w, h, default=0):
self.w = w
self.h = h
self.data = []
self.data = [[default for y in range(h)] for x in range(w)]
def show_array2d(self):
for y in range(self.h):
for x in range(self.w):
print(self.data[x][y], end=' ')
print("")
def __getitem__(self, item):
return self.data[item]
创建Array2D对象就是创建一个宽和高为w、h的二维数组,其中show_array2d是在控制台打印二维数组的内容。
因为我们实现了__getitem__方法,所以可以直接用中括号对Array2D对象进行取值,比如
arr2d=Array2D(3,5)
arr2d[2][4]=666
接下来就是编写地图类了,上面我们已经分析过了,地图包括:背景图、前景图、行走数据。
那么构造一个地图对象就需要相应的图片surface和行走数据,core.py中增加:
class GameMap(Array2D):
"""
游戏地图类
"""
def __init__(self, bottom, top, x, y):
# 将地图划分成w*h个小格子,每个格子32*32像素
w = int(bottom.get_width() / 32) + 1
h = int(top.get_height() / 32) + 1
super().__init__(w, h)
self.bottom = bottom
self.top = top
self.x = x
self.y = y
def draw_bottom(self, screen_surf):
screen_surf.blit(self.bottom, (self.x, self.y))
def draw_top(self, screen_surf):
screen_surf.blit(self.top, (self.x, self.y))
def load_walk_file(self, path):
"""
读取可行走区域文件
"""
with open(path, 'r') as file:
for x in range(self.w):
for y in range(self.h):
v = int(file.readline())
self[x][y] = v
self.show_array2d()
GameMap继承自Array2D,因为地图本身就是一个二维数组嘛。
构造方法里有四个参数,bottom和top是相应图片的surface,x,y是地图的绘图坐标。
draw_bottom和draw_top是绘制地图背景和地图前景的方法。
load_walk_file是加载地图行走区域的方法,用双for循环读取文件是因为当初写文件的时候,也是这样写入的,由于继承了Array2D,所以可以直接用self[x][y]。最后在控制台打印一下读取的地图二维数组。
既然封装好了地图类,那我们简单使用一下,看看效果咋样:
在main.py的Game类中,修改一下代码:
def __init_game(self):
self.hero = pygame.image.load('./img/character/hero.png').convert_alpha()
self.map_bottom = pygame.image.load('./img/map/0.png').convert_alpha()
self.map_top = pygame.image.load('./img/map/0_top.png').convert_alpha()
self.game_map = GameMap(self.map_bottom, self.map_top, 0, 0)
self.game_map.load_walk_file('./img/map/0.map')
增加了一个game_map属性,也就是游戏地图对象。
再修改一下绘图的代码,看看效果:
def update(self):
while True:
self.clock.tick(self.fps)
# TODO:逻辑更新
self.event_handler()
# TODO:画面更新
self.game_map.draw_bottom(self.screen_surf)
Sprite.draw(self.screen_surf, self.hero, 100, 100, 0, 0)
Sprite.draw(self.screen_surf, self.hero, 210, 120, 1, 1)
Sprite.draw(self.screen_surf, self.hero, 300, 100, 2, 2)
pygame.display.update()
我故意改了一下第二个精灵的位置,它竟然跑到房顶去了。
不过,别担心,是因为没有绘制前景图将角色挡住:
我们加一行代码就行了:
def update(self):
while True:
self.clock.tick(self.fps)
# TODO:逻辑更新
self.event_handler()
# TODO:画面更新
self.game_map.draw_bottom(self.screen_surf)
Sprite.draw(self.screen_surf, self.hero, 100, 100, 0, 0)
Sprite.draw(self.screen_surf, self.hero, 210, 120, 1, 1)
Sprite.draw(self.screen_surf, self.hero, 300, 100, 2, 2)
self.game_map.draw_top(self.screen_surf)
pygame.display.update()
本章完~