我如何在 Pygame 中制作基本的汽车物理?

Hab*_*ail 6 python pygame

在此处输入图片说明

我想知道如何使用箭头键制作一辆可以移动和旋转的汽车。我正在尝试制作一个汽车物理游戏,玩家可以在其中控制汽车并四处行驶和停车,但是我在如何开始实施控制方面遇到了麻烦。我怎样才能让我的车用箭头键沿着它旋转的方向移动?

例如,如果我按下后退箭头键,汽车应该倒车,如果汽车在倒车的同时也在转弯,它应该按照汽车转弯的方式移动。

这是我现在的代码。现在真的没有任何事情发生。

import pygame
pygame.init()

window = pygame.display.set_mode((800,800))
pygame.display.set_caption("car game")

class car:
    def __init__(self,x,y,height,width,color):
        self.x = x
        self.y = y
        self.height = height
        self.width = width
        self.color = color
        self.carimage = pygame.image.load("1.png")
        self.rect = pygame.Rect(x,y,height,width)
    def draw(self):
        self.rect.topleft = (self.x,self.y)
        window.blit(self.carimage,self.rect)

white = (255,255,2555)
car1 = car(300,300,20,20,white)

def ReDrawWindow():
    car1.draw()

# main loop
runninggame = True
while runninggame:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            runninggame = False
    ReDrawWindow()
    pygame.display.update()

pygame.quit()   
Run Code Online (Sandbox Code Playgroud)

Ray*_*Ray 5

这是改进后的代码:

import pygame, math
pygame.init()

window = pygame.display.set_mode((600,600))
pygame.display.set_caption("car game")
img = pygame.image.load("1.png")

class Car:
    def __init__(self, x, y, height, width, color):
        self.x = x - width / 2
        self.y = y - height / 2
        self.height = height
        self.width = width
        self.color = color
        self.rect = pygame.Rect(x, y, height, width)
        self.surface = pygame.Surface((height, width)) # 1
        self.surface.blit(img, (0, 0))
        self.angle = 0
        self.speed = 0 # 2

    def draw(self): # 3
        self.rect.topleft = (int(self.x), int(self.y))
        rotated = pygame.transform.rotate(self.surface, self.angle)
        surface_rect = self.surface.get_rect(topleft = self.rect.topleft)
        new_rect = rotated.get_rect(center = surface_rect.center)
        window.blit(rotated, new_rect.topleft)

white = (255, 255, 255)
car1 = Car(300, 300, 73, 73, white) # 4
clock = pygame.time.Clock()

runninggame = True
while runninggame:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            runninggame = False
    
    pressed = pygame.key.get_pressed()
    car1.speed *= 0.9 # 5
    if pressed[pygame.K_UP]: car1.speed += 0.5 # 6
    if pressed[pygame.K_DOWN]: car1.speed -= 0.5 # 6

    if pressed[pygame.K_LEFT]: car1.angle += car1.speed / 2 # 7
    if pressed[pygame.K_RIGHT]: car1.angle -= car1.speed / 2 # 7
    car1.x -= car1.speed * math.sin(math.radians(car1.angle)) # 8
    car1.y -= car1.speed * math.cos(math.radians(-car1.angle)) # 8
    
    window.fill((0, 0, 0)) # 9
    car1.draw()
    pygame.display.flip()
    clock.tick(60) # 10

pygame.quit()
Run Code Online (Sandbox Code Playgroud)

需要注意的一些事项:

  1. 我创建了一个用于绘制图片的新表面。这使它更容易旋转。
  2. 我为汽车创建了一个速度变量来存储它的速度。我稍后用它来获得动力。
  3. draw 函数逆时针旋转图像,因为这就是 Pygame 的工作方式。查看我使用的代码。
  4. 我用的汽车尺寸是73、73。把这个做成你图片的宽度和高度,否则汽车不能正常转弯。
  5. 我会稍微降低速度,这样当你不向前按压时,汽车会继续行驶一会儿。
  6. 当汽车前后移动时,其最大速度为每帧 5 个像素。(因为 5 * 0.9 + 0.5 = 5。)
  7. 汽车转弯的角度取决于速度。
  8. 这是我之前想说的三角学。因为 math.sin 和 math.cos 使用弧度,所以我必须将度数转换为弧度。
  9. 我用黑色填充了屏幕,这样你就不会看到早期的帧。
  10. clock.tick是用来防止它走得太快,它的意思是“最高每秒60帧的”。

我希望你明白一切。


Kin*_*ley 4

我想为这个问题添加一个基于 PyGame Sprite 的答案。将此类事情实现为精灵可以更轻松地使用 PyGame 碰撞函数。例如,可以制作任意数量的 CarSprite,但它们的碰撞会在一次调用中与玩家的 CarSrpite 进行检查groupcollide()

\n

该实现使用PyGame.math.Vector2()速度和位置。这允许利用 Vector2 的极坐标函数建立相当简单的转弯和速度模型。最初,这给出了奇怪且令人困惑的结果......直到我意识到Vector2.from_polar()所需的角度(以度为单位)。(与几乎所有其他采用角度的编程语言函数不同,不是弧度。)

\n

最初创建精灵时,代码将生成许多预先旋转的图像。这可以以大约每度 1 度 (360) 的速度实现最平滑的转动,但如果内存使用是一个问题,它也可能会少得多。

\n

无论如何,代码是相当不言自明的。它需要一个car_128.png图像和一个背景纹理图像road_texture.png。有任何问题请评论。

\n

演示图像

\n
import pygame\nimport math\n\n# Window size\nWINDOW_WIDTH    = 600\nWINDOW_HEIGHT   = 600\nWINDOW_SURFACE  = pygame.HWSURFACE|pygame.DOUBLEBUF|pygame.RESIZABLE\n\n\nclass CarSprite( pygame.sprite.Sprite ):\n    """ Car Sprite with basic acceleration, turning, braking and reverse """\n\n    def __init__( self, car_image, x, y, rotations=360 ):\n        """ A car Sprite which pre-rotates up to <rotations> lots of\n            angled versions of the image.  Depending on the sprite\'s\n            heading-direction, the correctly angled image is chosen.\n            The base car-image should be pointing North/Up.          """\n        pygame.sprite.Sprite.__init__(self)\n        # Pre-make all the rotated versions\n        # This assumes the start-image is pointing up-screen\n        # Operation must be done in degrees (not radians)\n        self.rot_img   = []\n        self.min_angle = ( 360 / rotations ) \n        for i in range( rotations ):\n            # This rotation has to match the angle in radians later\n            # So offet the angle (0 degrees = "north") by 90\xc2\xb0 to be angled 0-radians (so 0 rad is "east")\n            rotated_image = pygame.transform.rotozoom( car_image, 360-90-( i*self.min_angle ), 1 )\n            self.rot_img.append( rotated_image )\n        self.min_angle = math.radians( self.min_angle )   # don\'t need degrees anymore\n        # define the image used\n        self.image       = self.rot_img[0]\n        self.rect        = self.image.get_rect()\n        self.rect.center = ( x, y )\n        # movement\n        self.reversing = False\n        self.heading   = 0                           # pointing right (in radians)\n        self.speed     = 0    \n        self.velocity  = pygame.math.Vector2( 0, 0 )\n        self.position  = pygame.math.Vector2( x, y )\n\n    def turn( self, angle_degrees ):\n        """ Adjust the angle the car is heading, if this means using a \n            different car-image, select that here too """\n        ### TODO: car shouldn\'t be able to turn while not moving\n        self.heading += math.radians( angle_degrees ) \n        # Decide which is the correct image to display\n        image_index = int( self.heading / self.min_angle ) % len( self.rot_img )\n        # Only update the image if it\'s changed\n        if ( self.image != self.rot_img[ image_index ] ):\n            x,y = self.rect.center\n            self.image = self.rot_img[ image_index ]\n            self.rect  = self.image.get_rect()\n            self.rect.center = (x,y)\n\n    def accelerate( self, amount ):\n        """ Increase the speed either forward or reverse """\n        if ( not self.reversing ):\n            self.speed += amount\n        else: \n            self.speed -= amount\n\n    def brake( self ):\n        """ Slow the car by half """\n        self.speed /= 2\n        if ( abs( self.speed ) < 0.1 ):\n            self.speed = 0\n\n    def reverse( self ):\n        """ Change forward/reverse, reset any speed to 0 """\n        self.speed     = 0\n        self.reversing = not self.reversing\n\n    def update( self ):\n        """ Sprite update function, calcualtes any new position """\n        self.velocity.from_polar( ( self.speed, math.degrees( self.heading ) ) )\n        self.position += self.velocity\n        self.rect.center = ( round(self.position[0]), round(self.position[1] ) )\n\n\n### initialisation\npygame.init()\npygame.mixer.init()\nwindow = pygame.display.set_mode( ( WINDOW_WIDTH, WINDOW_HEIGHT ), WINDOW_SURFACE )\npygame.display.set_caption("Car Steering")\n\n\n### Bitmaps\nroad_image = road_image = pygame.image.load( \'road_texture.png\' )\nbackground = pygame.transform.smoothscale( road_image, ( WINDOW_WIDTH, WINDOW_HEIGHT ) )\ncar_image  = pygame.image.load( \'car_128.png\' ).convert_alpha()\n\n\n### Sprites\nblack_car = CarSprite( car_image, WINDOW_WIDTH//2, WINDOW_HEIGHT//2 )\ncar_sprites = pygame.sprite.Group() #Single()\ncar_sprites.add( black_car )\n\n\n### Main Loop\nclock = pygame.time.Clock()\ndone = False\nwhile not done:\n\n    # Handle user-input\n    for event in pygame.event.get():\n        if ( event.type == pygame.QUIT ):\n            done = True\n        elif ( event.type == pygame.VIDEORESIZE ):\n            WINDOW_WIDTH  = event.w\n            WINDOW_HEIGHT = event.h\n            window = pygame.display.set_mode( ( WINDOW_WIDTH, WINDOW_HEIGHT ), WINDOW_SURFACE )\n            background = pygame.transform.smoothscale( road_image, ( WINDOW_WIDTH, WINDOW_HEIGHT ) )\n        elif ( event.type == pygame.MOUSEBUTTONUP ):\n            # On mouse-click\n            pass\n        elif ( event.type == pygame.KEYUP ):\n            if ( event.key == pygame.K_h ):  \n                print( \'meep-meep\' )\n            elif ( event.key == pygame.K_r ):  \n                print( \'resersing\' )\n                black_car.reverse()\n            elif ( event.key == pygame.K_UP ):  \n                print( \'accelerate\' )\n                black_car.accelerate( 0.5 )\n            elif ( event.key == pygame.K_DOWN ):  \n                print( \'brake\' )\n                black_car.brake( )\n\n    # Continuous Movement keys\n    keys = pygame.key.get_pressed()\n    if ( keys[pygame.K_LEFT] ):\n        black_car.turn( -1.8 )  # degrees\n    if ( keys[pygame.K_RIGHT] ):\n        black_car.turn( 1.8 )\n\n    # Update the car(s)\n    car_sprites.update()\n\n    # Update the window\n    window.blit( background, ( 0, 0 ) ) # backgorund\n    car_sprites.draw( window )\n    pygame.display.flip()\n\n    # Clamp FPS\n    clock.tick_busy_loop(60)\n\npygame.quit()\n
Run Code Online (Sandbox Code Playgroud)\n

car_128.pngcar_128.png(来源:https://openclipart.org

\n

道路纹理.png道路纹理.png

\n