在我的第一个项目上工作时,我试图对敌人的动作进行分类,下面的代码是我当前的实现。敌人使用玩家位置(target.pos.x)与他们的pos.x之间的距离。希望敌人向左移动20步,然后改变方向,向右移动20步,冲洗并重复。
self.target = game.player
def movement(self):
self.acc = vec(0, BOSS_GRAVITY)
if (-17 >= (self.pos.x - self.target.pos.x) >= -200) and self.target.hit_rect.y == self.hit_rect.y:
self.vel.x -= BOSS_SPEED * -1
self.enemy_direction = 'R'
if (200 >= (self.pos.x - self.target.pos.x) >= 17) and self.target.hit_rect.y == self.hit_rect.y:
self.vel.x += BOSS_SPEED * -1
self.enemy_direction = 'L'
self.acc.x += self.vel.x * BOSS_FRICTION
self.vel += self.acc
self.pos += self.vel
self.pos += self.vel + 0.5 * self.acc
我希望我的敌人向右移动一定量,然后改变速度,然后以相反的方式保持静止。
我希望敌人向左移动20步,然后改变方向,向右移动20步,冲洗并重复。
好的,我们如何实现这一目标?首先是一些定义:
什么是“步伐”?让我们从开始5 pixels
。左边是-x
; 对+x
。
还有一些额外的事情要照顾。当对象无法沿所需方向移动时该怎么办?可以turn around
。
因此,我们需要保留有关该敌人的大量统计信息:位置,步数和行进方向。一旦有了一些基准点,请思考:数据结构。现在,我将所有这些内容放入Python类中,但也可以将其放入一个简单列表中。但是,这些数据多于几个点,因此变得笨拙。
# As a list
enemy_image = pygame.image.load( "doomba.png" ).convert_alpha()
enemy_rect = enemy_image.get_rect()
enemy_rect.center = ( x, y )
enemy1 = [ enemy_rect, enemy_image, PACE_SIZE, TURN_SIZE ]
作为一个班级要好得多:
# As a sprite class
class Enemy( pygame.sprite.Sprite ):
def __init__( self, x, y, bitmap, pace=5, turn_after=20 ):
""" Create a new Enemy at that is drawn at (x,y) as the /bitmap/.
It moves /pace/ pixels each step, left, then right """
pygame.sprite.Sprite.__init__( self )
self.image = pygame.image.load( bitmap ).convert_alpha()
self.rect = self.image.get_rect()
self.rect.center = ( x, y ) # location
self.pace_size = pace # How big each step is
self.pace_count = 0 # distance moved
self.direction = -1 # Start moving left (-x)
self.turn_after = turn_after # distance limit
(我已经基于PyGame Sprite制作了数据结构,因为它仅花费两行代码,并提供了许多预建功能。)
现在,我们有了一个数据结构(名为Enemy
),其中包含一个位置,大小,位图,并记住它走了多远以及向哪个方向移动。但是,它尚未实现任何形式的运动算法。因此,我们添加一下。
Sprite类希望将此算法写入名为的函数中update()
。每个帧都会调用此函数,以决定该帧的运动。这可能是不动产,或其他。可以是任何东西。
在这里您可以看到我们正在计算移入的步数self.pace_count
,然后根据步长()调整位图的x
位置(保持在)。如果敌人向左移动,则需要减去步速大小,向右则增加步速大小。我们可以通过我们在添加量乘以自动执行此操作,无论是或。每当敌人转身时就设置方向值。self.rect
self.pace_size
self.direction
-1
1
def update( self ):
""" Implement the movement algorithm """
# Walk pace in the current direction
self.pace_count += 1
self.rect.x += self.direction * self.pace_size # Move some pixels
# We need to turn around if walked enough paces in the same direction
if ( self.pace_count >= self.turn_after ):
# Turn around!
self.direction *= -1 # reverses the pixel distance
self.pace_count = 0 # reset the pace count
# We also should change direction if we hit the screen edge
if ( self.rect.x <= 0 ):
self.direction = 1 # turn right
self.pace_count = 0
elif ( self.rect.x >= WINDOW_WIDTH - self.rect.width ):
self.direction = -1
self.pace_count = 0
因此,当敌人按照设定的步数行走时,方向会反转并且步数最终归零。但是,如果我们撞到屏幕的一侧,我们还需要调头。发生这种情况时,只有一种明显的转弯方法,因此方向绝对会改变,而不是反向。该代码可能会变得更简单,因为它每次基本上都执行几乎相同的操作。但是,我已经花了更长的时间来清楚地说明所涉及的步骤。
而且,算法得以实现。看着演示,它的方式太快。因此,我们还要结合实时速度。
控制运动速度的一种简单方法是在步骤之间设置延迟。首先确定敌人移动的频率(例如,每100毫秒),存储self.speed
一次,然后采取最后一步的时间self.pace_time
。然后,当需要更新时,请查看PyGame时钟,看看是否经过了足够的毫秒,然后才移动敌人。否则什么都不做。
def update( self ):
""" Implement the movement algorithm """
time_now = pygame.time.get_ticks() # what time is it
if ( time_now > self.pace_time + self.speed ): # time to move again?
self.pace_time = time_now # remember move time
# Walk pace in the current direction
self.pace_count += 1
这给出了更静定的动作。我调整了敌人以使其更频繁地移动,但步幅较小。因此,现在它也不会遍历整个窗口。将速度控制为时间的函数,而不是帧速率,这一点很重要。例如,如果我只是将pace
尺寸0.2
像素设置为上方,请确保将蘑菇放慢到一定速度。但这仅在我的计算机上是准确的。如果帧速率仅为21 FPS,突然又降低了2/3,该怎么办?如果帧率为160 FPS怎么办?那将是超快的。因此,请保持由实时毫秒(而不是帧速率和距离)控制的任何类型的速度和运动。
无论如何,这足以让您继续使用自己的运动算法。如果对代码有疑问,请发表评论。
参考代码:
import pygame
# Window size
WINDOW_WIDTH = 600
WINDOW_HEIGHT = 400
WINDOW_SURFACE = pygame.HWSURFACE|pygame.DOUBLEBUF
DARK_BLUE = ( 3, 5, 54)
class Enemy( pygame.sprite.Sprite ):
def __init__( self, x, y, pace, bitmap, turn_after=20, speed=100 ):
""" Create a new Enemy at that is drawn at (x,y) as the /bitmap/.
It moves /pace/ pixels left, then right """
pygame.sprite.Sprite.__init__( self )
self.image = pygame.image.load( bitmap ).convert_alpha()
self.rect = self.image.get_rect()
self.rect.center = ( x, y ) # location
self.pace_size = pace # How big each step is
self.pace_count = 0 # distance moved
self.direction = -1 # Start moving left (-x)
self.turn_after = turn_after # distance limit
self.speed = speed # Milliseconds per pace
self.pace_time = 0 # time of last step
def update( self ):
""" Implement the movement algorithm """
time_now = pygame.time.get_ticks() # what time is it
if ( time_now > self.pace_time + self.speed ): # is it time to move again
self.pace_time = time_now
# Walk pace in the current direction
self.pace_count += 1
self.rect.x += self.direction * self.pace_size # Move some pixels
# We need to turn around if walked enough paces in the same direction
if ( self.pace_count >= self.turn_after ):
# Turn around!
self.direction *= -1 # reverses the pixel distance
self.pace_count = 0 # reset the pace count
# We also should change direction if we hit the screen edge
if ( self.rect.x <= 0 ):
self.direction = 1 # turn right
self.pace_count = 0
elif ( self.rect.x >= WINDOW_WIDTH - self.rect.width ):
self.direction = -1
self.pace_count = 0
### initialisation
pygame.init()
pygame.mixer.init()
window = pygame.display.set_mode( ( WINDOW_WIDTH, WINDOW_HEIGHT ), WINDOW_SURFACE )
pygame.display.set_caption("Movement Algorithm Example")
### Sprite and Sprite Group
pos_x = WINDOW_WIDTH//2
pos_y = WINDOW_HEIGHT//2
pace_size = 7
enemy = Enemy( pos_x, pos_y, pace_size, "mushroom.png" )
all_sprites_group = pygame.sprite.Group()
all_sprites_group.add( enemy )
### Main Loop
clock = pygame.time.Clock()
done = False
while not done:
# Handle user-input
for event in pygame.event.get():
if ( event.type == pygame.QUIT ):
done = True
elif ( event.type == pygame.MOUSEBUTTONUP ):
# On mouse-click
pass
elif ( event.type == pygame.KEYUP ):
pass
# Movement keys
#keys = pygame.key.get_pressed()
#if ( keys[pygame.K_UP] ):
# print("up")
# Update the window, but not more than 60fps
all_sprites_group.update()
window.fill( DARK_BLUE )
all_sprites_group.draw( window )
pygame.display.flip()
# Clamp FPS
clock.tick_busy_loop(60)
pygame.quit()
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句