import logging
import pygame
from pygame.locals import *
import pytmx
from pytmx import TiledImageLayer
from pytmx import TiledObjectGroup
from pytmx import TiledTileLayer
from pytmx.util_pygame import load_pygame
logger = logging.getLogger(__name__)
def init_screen(width, height):
""" Set the screen mode
This function is used to handle window resize events
"""
return pygame.display.set_mode((width, height), pygame.RESIZABLE)
class TiledRenderer(object):
"""
Super simple way to render a tiled map
"""
def __init__(self, filename):
tm = load_pygame(filename)
# self.size will be the pixel size of the map
# this value is used later to render the entire map to a pygame surface
self.pixel_size = tm.width * tm.tilewidth, tm.height * tm.tileheight
self.tmx_data = tm
def render_map(self, surface):
""" Render our map to a pygame surface
Feel free to use this as a starting point for your pygame app.
This method expects that the surface passed is the same pixel
size as the map.
Scrolling is a often requested feature, but pytmx is a map
loader, not a renderer! If you'd like to have a scrolling map
renderer, please see my pyscroll project.
"""
# fill the background color of our render surface
if self.tmx_data.background_color:
surface.fill(pygame.Color(self.tmx_data.background_color))
# iterate over all the visible layers, then draw them
for layer in self.tmx_data.visible_layers:
# each layer can be handled differently by checking their type
if isinstance(layer, TiledTileLayer):
self.render_tile_layer(surface, layer)
elif isinstance(layer, TiledObjectGroup):
self.render_object_layer(surface, layer)
elif isinstance(layer, TiledImageLayer):
self.render_image_layer(surface, layer)
def render_tile_layer(self, surface, layer):
""" Render all TiledTiles in this layer
"""
# deref these heavily used references for speed
tw = self.tmx_data.tilewidth
th = self.tmx_data.tileheight
surface_blit = surface.blit
# iterate over the tiles in the layer, and blit them
for x, y, image in layer.tiles():
surface_blit(image, (x * tw, y * th))
def render_object_layer(self, surface, layer):
""" Render all TiledObjects contained in this layer
"""
# deref these heavily used references for speed
draw_lines = pygame.draw.lines
surface_blit = surface.blit
# these colors are used to draw vector shapes,
# like polygon and box shapes
rect_color = (255, 0, 0)
# iterate over all the objects in the layer
# These may be Tiled shapes like circles or polygons, GID objects, or Tiled Objects
for obj in layer:
logger.info(obj)
# objects with points are polygons or lines
if obj.image:
# some objects have an image; Tiled calls them "GID Objects"
surface_blit(obj.image, (obj.x, obj.y))
else:
# use `apply_transformations` to get the points after rotation
draw_lines(surface, rect_color, obj.closed, obj.apply_transformations(), 3)
def render_image_layer(self, surface, layer):
if layer.image:
surface.blit(layer.image, (0, 0))
class SimpleTest(object):
""" Basic app to display a rendered Tiled map
"""
def __init__(self, filename):
self.renderer = None
self.running = False
self.dirty = False
self.exit_status = 0
self.load_map(filename)
def load_map(self, filename):
""" Create a renderer, load data, and print some debug info
"""
self.renderer = TiledRenderer(filename)
logger.info("地图中的对象:")
for obj in self.renderer.tmx_data.objects:
logger.info(obj)
for k, v in obj.properties.items():
logger.info("%s\t%s", k, v)
logger.info("GID(磁贴)属性:")
for k, v in self.renderer.tmx_data.tile_properties.items():
logger.info("%s\t%s", k, v)
logger.info("碰撞体:")
for k, v in self.renderer.tmx_data.get_tile_colliders():
logger.info("%s\t%s", k, list(v))
def draw(self, surface):
""" Draw our map to some surface (probably the display)
"""
# first we make a temporary surface that will accommodate the entire
# size of the map.
# because this demo does not implement scrolling, we render the
# entire map each frame
temp = pygame.Surface(self.renderer.pixel_size)
# render the map onto the temporary surface
self.renderer.render_map(temp)
# now resize the temporary surface to the size of the display
# this will also 'blit' the temp surface to the display
pygame.transform.smoothscale(temp, surface.get_size(), surface)
# display a bit of use info on the display
f = pygame.font.Font(pygame.font.get_default_font(), 20)
i = f.render('press any key for next map or ESC to quit',
1, (180, 180, 0))
surface.blit(i, (0, 0))
def handle_input(self):
try:
event = pygame.event.wait()
if event.type == QUIT:
self.exit_status = 0
self.running = False
elif event.type == KEYDOWN:
if event.key == K_ESCAPE:
self.exit_status = 0
self.running = False
else:
self.running = False
elif event.type == VIDEORESIZE:
init_screen(event.w, event.h)
self.dirty = True
except KeyboardInterrupt:
self.exit_status = 0
self.running = False
def run(self):
""" This is our app main loop
"""
self.dirty = True
self.running = True
self.exit_status = 1
while self.running:
self.handle_input()
# we don't want to constantly draw on the display, as that is way
# inefficient. so, this 'dirty' values is used. If dirty is True,
# then re-render the map, display it, then mark 'dirty' False.
if self.dirty:
self.draw(screen)
self.dirty = False
pygame.display.flip()
return self.exit_status
if __name__ == '__main__':
import os.path
import glob
pygame.init()
pygame.font.init()
screen = init_screen(600, 600)
pygame.display.set_caption('地图浏览器')
logging.basicConfig(level=logging.DEBUG)
logger.info(pytmx.__version__) # '版本',
# loop through a bunch of maps in the maps folder
try:
SimpleTest('家.tmx').run()
# for filename in glob.glob(os.path.join('data', '*.tmx')):
# print(filename)
# logger.info("Testing %s", filename)
# if not SimpleTest(filename).run():
# break
except:
pygame.quit()
raise
注:部分代码及资源来自网络,如有不当,请联系我删除,此处仅供大家学习参考
## 总结
python游戏开发,现从简单到稍微复杂些,已试过了pyzero,pygame,通过对比,pygame在处理图片上比pyzero更进一步,灵活性更大些,今天又试了pygame调用图块地图的功能,后期会解始arcade模块,感到比pygame又有一些优点。
## 源码获取
可**关注**博主后,*私聊博主*免费获取
需要技术指导,育娃新思考,企业软件合作等更多服务请联系博主
今天是以此模板持续更新此育儿专栏的第 11 /50次。
可以**关注**我,**点赞**我、**评论**我、**收藏**我啦。