I was wondering how I could make a car that moves and rotates using the arrow keys. I am trying to make a car physics game where the player controls the car and drives around and parks, but I am having trouble with how to start implementing the controls. How could I make my car move the direction it's rotating with the arrow keys?
For example, if I am pressing the back arrow key, the car should reverse, and if the car is reversing while also turning, it should move the way the car is turning.
Here is my code right now. There isn't really anything going on right now.
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()
To move a sprite in Pygame, you must tell Python to redraw the sprite in its new location—and where that new location is. Since the Player sprite isn't always moving, make these updates a dedicated function within the Player class. Add this function after the control function you created earlier.
The pygame library is an open-source module for the Python programming language specifically intended to help you make games and other multimedia applications. Built on top of the highly portable SDL (Simple DirectMedia Layer) development library, pygame can run across many platforms and operating systems.
The code is tested to run on Python 3.6. Most of the tutorials on car physics I found online either try to implement a complete simulation of car mechanics or, by contrast, give only a few lines of code without explaining how they work.
Add the following lines to you game loop after the self.screen.fill () and before pygame.display.flip () function calls: This will draw the car image. To align the center of the image with the car position, we subtract the half of the image bounding rectangle from its original position.
No Brake is a 2d car game. A simple driving game. Dodge racing is a scrolling game. You drive a car and you must dodge the other cars. An open source topdown car game fully written with Python and Pygame. Pyformula1 a race game on circuits against the clock, with music, animations, and effects.
This series of tutorials demonstrates how to create a physical simulation using Python and Pygame. The tutorials start with the very basics and build up to a final simulation of a classical physics problem: the trajectory of a cannonball.
I wanted to add a PyGame Sprite based answer to this question. Implementing this sort of thing as a sprite makes it easier to use the PyGame collision functions. For example, any number of CarSprites could be made, but their collision checked against the player's CarSrpite in a single call to groupcollide()
.
This implementation uses PyGame.math.Vector2()
for velocity and position. This allows for a fairly simple turning and speed model utilising the Vector2's polar co-ordinate function. Initially this gave weird and confusing result... until I realised the Vector2.from_polar()
required the angle in degrees. (Not radians unlike just about every other programming language function that takes angles.)
When the sprite is initially created, the code will make a lot of pre-rotated images. This does the smoothest turning at around 1 per degree (360), but if memory-usage was a issue, it could also be much less.
Anyway, the code is fairly self-explanatory. It requires a car_128.png
image, and a background texture image road_texture.png
. Please comment any questions.
import pygame
import math
# Window size
WINDOW_WIDTH = 600
WINDOW_HEIGHT = 600
WINDOW_SURFACE = pygame.HWSURFACE|pygame.DOUBLEBUF|pygame.RESIZABLE
class CarSprite( pygame.sprite.Sprite ):
""" Car Sprite with basic acceleration, turning, braking and reverse """
def __init__( self, car_image, x, y, rotations=360 ):
""" A car Sprite which pre-rotates up to <rotations> lots of
angled versions of the image. Depending on the sprite's
heading-direction, the correctly angled image is chosen.
The base car-image should be pointing North/Up. """
pygame.sprite.Sprite.__init__(self)
# Pre-make all the rotated versions
# This assumes the start-image is pointing up-screen
# Operation must be done in degrees (not radians)
self.rot_img = []
self.min_angle = ( 360 / rotations )
for i in range( rotations ):
# This rotation has to match the angle in radians later
# So offet the angle (0 degrees = "north") by 90° to be angled 0-radians (so 0 rad is "east")
rotated_image = pygame.transform.rotozoom( car_image, 360-90-( i*self.min_angle ), 1 )
self.rot_img.append( rotated_image )
self.min_angle = math.radians( self.min_angle ) # don't need degrees anymore
# define the image used
self.image = self.rot_img[0]
self.rect = self.image.get_rect()
self.rect.center = ( x, y )
# movement
self.reversing = False
self.heading = 0 # pointing right (in radians)
self.speed = 0
self.velocity = pygame.math.Vector2( 0, 0 )
self.position = pygame.math.Vector2( x, y )
def turn( self, angle_degrees ):
""" Adjust the angle the car is heading, if this means using a
different car-image, select that here too """
### TODO: car shouldn't be able to turn while not moving
self.heading += math.radians( angle_degrees )
# Decide which is the correct image to display
image_index = int( self.heading / self.min_angle ) % len( self.rot_img )
# Only update the image if it's changed
if ( self.image != self.rot_img[ image_index ] ):
x,y = self.rect.center
self.image = self.rot_img[ image_index ]
self.rect = self.image.get_rect()
self.rect.center = (x,y)
def accelerate( self, amount ):
""" Increase the speed either forward or reverse """
if ( not self.reversing ):
self.speed += amount
else:
self.speed -= amount
def brake( self ):
""" Slow the car by half """
self.speed /= 2
if ( abs( self.speed ) < 0.1 ):
self.speed = 0
def reverse( self ):
""" Change forward/reverse, reset any speed to 0 """
self.speed = 0
self.reversing = not self.reversing
def update( self ):
""" Sprite update function, calcualtes any new position """
self.velocity.from_polar( ( self.speed, math.degrees( self.heading ) ) )
self.position += self.velocity
self.rect.center = ( round(self.position[0]), round(self.position[1] ) )
### initialisation
pygame.init()
pygame.mixer.init()
window = pygame.display.set_mode( ( WINDOW_WIDTH, WINDOW_HEIGHT ), WINDOW_SURFACE )
pygame.display.set_caption("Car Steering")
### Bitmaps
road_image = road_image = pygame.image.load( 'road_texture.png' )
background = pygame.transform.smoothscale( road_image, ( WINDOW_WIDTH, WINDOW_HEIGHT ) )
car_image = pygame.image.load( 'car_128.png' ).convert_alpha()
### Sprites
black_car = CarSprite( car_image, WINDOW_WIDTH//2, WINDOW_HEIGHT//2 )
car_sprites = pygame.sprite.Group() #Single()
car_sprites.add( black_car )
### 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.VIDEORESIZE ):
WINDOW_WIDTH = event.w
WINDOW_HEIGHT = event.h
window = pygame.display.set_mode( ( WINDOW_WIDTH, WINDOW_HEIGHT ), WINDOW_SURFACE )
background = pygame.transform.smoothscale( road_image, ( WINDOW_WIDTH, WINDOW_HEIGHT ) )
elif ( event.type == pygame.MOUSEBUTTONUP ):
# On mouse-click
pass
elif ( event.type == pygame.KEYUP ):
if ( event.key == pygame.K_h ):
print( 'meep-meep' )
elif ( event.key == pygame.K_r ):
print( 'resersing' )
black_car.reverse()
elif ( event.key == pygame.K_UP ):
print( 'accelerate' )
black_car.accelerate( 0.5 )
elif ( event.key == pygame.K_DOWN ):
print( 'brake' )
black_car.brake( )
# Continuous Movement keys
keys = pygame.key.get_pressed()
if ( keys[pygame.K_LEFT] ):
black_car.turn( -1.8 ) # degrees
if ( keys[pygame.K_RIGHT] ):
black_car.turn( 1.8 )
# Update the car(s)
car_sprites.update()
# Update the window
window.blit( background, ( 0, 0 ) ) # backgorund
car_sprites.draw( window )
pygame.display.flip()
# Clamp FPS
clock.tick_busy_loop(60)
pygame.quit()
car_128.png (Source: https://openclipart.org )
road_texture.png
Here is the improved code:
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()
Some things to notice:
clock.tick
is used to keep it from going too fast, and it means "a maximum of 60 frames per second".I hope you understand everything.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With