完整的游戏代码:http://pastebin.com/v9UvDYWy
我觉得我做错了...我有一个游戏类,它有一个加载器方法,然后是一个玩家类。玩家类需要向游戏类的加载器方法询问其图像,并且当它发射子弹时(使用子弹类)它再次需要询问子弹图像......这就是我现在拥有的... < / p>
class Player(pygame.sprite.Sprite):
""" This class represents the player. """
mouse = True
def __init__(self, caller):
pygame.sprite.Sprite.__init__(self)
self.image = caller.PLAYER_IMAGE
self.rect = self.image.get_rect()
self.mask = pygame.mask.from_surface(self.image)
def update(self):
""" Update the player location. """
if self.mouse:
self.rect.center = pygame.mouse.get_pos() # center player to mouse
self.rect.y = SCREEN_HEIGHT-130 # lock player to bottom of screen
class Bullet(pygame.sprite.Sprite):
speed = 0
""" This Class Represents a Bullet"""
def __init__(self, caller):
#call the parent class constructor
pygame.sprite.Sprite.__init__(self)
self.image = caller.BULLET_IMAGE
self.rect = self.image.get_rect()
self.mask = pygame.mask.from_surface(self.image)
self.speed = 8
def update(self):
"""Move Bullet"""
self.rect.y -= self.speed
目前我的游戏类有一个方法“射击”,但我觉得玩家类应该是拥有这个方法的人......但是如果我这样做那么Player类和Bullet类之间的引用会变得混乱。游戏应该是保持子弹列表等的游戏,以便它可以检查碰撞但是如果玩家是启动子弹类的玩家那么玩家对象需要一种引用游戏对象的方式来创建该列表那里。
这是子弹碰撞逻辑:
for bullet in self.bullet_list:
# check if the lasers(bullet) hit anything in the block list(enemies)
bullet_hit_list = pygame.sprite.spritecollide(bullet, self.block_list, True,collided=pygame.sprite.collide_mask)
for block in bullet_hit_list:
self.bullet_list.remove(bullet)
self.all_sprites_list.remove(bullet)
self.score += block.scorevalue
if bullet.rect.y < -10: # remove bullet if it goes off screen
self.bullet_list.remove(bullet)
self.all_sprites_list.remove(bullet)
我知道我的问题不是很清楚,但我不知道怎么说得更清楚...所以我改变了代码,所以玩家有方法射击..注意玩家现在需要暂时保持子弹图像,因为子弹类不知道如何找到它。
class Player(pygame.sprite.Sprite):
""" This class represents the player. """
mouse = True
bullet_list = None
def __init__(self, caller):
pygame.sprite.Sprite.__init__(self)
self.bullet_list = pygame.sprite.Group()
self.image = caller.PLAYER_IMAGE
self.BULLET_IMAGE = caller.BULLET_IMAGE
self.rect = self.image.get_rect()
self.mask = pygame.mask.from_surface(self.image)
def shoot(self,caller):
if len(self.bullet_list) < 3:
bullet = Bullet(self)
# Set the bullet so it is where the player is(and centered)
bullet.rect.center = self.rect.center
# Add the bullet to the lists
#pygame.Surface.fill(self.bullet.image,RED)
caller.all_sprites_list.add(bullet)
self.bullet_list.add(bullet)
#Play Bullet sound
caller.sound_bullet_fire.play()
def update(self):
""" Update the player location. """
if self.mouse:
self.rect.center = pygame.mouse.get_pos() # center player to mouse
self.rect.y = SCREEN_HEIGHT-130 # lock player to bottom of screen
class Bullet(pygame.sprite.Sprite):
speed = 0
""" This Class Represents a Bullet"""
def __init__(self, caller):
#call the parent class constructor
pygame.sprite.Sprite.__init__(self)
self.image = caller.BULLET_IMAGE
self.rect = self.image.get_rect()
self.mask = pygame.mask.from_surface(self.image)
self.speed = 8
def update(self):
"""Move Bullet"""
self.rect.y -= self.speed
答案 0 :(得分:0)
由于您已将caller
传递到Player.shoot
,为什么不将其传递给Bullet
的初始值设定项?
class Player(pygame.sprite.Sprite):
...
def shoot(self,caller):
if len(self.bullet_list) < 3:
bullet = Bullet(self, caller)
答案 1 :(得分:0)
我有一个pygame游戏,也管理射弹。它有类似的困境。我发现最有效的方法是让子弹类管理自己的图像,并让玩家管理其所有附属子弹,调用子弹需要更新的子弹中包含的任何功能。角色还包含投射子弹的功能。所有游戏都将管理子弹(我将所有在屏幕上定期更新的内容更新为渲染更新组)。这段代码有点普遍,但它对于弹丸管理非常有效,我使用这个基本的大型机快速制作了几个游戏:
class Moveable(pygame.sprite.Sprite):
def __init__(self,pos,imageFileName):
pygame.sprite.Sprite.__init__(self)
self.init2(pos,imageFileName)
def init2(self,pos,imageFileName):
self.right = pygame.image.load(imageFileName).convert_alpha()
self.left = pygame.transform.flip(self.right,True,False)
self.vertical = pygame.transform.rotate(self.right,90)
self.image = self.right
if self not in projectiles:
self.direction = "right"
self.rect = self.image.get_rect()
self.rect.center = pos
def move(self,dx,dy):
if self in special:
pygame.display.update(special.draw(screen))
#print COLOR
screen.fill((COLOR),self.rect)
#print COLOR
if dx > 0:
self.image = self.right
if self not in projectiles:
self.direction = "right"
elif dx < 0:
self.image = self.left
if self not in projectiles:
self.direction = "left"
collisions = pygame.sprite.spritecollide(self, collidable, False)
for other in collisions:
if other != self:
(awayDx,awayDy) = self.moveRelative(other,-1)
if abs(dx + 1*(awayDx)) < abs(dx):
dx = 0
if abs(dy + 1*(awayDy)) < abs(dy):
dy = 0
dx = dx + 1*(awayDx)
dy = dy + 1*(awayDy)
for item in gravities:
if item != self:
(toDx,toDy) = self.moveRelative(item,1)
dx = dx + (item.force*(toDx))/(self.rangeTo(item)/100)
dy = dy + (item.force*(toDy))/(self.rangeTo(item)/100)
self.rect.move_ip(dx,dy)
def moveRelative(self,other,speed,exact=False):
dx = other.rect.x - self.rect.x
dy = other.rect.y - self.rect.y
if exact == False:
if abs(dx) > abs(dy):
# other is farther away in x than in y
if dx > 0:
return (+speed,0)
else:
return (-speed,0)
else:
if dy > 0:
return (0,+speed)
else:
return (0,-speed)
else:
angle = math.atan2(dx,dy)
newx = speed*math.cos(angle)
newy = speed*math.sin(angle)
return (newy,newx)
def movePerpendicular(self,other,speed):
dx = other.rect.x - self.rect.x
dy = other.rect.y - self.rect.y
if abs(dx) > abs(dy):
# this is to dodge a projectile
if dy > 0:
if dx > 0:
return (+speed/2,+speed)
else:
return (-speed/2,+speed)
else:
if dx > 0:
return (+speed/2,-speed)
else:
return (-speed/2,-speed)
else:
if dx > 0:
if dy > 0:
return (+speed,+speed/2)
else:
return (+speed,-speed/2)
else:
if dy > 0:
return (-speed,+speed/2)
else:
return (-speed,-speed/2)
def rangeTo(self,other):
dx = other.rect.x - self.rect.x
dy = other.rect.y - self.rect.y
return math.sqrt(dx*dx + dy*dy)
class Stationary(pygame.sprite.Sprite):
def __init__(self,pos,imageFileName,collide,impermeable=False,alpha=False):
pygame.sprite.Sprite.__init__(self)
self.init2(pos,imageFileName,collide,alpha)
self.impermeable = impermeable
def init2(self,pos,imageFileName,collide,alpha):
drawn.add(self)
updated.add(self)
if collide:
collidable.add(self)
if alpha:
self.image = pygame.image.load(imageFileName).convert_alpha()
else:
self.image = pygame.image.load(imageFileName).convert()
self.rect = self.image.get_rect()
self.rect.center = pos
def rangeTo(self,other):
dx = other.rect.x - self.rect.x
dy = other.rect.y - self.rect.y
return math.sqrt(dx*dx + dy*dy)
class unit(Moveable):
def __init__(self,pos,image,health,projectile_count,fire_rate,team,speed,impermeable=False,special_reload={}):
Moveable.__init__(self,pos,image)
self.projectiles = []
for number in range(projectile_count):
self.projectiles.append(None)
self.health = health
self.team = team
team.add(self)
drawn.add(self)
collidable.add(self)
updated.add(self)
self.firetime = fire_rate
self.fire_rate = fire_rate
self.reload = special_reload
self.speed = speed
self.impermeable = impermeable
def maintain(self):
self.firetime -= 1
for item in self.reload:
self.reload[item][0] -= 1
index = 0
for projectile in self.projectiles:
if projectile != None:
if projectile.update() == False:
projectile.end()
self.projectiles[index] = None
index += 1
collisions = pygame.sprite.spritecollide(self, damagers, False)
for other in collisions:
if other != self and other.parent != self:
try:
self.health -= other.damage
except AttributeError:
print "Error: Unit Damage Collisions:", other.__name__, "lacks the attribute self.damage used to damage object"
raise RuntimeError
if self.health <= 0:
self.end()
def project(self,bolt,speed=6,direction=None,target=None,accuracy=None,aimed=False):
if bolt not in self.reload.keys():
if self.firetime > 0:
pass
else:
if direction == None:
if aimed == True:
direction = self.moveRelative(target,speed,exact=True)
else:
direction = self.moveRelative(target,speed)
index = 0
for projectile in self.projectiles:
if projectile == None:
self.projectiles[index] = bolt(self.rect.center,direction,self)
projectiles.add(self.projectiles[index])
updated.add(self.projectiles[index])
break
index += 1
self.firetime = self.fire_rate
else:
if self.reload[bolt][0] > 0:
pass
else:
if direction == None:
direction = self.moveRelative(target,speed)
index = 0
for projectile in self.projectiles:
if projectile == None:
self.projectiles[index] = bolt(self.rect.center,direction,self)
projectiles.add(self.projectiles[index])
updated.add(self.projectiles[index])
break
index += 1
self.reload[bolt][0] = self.reload[bolt][1]
def end(self):
for projectile in self.projectiles:
if projectile != None:
projectile.end()
drawn.remove(self)
collidable.remove(self)
updated.remove(self)
special.remove(self)
damagers.remove(self)
explosion_triggers.remove(self)
self.team.remove(self)
screen.fill(COLOR,self.rect)
def goup(self):
self.directions = (0,-1)
self.inertia()
def godown(self):
self.directions = (0,1)
self.inertia()
def goleft(self):
self.directions = (-1,0)
self.inertia()
def goright(self):
self.directions = (1,0)
self.inertia()
def magnitude(self,factor):
return (self.directions[0]*factor,self.directions[1]*factor)
def inertia(self):
self.move(*self.magnitude(self.speed))
def shoot(self,bolt):
self.project(bolt,direction=self.magnitude(10))
def aimshoot(self,bolt,vector):
self.project(bolt,direction=vector)
class projectile(Moveable):
def __init__(self,pos,direction,image,destructcount,damager=False,boomtrigger=False,simple=True,parent=None,arc=False,explodable=False,countdown=None):
Moveable.__init__(self,pos,image)
self.arc=arc
self.destructCountDown = destructcount
self.full = destructcount
if self.arc == True:
magnitude = math.sqrt(direction[0]*direction[0]+direction[1]*direction[1])
if explodable == True:
time = float(self.full)-float(countdown)/2.0
else:
time = float(self.full)/2.0
self.change = float(magnitude)/float(time)
self.parent = parent
drawn.add(self)
if boomtrigger != False:
explosion_triggers.add(self)
if damager != False:
self.damage = damager
damagers.add(self)
self.directions = list(direction)
self.explodable = explodable
self.delay = 0
if simple == True:
if abs(self.directions[1]) > abs(self.directions[0]):
self.image = self.vertical
self.rect = self.image.get_rect()
self.rect.center = pos
else:
self.image = pygame.transform.rotate(self.vertical,math.degrees(math.atan2(direction[0],direction[1])))
self.rect = self.image.get_rect()
self.rect.center = pos
def update(self):
if self.delay > 0:
self.delay -= 1
else:
screen.fill((COLOR),self.rect)
collisions = pygame.sprite.spritecollide(self, collidable, False)
for other in collisions:
if other != self:
if other.impermeable == True:
self.end()
return False
self.destructCountDown = self.destructCountDown - 1
if self.explodable == True:
if self.destructCountDown == self.countdown:
self.destruct()
if self.destructCountDown <= 0:
return False
else:
if self.explodable == True:
if self.exploded == False:
if self.arc == True:
print self.destructCountDown, (self.full-self.countdown)/2
if self.destructCountDown > (self.full-self.countdown)/2:
self.rect.move_ip(*self.directions)
self.directions[0], self.directions[1] = self.adjustmag(self.directions[0], self.directions[1],-1)
else:
self.rect.move_ip(*self.directions)
self.directions[0], self.directions[1] = self.adjustmag(self.directions[0], self.directions[1],1)
else:
self.rect.move_ip(*self.directions)
else:
if self.arc == True:
if self.destructCountDown > self.full/2:
self.rect.move_ip(*self.directions)
self.directions[0], self.directions[1] = self.adjustmag(self.directions[0], self.directions[1],-1)
else:
self.rect.move_ip(*self.directions)
self.directions[0], self.directions[1] = self.adjustmag(self.directions[0], self.directions[1],1)
else:
self.rect.move_ip(*self.directions)
return True
def adjustmag(self,x,y,change):
angle = math.atan2(y,x)
print "x, y: ", x, y
magnitude = math.sqrt(x*x+y*y)
print "magnitude: ", magnitude
if magnitude > 1 and change < 0:
magnitude = float(magnitude) + float(change)
elif change > 0:
magnitude = float(magnitude) + float(change)
nx = math.cos(angle)*float(magnitude)
ny = math.sin(angle)*float(magnitude)
return nx, ny
def end(self):
drawn.remove(self)
collidable.remove(self)
updated.remove(self)
damagers.remove(self)
explosion_triggers.remove(self)
此代码是较大程序的一部分,如果你运行它不会起作用,它还包括你不应该需要的一些功能,但这是一个很好的,很好实现的如何射弹的例子应该是有条理的。然而,基本思想是单元管理射弹的更新并具有射击它们的功能,射弹具有内部更新功能,可以在初始化时作为精灵移动,管理自己的图像(它们是自己的类),以及在更新功能中管理他们自己的毁灭,他们可以返回到玩家,游戏将绘制所有内容。