我正尝试观看视频(This one),但遇到了问题:
“ TypeError:int()参数必须是字符串,类似字节的对象或 数字,而不是“ NoneType””(下面是完整回溯)
pytmx代码似乎有问题,但是我无法决定是否可以修复它。有人可以尝试翻译此追溯的含义吗?谢谢!
(我正在使用Tiled,Python,Atom代码编辑器,pygame,pytmx和Windows笔记本电脑)
这里是代码和完整的追溯:
main.py:
# KidsCanCode - Game Development with Pygame video series
# Tile-based game - Part 12
# Loading Tiled Maps
# Video link: https://youtu.be/QIXyj3WeyZM
import pygame as pg
import sys
from os import path
from settings import *
from sprites import *
from tilemap import *
# HUD functions
def draw_player_health(surf, x, y, pct):
if pct < 0:
pct = 0
BAR_LENGTH = 100
BAR_HEIGHT = 20
fill = pct * BAR_LENGTH
outline_rect = pg.Rect(x, y, BAR_LENGTH, BAR_HEIGHT)
fill_rect = pg.Rect(x, y, fill, BAR_HEIGHT)
if pct > 0.6:
col = GREEN
elif pct > 0.3:
col = YELLOW
else:
col = RED
pg.draw.rect(surf, col, fill_rect)
pg.draw.rect(surf, WHITE, outline_rect, 2)
class Game:
def __init__(self):
pg.init()
self.screen = pg.display.set_mode((WIDTH, HEIGHT))
pg.display.set_caption(TITLE)
self.clock = pg.time.Clock()
self.load_data()
def load_data(self):
game_folder = path.dirname(__file__)
img_folder = path.join(game_folder, 'img')
map_folder = path.join(game_folder, 'maps')
self.map = TiledMap(path.join(map_folder, 'level1.tmx'))
self.map_img = self.map.make_map()
self.map_rect = self.map_img.get_rect()
self.player_img = pg.image.load(path.join(img_folder, PLAYER_IMG)).convert_alpha()
self.bullet_img = pg.image.load(path.join(img_folder, BULLET_IMG)).convert_alpha()
self.mob_img = pg.image.load(path.join(img_folder, MOB_IMG)).convert_alpha()
self.wall_img = pg.image.load(path.join(img_folder, WALL_IMG)).convert_alpha()
self.wall_img = pg.transform.scale(self.wall_img, (TILESIZE, TILESIZE))
def new(self):
# initialize all variables and do all the setup for a new game
self.all_sprites = pg.sprite.Group()
self.walls = pg.sprite.Group()
self.mobs = pg.sprite.Group()
self.bullets = pg.sprite.Group()
# for row, tiles in enumerate(self.map.data):
# for col, tile in enumerate(tiles):
# if tile == '1':
# Wall(self, col, row)
# if tile == 'M':
# Mob(self, col, row)
# if tile == 'P':
# self.player = Player(self, col, row)
self.player = Player(self, 5, 5)
self.camera = Camera(self.map.width, self.map.height)
def run(self):
# game loop - set self.playing = False to end the game
self.playing = True
while self.playing:
self.dt = self.clock.tick(FPS) / 1000.0 # fix for Python 2.x
self.events()
self.update()
self.draw()
def quit(self):
pg.quit()
sys.exit()
def update(self):
# update portion of the game loop
self.all_sprites.update()
self.camera.update(self.player)
# mobs hit player
hits = pg.sprite.spritecollide(self.player, self.mobs, False, collide_hit_rect)
for hit in hits:
self.player.health -= MOB_DAMAGE
hit.vel = vec(0, 0)
if self.player.health <= 0:
self.playing = False
if hits:
self.player.pos += vec(MOB_KNOCKBACK, 0).rotate(-hits[0].rot)
# bullets hit mobs
hits = pg.sprite.groupcollide(self.mobs, self.bullets, False, True)
for hit in hits:
hit.health -= BULLET_DAMAGE
hit.vel = vec(0, 0)
def draw_grid(self):
for x in range(0, WIDTH, TILESIZE):
pg.draw.line(self.screen, LIGHTGREY, (x, 0), (x, HEIGHT))
for y in range(0, HEIGHT, TILESIZE):
pg.draw.line(self.screen, LIGHTGREY, (0, y), (WIDTH, y))
def draw(self):
pg.display.set_caption("{:.2f}".format(self.clock.get_fps()))
# self.screen.fill(BGCOLOR)
self.screen.blit(self.map_img, self.camera.apply_rect(self.map_rect))
# self.draw_grid()
for sprite in self.all_sprites:
if isinstance(sprite, Mob):
sprite.draw_health()
self.screen.blit(sprite.image, self.camera.apply(sprite))
# pg.draw.rect(self.screen, WHITE, self.player.hit_rect, 2)
# HUD functions
draw_player_health(self.screen, 10, 10, self.player.health / PLAYER_HEALTH)
pg.display.flip()
def events(self):
# catch all events here
for event in pg.event.get():
if event.type == pg.QUIT:
self.quit()
if event.type == pg.KEYDOWN:
if event.key == pg.K_ESCAPE:
self.quit()
def show_start_screen(self):
pass
def show_go_screen(self):
pass
# create the game object
g = Game()
g.show_start_screen()
while True:
g.new()
g.run()
g.show_go_screen()
sprites.py:
import pygame as pg
from random import uniform
from settings import *
from tilemap import collide_hit_rect
vec = pg.math.Vector2
def collide_with_walls(sprite, group, dir):
if dir == 'x':
hits = pg.sprite.spritecollide(sprite, group, False, collide_hit_rect)
if hits:
if hits[0].rect.centerx > sprite.hit_rect.centerx:
sprite.pos.x = hits[0].rect.left - sprite.hit_rect.width / 2
if hits[0].rect.centerx < sprite.hit_rect.centerx:
sprite.pos.x = hits[0].rect.right + sprite.hit_rect.width / 2
sprite.vel.x = 0
sprite.hit_rect.centerx = sprite.pos.x
if dir == 'y':
hits = pg.sprite.spritecollide(sprite, group, False, collide_hit_rect)
if hits:
if hits[0].rect.centery > sprite.hit_rect.centery:
sprite.pos.y = hits[0].rect.top - sprite.hit_rect.height / 2
if hits[0].rect.centery < sprite.hit_rect.centery:
sprite.pos.y = hits[0].rect.bottom + sprite.hit_rect.height / 2
sprite.vel.y = 0
sprite.hit_rect.centery = sprite.pos.y
class Player(pg.sprite.Sprite):
def __init__(self, game, x, y):
self.groups = game.all_sprites
pg.sprite.Sprite.__init__(self, self.groups)
self.game = game
self.image = game.player_img
self.rect = self.image.get_rect()
self.hit_rect = PLAYER_HIT_RECT
self.hit_rect.center = self.rect.center
self.vel = vec(0, 0)
self.pos = vec(x, y) * TILESIZE
self.rot = 0
self.last_shot = 0
self.health = PLAYER_HEALTH
def get_keys(self):
self.rot_speed = 0
self.vel = vec(0, 0)
keys = pg.key.get_pressed()
if keys[pg.K_LEFT] or keys[pg.K_a]:
self.rot_speed = PLAYER_ROT_SPEED
if keys[pg.K_RIGHT] or keys[pg.K_d]:
self.rot_speed = -PLAYER_ROT_SPEED
if keys[pg.K_UP] or keys[pg.K_w]:
self.vel = vec(PLAYER_SPEED, 0).rotate(-self.rot)
if keys[pg.K_DOWN] or keys[pg.K_s]:
self.vel = vec(-PLAYER_SPEED / 2, 0).rotate(-self.rot)
if keys[pg.K_SPACE]:
now = pg.time.get_ticks()
if now - self.last_shot > BULLET_RATE:
self.last_shot = now
dir = vec(1, 0).rotate(-self.rot)
pos = self.pos + BARREL_OFFSET.rotate(-self.rot)
Bullet(self.game, pos, dir)
self.vel = vec(-KICKBACK, 0).rotate(-self.rot)
def update(self):
self.get_keys()
self.rot = (self.rot + self.rot_speed * self.game.dt) % 360
self.image = pg.transform.rotate(self.game.player_img, self.rot)
self.rect = self.image.get_rect()
self.rect.center = self.pos
self.pos += self.vel * self.game.dt
self.hit_rect.centerx = self.pos.x
collide_with_walls(self, self.game.walls, 'x')
self.hit_rect.centery = self.pos.y
collide_with_walls(self, self.game.walls, 'y')
self.rect.center = self.hit_rect.center
class Mob(pg.sprite.Sprite):
def __init__(self, game, x, y):
self.groups = game.all_sprites, game.mobs
pg.sprite.Sprite.__init__(self, self.groups)
self.game = game
self.image = game.mob_img
self.rect = self.image.get_rect()
self.hit_rect = MOB_HIT_RECT.copy()
self.hit_rect.center = self.rect.center
self.pos = vec(x, y) * TILESIZE
self.vel = vec(0, 0)
self.acc = vec(0, 0)
self.rect.center = self.pos
self.rot = 0
self.health = MOB_HEALTH
def update(self):
self.rot = (self.game.player.pos - self.pos).angle_to(vec(1, 0))
self.image = pg.transform.rotate(self.game.mob_img, self.rot)
# self.rect = self.image.get_rect()
self.rect.center = self.pos
self.acc = vec(MOB_SPEED, 0).rotate(-self.rot)
self.acc += self.vel * -1
self.vel += self.acc * self.game.dt
self.pos += self.vel * self.game.dt + 0.5 * self.acc * self.game.dt ** 2
self.hit_rect.centerx = self.pos.x
collide_with_walls(self, self.game.walls, 'x')
self.hit_rect.centery = self.pos.y
collide_with_walls(self, self.game.walls, 'y')
self.rect.center = self.hit_rect.center
if self.health <= 0:
self.kill()
def draw_health(self):
if self.health > 60:
col = GREEN
elif self.health > 30:
col = YELLOW
else:
col = RED
width = int(self.rect.width * self.health / MOB_HEALTH)
self.health_bar = pg.Rect(0, 0, width, 7)
if self.health < MOB_HEALTH:
pg.draw.rect(self.image, col, self.health_bar)
class Bullet(pg.sprite.Sprite):
def __init__(self, game, pos, dir):
self.groups = game.all_sprites, game.bullets
pg.sprite.Sprite.__init__(self, self.groups)
self.game = game
self.image = game.bullet_img
self.rect = self.image.get_rect()
self.pos = vec(pos)
self.rect.center = pos
spread = uniform(-GUN_SPREAD, GUN_SPREAD)
self.vel = dir.rotate(spread) * BULLET_SPEED
self.spawn_time = pg.time.get_ticks()
def update(self):
self.pos += self.vel * self.game.dt
self.rect.center = self.pos
if pg.sprite.spritecollideany(self, self.game.walls):
self.kill()
if pg.time.get_ticks() - self.spawn_time > BULLET_LIFETIME:
self.kill()
class Wall(pg.sprite.Sprite):
def __init__(self, game, x, y):
self.groups = game.all_sprites, game.walls
pg.sprite.Sprite.__init__(self, self.groups)
self.game = game
self.image = game.wall_img
self.rect = self.image.get_rect()
self.x = x
self.y = y
self.rect.x = x * TILESIZE
self.rect.y = y * TILESIZE
tilemap.py:
import pygame as pg
import pytmx
from settings import *
def collide_hit_rect(one, two):
return one.hit_rect.colliderect(two.rect)
class Map:
def __init__(self, filename):
self.data = []
with open(filename, 'rt') as f:
for line in f:
self.data.append(line.strip())
self.tilewidth = len(self.data[0])
self.tileheight = len(self.data)
self.width = self.tilewidth * TILESIZE
self.height = self.tileheight * TILESIZE
class TiledMap:
def __init__(self, filename):
tm = pytmx.load_pygame(filename, pixelalpha=True)
self.width = tm.width * tm.tilewidth
self.height = tm.height * tm.tileheight
self.tmxdata = tm
def render(self, surface):
ti = self.tmxdata.get_tile_image_by_gid
for layer in self.tmxdata.visible_layers:
if isinstance(layer, pytmx.TiledTileLayer):
for x, y, gid, in layer:
tile = ti(gid)
if tile:
surface.blit(tile, (x * self.tmxdata.tilewidth,
y * self.tmxdata.tileheight))
def make_map(self):
temp_surface = pg.Surface((self.width, self.height))
self.render(temp_surface)
return temp_surface
class Camera:
def __init__(self, width, height):
self.camera = pg.Rect(0, 0, width, height)
self.width = width
self.height = height
def apply(self, entity):
return entity.rect.move(self.camera.topleft)
def apply_rect(self, rect):
return rect.move(self.camera.topleft)
def update(self, target):
x = -target.rect.centerx + int(WIDTH / 2)
y = -target.rect.centery + int(HEIGHT / 2)
# limit scrolling to map size
x = min(0, x) # left
y = min(0, y) # top
x = max(-(self.width - WIDTH), x) # right
y = max(-(self.height - HEIGHT), y) # bottom
self.camera = pg.Rect(x, y, self.width, self.height)
settings.py:
import pygame as pg
vec = pg.math.Vector2
# define some colors (R, G, B)
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
DARKGREY = (40, 40, 40)
LIGHTGREY = (100, 100, 100)
GREEN = (0, 255, 0)
RED = (255, 0, 0)
YELLOW = (255, 255, 0)
BROWN = (106, 55, 5)
# game settings
WIDTH = 1024 # 16 * 64 or 32 * 32 or 64 * 16
HEIGHT = 768 # 16 * 48 or 32 * 24 or 64 * 12
FPS = 60
TITLE = "Tilemap Demo"
BGCOLOR = BROWN
TILESIZE = 64
GRIDWIDTH = WIDTH / TILESIZE
GRIDHEIGHT = HEIGHT / TILESIZE
WALL_IMG = 'tileGreen_39.png'
# Player settings
PLAYER_HEALTH = 100
PLAYER_SPEED = 280
PLAYER_ROT_SPEED = 200
PLAYER_IMG = 'manBlue_gun.png'
PLAYER_HIT_RECT = pg.Rect(0, 0, 35, 35)
BARREL_OFFSET = vec(30, 10)
# Gun settings
BULLET_IMG = 'bullet.png'
BULLET_SPEED = 500
BULLET_LIFETIME = 1000
BULLET_RATE = 150
KICKBACK = 200
GUN_SPREAD = 5
BULLET_DAMAGE = 10
# Mob settings
MOB_IMG = 'zombie1_hold.png'
MOB_SPEED = 150
MOB_HIT_RECT = pg.Rect(0, 0, 30, 30)
MOB_HEALTH = 100
MOB_DAMAGE = 10
MOB_KNOCKBACK = 20
pygame 1.9.6
Hello from the pygame community. https://www.pygame.org/contribute.html
Traceback (most recent call last):
File "C:\Users\wscur\Creative Cloud Files\Creative things (coding)\Tile Game\main.py", line 137, in <module>
g = Game()
File "C:\Users\wscur\Creative Cloud Files\Creative things (coding)\Tile Game\main.py", line 37, in __init__
self.load_data()
File "C:\Users\wscur\Creative Cloud Files\Creative things (coding)\Tile Game\main.py", line 43, in load_data
self.map = TiledMap(path.join(map_folder, 'level1.tmx'))
File "C:\Users\wscur\Creative Cloud Files\Creative things (coding)\Tile Game\tilemap.py", line 22, in __init__
tm = pytmx.load_pygame(filename, pixelalpha=True)
File "C:\Users\wscur\AppData\Local\Programs\Python\Python36-32\lib\site-packages\pytmx\util_pygame.py", line 141, in load_pygame
return pytmx.TiledMap(filename, *args, **kwargs)
File "C:\Users\wscur\AppData\Local\Programs\Python\Python36-32\lib\site-packages\pytmx\pytmx.py", line 360, in __init__
self.parse_xml(ElementTree.parse(self.filename).getroot())
File "C:\Users\wscur\AppData\Local\Programs\Python\Python36-32\lib\site-packages\pytmx\pytmx.py", line 391, in parse_xml
self.add_layer(TiledTileLayer(self, subnode))
File "C:\Users\wscur\AppData\Local\Programs\Python\Python36-32\lib\site-packages\pytmx\pytmx.py", line 962, in __init__
self.parse_xml(node)
File "C:\Users\wscur\AppData\Local\Programs\Python\Python36-32\lib\site-packages\pytmx\pytmx.py", line 1072, in parse_xml
self.data[y][x] = reg(*decode_gid(next(next_gid)))
File "C:\Users\wscur\AppData\Local\Programs\Python\Python36-32\lib\site-packages\pytmx\pytmx.py", line 1052, in get_children
yield int(child.get('gid'))
TypeError: int() argument must be a string, a bytes-like object or a number, not 'NoneType'
答案 0 :(得分:0)
此错误表示您正在尝试使用无法将None
对象作为参数的方法int
将int()
对象转换为None
。
因为这里发生错误:
yield int(child.get('gid'))
它表示child.get('gid')
返回None
。
您可以通过添加无检查或尝试尝试来避免此错误,除了TypeError
之外。