目前,我根据找到的链接尝试这款射击游戏。但是我想更改子弹属性,但是我不了解物理并将其编码。我想让子弹以弹丸的方式运动。有人可以帮我编码吗?
这是一些代码:
DbContext
答案 0 :(得分:0)
从本质上讲,弹丸运动意味着有两个力作用在弹丸上-有初始速度(沿某个方向)和重力。当弹丸在空间和时间中移动时,可以通过应用速度,重力和时间来计算弹丸的轨迹(其移动路径)。
我在这里不打算使用公式,只需使用它们即可。阅读wikipedia article中有关弹丸运动的说明。基本上,要移动弹丸,我们只需要计算它的displacement。本质上,您可以像处理水平和垂直变化一样处理对象的运动。
因此,让我们创建一个简单的精灵对象,该对象以弹丸运动移动。为了简单起见,我们将使用PyGame Sprite类(及其提供的预先存在的库代码的全部内容)。
所以,我们需要一个图像,xy位置,起始角度和速度。
class Projectile( pygame.sprite.Sprite ):
GRAVITY = -9.8 # Earth
def __init__( self, bitmap, start_x, start_y, velocity=0, angle=0 ):
pygame.sprite.Sprite.__init__( self )
self.image = bitmap
self.rect = bitmap.get_rect()
self.start_x = start_x
self.start_y = start_y
self.rect.center = ( ( start_x, start_y ) )
# Physics
self.start_time = pygame.time.get_ticks() # "now" in milliseconds
self.velocity = velocity
self.angle = math.radians( angle ) # Note: convert Degrees to Radians
就是这样。我们可以创建一个像这样的射弹:
rock = Projectile( rock_image, 10, 100, 50, 60 )
以(rock,image)绘制投射物,以(50,100)开始,速度为50,角度为60度。
要注意的一件事是,数学库中的角度通常在radians中指定(不是度数)。我无法以弧度来考虑,因此我在课堂外使用学位。这是您的代码,不过可以按自己的方式编写。
速度有点奇怪,因为通常您以米/秒为单位进行此类计算,这里是以毫秒/像素为单位,但是我不想赘述,因为它是无关紧要的,并且按比例缩放离开一个数字。
所以现在我们需要添加机芯。 PyGame精灵的移动由update()
函数处理。因此,我们需要编写此函数,以便在将来的任何给定时间中,可以得出绘制“ rock_image”的位置的x
和y
坐标。因此引用wikipedia's formulae:
x = start_velocity * time_now * cos(start_angle)
y = start_velocity * time_now * sin(start_angle)-½*重力*time_now²
这为我们提供了Projectile.update()
函数:
def update( self ):
time_now = pygame.time.get_ticks()
if ( self.velocity > 0 ):
time_change = ( time_now - self.start_time )
if ( time_change > 0 ):
time_change /= 100.0 # fudge for metres/second to pixels/millisecond
# re-calculate the displacement
# x
displacement_x = self.velocity * time_change * math.sin( self.angle )
# y
half_gravity_time_squared = self.GRAVITY * time_change * time_change / 2.0
displacement_y = self.velocity * time_change * math.cos( self.angle ) + half_gravity_time_squared
# reposition sprite (subtract y, because in pygame 0 is screen-top)
self.rect.center = ( ( self.start_x + int( displacement_x ), self.start_y - int( displacement_y ) ) )
显然,这需要更新,以便仅在仍在屏幕上时更新子画面等。我们与教科书的计算也略有不同,因为在PyGame中,肯定-Y在屏幕上向下(而通常,正Y是 up )。
因此,将所有这些放在一起,这是一个简短的演示,该演示在屏幕的中央底部创建了20个弹丸,并以随机的速度稍微向上指向:
import pygame
import random
import math
# Window size
WINDOW_WIDTH = 800
WINDOW_HEIGHT = 400
FPS = 60
# background colours
INKY_GREY = ( 128, 128, 128 )
INITIAL_VELOCITY_LOW = 10 # pixels per millisecond (adjusted later)
INITIAL_VELOCITY_HIGH = 100
LAUNCH_ANGLE = 80 # random start-angle range
class Projectile( pygame.sprite.Sprite ):
GRAVITY = -9.8
def __init__( self, bitmap, start_x, start_y, velocity=0, angle=0 ):
pygame.sprite.Sprite.__init__( self )
self.image = bitmap
self.rect = bitmap.get_rect()
self.start_x = start_x
self.start_y = start_y
self.rect.center = ( ( start_x, start_y ) )
# Physics
self.start_time = pygame.time.get_ticks() # "now" in milliseconds
self.velocity = velocity
self.angle = math.radians( angle ) # Note: convert Degrees to Radians
def update( self ):
time_now = pygame.time.get_ticks()
if ( self.velocity > 0 and self.rect.y < WINDOW_HEIGHT - self.rect.height ):
time_change = ( time_now - self.start_time )
if ( time_change > 0 ):
time_change /= 100.0 # fudge for metres/second to pixels/millisecond
# re-calculate the displacement
# x
displacement_x = self.velocity * time_change * math.sin( self.angle )
# y
half_gravity_time_squared = self.GRAVITY * time_change * time_change / 2.0
displacement_y = self.velocity * time_change * math.cos( self.angle ) + half_gravity_time_squared
# reposition sprite
self.rect.center = ( ( self.start_x + int( displacement_x ), self.start_y - int( displacement_y ) ) )
# Stop at the bottom of the window
if ( self.rect.y >= WINDOW_HEIGHT - self.rect.height ):
self.rect.y = WINDOW_HEIGHT - self.rect.height
self.velocity = 0
self.kill() # remove the sprite
### MAIN
pygame.init()
SURFACE = pygame.HWSURFACE | pygame.DOUBLEBUF | pygame.RESIZABLE
window = pygame.display.set_mode( ( WINDOW_WIDTH, WINDOW_HEIGHT ), SURFACE )
pygame.display.set_caption("Projectile Motion Example")
# Load resource image(s)
sprite_image = pygame.image.load( "ball.png" )#.convert_alpha()
# Make some sprites
screen_centre_x = WINDOW_WIDTH // 2
screen_bottom_y = WINDOW_HEIGHT - 10
SPRITES = pygame.sprite.Group()
for i in range( 20 ):
speed = random.randrange( INITIAL_VELOCITY_LOW, INITIAL_VELOCITY_HIGH ) # metres per second
angle = random.randrange( -LAUNCH_ANGLE, LAUNCH_ANGLE )
new_sprite = Projectile( sprite_image, screen_centre_x, screen_bottom_y, speed, angle )
SPRITES.add( new_sprite )
# 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
# Repaint the screen
window.fill( INKY_GREY )
SPRITES.update() # re-position the sprites
SPRITES.draw( window ) # draw the sprites
# Update the window, but not more than 60fps
pygame.display.flip()
clock.tick_busy_loop( FPS )
pygame.quit()
样式注:如果条件,我会始终将它们放在方括号中。这违反了PEP8,但我认为它使代码更具可读性。