How to change my ball direction by clicking keys in pygame? - python
I have question. My ball is allways moving in 1 of 8 directions but when i click LEFT or RIGHT arrow I want to change direction and turn in smooth arc. I need advice what should I write to conditions for keys. I'm beginner but this is my code:
import pygame
pygame.init()
import random
win = pygame.display.set_mode((1280,720))
x = random.randint(150,1130)
y = random.randint(150,570)
vel = 1
x_direction = random.randint(-vel, vel)
y_direction = random.randint(-vel, vel)
while True:
x += x_direction
y += y_direction
pygame.time.delay(10)
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
pass
if keys[pygame.K_RIGHT]:
pass
win.fill((0,0,0))
pygame.draw.circle(win, (255,0,0), (x, y), 6)
pygame.display.update()
pygame.quit()
I recommend to store the direction in a pygame.math.Vector2 object:
direction = pygame.math.Vector2(x_direction, y_direction)
Change the the direction by rotating the vector with rotate_ip():
if keys[pygame.K_LEFT]:
direction.rotate_ip(-1)
if keys[pygame.K_RIGHT]:
direction.rotate_ip(1)
x += direction.x
y += direction.y
Not you can use rotate to create a vector with a random direction:
direction = pygame.math.Vector2(1, 0).rotate(random.randint(0, 360))
See also Motion and movement.
Complete example:
import pygame
import random
pygame.init()
win = pygame.display.set_mode((1280,720))
background = pygame.Surface(win.get_size(), pygame.SRCALPHA)
background.fill((0, 0, 0, 1))
clock = pygame.time.Clock()
x = random.randint(150,1130)
y = random.randint(150,570)
direction = pygame.math.Vector2(1, 0).rotate(random.randint(0, 360))
run = True
while run:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
direction.rotate_ip(-1)
if keys[pygame.K_RIGHT]:
direction.rotate_ip(1)
x = max(0, min(direction.x + x, win.get_width()))
y = max(0, min(direction.y + y, win.get_height()))
win.blit(background, (0, 0))
pygame.draw.circle(win, (255,0,0), (round(x), round(y)), 6)
pygame.display.update()
pygame.quit()
Related
Collision for Pygame Game Map
I am trying to make a maze game in Pygame but am unable to achieve collision for the 1 (maze wall) in the array. I tried to put the collision detection in the loop creating the map but it is not working. I also put the collision detection in the main loop but only the top left rect detected the collision, not all the 1 rects. How would I go about fixing this? Thank you! import pygame pygame.init() screen = pygame.display.set_mode((700,700)) pygame.display.set_caption("Game") speed = 20 x = 200 y = 600 def game_map(): global rect_one surface = pygame.Surface((100, 100), pygame.SRCALPHA) rect_one = pygame.draw.rect(surface, (0, 0, 255), (0, 0, 50, 50)) global rect_two surface_one = pygame.Surface((80, 80), pygame.SRCALPHA) rect_two = pygame.draw.rect(surface_one, (255, 255, 255), (0, 0, 50, 50)) tileX = 0 tileY = 0 global tile_list tile_list = [] map = [ [1,1,1,1,1,1,1,1,1,1,1,1,1], [1,0,0,0,1,0,1,0,0,0,0,0,1], [1,0,1,0,0,0,1,0,1,1,1,0,1], [1,0,0,0,1,1,1,0,0,0,0,0,1], [1,0,1,0,0,0,0,0,1,1,1,0,1], [1,0,1,0,1,1,1,0,1,0,0,0,1], [1,0,1,0,1,0,0,0,1,1,1,0,1], [1,0,1,0,1,1,1,0,1,0,1,0,1], [1,0,0,0,0,0,0,0,0,0,1,0,1], [1,1,1,1,1,1,1,1,1,1,1,1,1] ] for y, row in enumerate(map): tileX = 0 for x, cell in enumerate(row): image = surface if cell == 1 else surface_one screen.blit(image, [x*50, y*50]) tile_list.append(rect_one) pygame.display.update() def player(): player = pygame.draw.rect(screen, (255,0,0), (x, y, 20, 20)) for i in tile_list: if player.colliderect(i): print("hello") loop = True while loop: pygame.time.delay(100) for event in pygame.event.get(): if event.type == pygame.QUIT: loop = False #player controls keys = pygame.key.get_pressed() if keys[pygame.K_LEFT]: x -= speed if keys[pygame.K_RIGHT]: x += speed if keys[pygame.K_UP]: y -= speed if keys[pygame.K_DOWN]: y += speed screen.fill((255,255,255)) game_map() player() pygame.display.update() pygame.quit()
Your tile_list only contains one Rect multiple times. I simplified your code a little bit and use a Rect with the correct coordinates for each 1 in your map. Also note the comments: import pygame pygame.init() screen = pygame.display.set_mode((700,700)) pygame.display.set_caption("Game") speed = 10 player_x = 200 player_y = 600 # Use a constant. There's not need to make big Surfaces and then draw a smaller rect on them to create the map. TILESIZE = 50 tile_list = [] map = [ [1,1,1,1,1,1,1,1,1,1,1,1,1], [1,0,0,0,1,0,1,0,0,0,0,0,1], [1,0,1,0,0,0,1,0,1,1,1,0,1], [1,0,0,0,1,1,1,0,0,0,0,0,1], [1,0,1,0,0,0,0,0,1,1,1,0,1], [1,0,1,0,1,1,1,0,1,0,0,0,1], [1,0,1,0,1,0,0,0,1,1,1,0,1], [1,0,1,0,1,1,1,0,1,0,1,0,1], [1,0,0,0,0,0,0,0,0,0,1,0,1], [1,1,1,1,1,1,1,1,1,1,1,1,1] ] # let's create a single Surface for the map and reuse that grid = pygame.Surface((len(map[0]) * TILESIZE, len(map) * TILESIZE), pygame.SRCALPHA) for y, row in enumerate(map): for x, cell in enumerate(row): # if we want a wall, we draw it on the new Surface # also, we store the Rect in the tile_list so collision detection works if cell: rect = pygame.draw.rect(grid, 'blue', (x*TILESIZE, y*TILESIZE, TILESIZE, TILESIZE)) tile_list.append(rect) loop = True clock = pygame.time.Clock() while loop: clock.tick(60) for event in pygame.event.get(): if event.type == pygame.QUIT: loop = False #player controls keys = pygame.key.get_pressed() if keys[pygame.K_LEFT]: player_x -= speed if keys[pygame.K_RIGHT]: player_x += speed if keys[pygame.K_UP]: player_y -= speed if keys[pygame.K_DOWN]: player_y += speed screen.fill((255,255,255)) # draw the map surface to the screen screen.blit(grid, (0 ,0)) player = pygame.draw.rect(screen, (255,0,0), (player_x, player_y, 20, 20)) # now collision detection works because for each 1 in the map # there's a Rect in tile_list with the correct coordinates for i in tile_list: if player.colliderect(i): print("colliding") break else: print('not colliding') pygame.display.update() pygame.quit()
Save the position of the player before moving it: pos = x, y Compute the row and column after the player has moved: row = y // 50 column = x // 50 Reset the player's position if the new position is on a wall: if map[row][column] == 1: x, y = pos Additionally you have to move the map variable to global namespace. The speed should a integral divider of the tile size. Change the starting position to a position in the grid: speed = 25 x = 50 y = 50 Complete code: import pygame pygame.init() screen = pygame.display.set_mode((700,700)) pygame.display.set_caption("Game") speed = 25 x = 50 y = 50 map = [ [1,1,1,1,1,1,1,1,1,1,1,1,1], [1,0,0,0,1,0,1,0,0,0,0,0,1], [1,0,1,0,0,0,1,0,1,1,1,0,1], [1,0,0,0,1,1,1,0,0,0,0,0,1], [1,0,1,0,0,0,0,0,1,1,1,0,1], [1,0,1,0,1,1,1,0,1,0,0,0,1], [1,0,1,0,1,0,0,0,1,1,1,0,1], [1,0,1,0,1,1,1,0,1,0,1,0,1], [1,0,0,0,0,0,0,0,0,0,1,0,1], [1,1,1,1,1,1,1,1,1,1,1,1,1] ] def game_map(): global rect_one surface = pygame.Surface((100, 100), pygame.SRCALPHA) rect_one = pygame.draw.rect(surface, (0, 0, 255), (0, 0, 50, 50)) global rect_two surface_one = pygame.Surface((80, 80), pygame.SRCALPHA) rect_two = pygame.draw.rect(surface_one, (255, 255, 255), (0, 0, 50, 50)) tileX = 0 tileY = 0 for y, row in enumerate(map): tileX = 0 for x, cell in enumerate(row): image = surface if cell == 1 else surface_one screen.blit(image, [x*50, y*50]) pygame.display.update() def player(): player = pygame.draw.rect(screen, (255,0,0), (x, y, 25, 25)) loop = True while loop: pygame.time.delay(100) for event in pygame.event.get(): if event.type == pygame.QUIT: loop = False #player controls keys = pygame.key.get_pressed() pos = x, y if keys[pygame.K_LEFT]: x -= speed if keys[pygame.K_RIGHT]: x += speed if keys[pygame.K_UP]: y -= speed if keys[pygame.K_DOWN]: y += speed row = y // 50 column = x // 50 if map[row][column] == 1: x, y = pos screen.fill((255,255,255)) game_map() player() pygame.display.update() pygame.quit()
how to make object keep moving up
I'm making a game with Python. I have a spaceship in this game. The spaceship can move to the left and to the right and it is supposed to shoot bullets from its x-position and it is supposed to fire the bullets up. I am able to move the spaceship and I am able to put it on the screen. The problem is that I am not able to fire the bullet from the spaceship's x-position and I am not able to make the bullet move up. Can somebody help me with this? Please post simple code too if possible. Here's the code: import pygame import sys pygame.init() screen_length = 512 screen_width = 288 clock = pygame.time.Clock() screen = pygame.display.set_mode((screen_width, screen_length)) bg = pygame.image.load(r'C:\Users\Anonymous\Downloads\space game folder\space background3.png').convert() bg = pygame.transform.scale2x(bg) spaceship = pygame.image.load(r'C:\Users\Soorya\Anonymous\space game folder\spaceship.png').convert() missile = pygame.image.load(r'C:\Users\Soorya\Anonymous\space game folder\bullet2.png').convert() x = 130 y = 480 z = 460 velocity = 30 spaceship_rect = spaceship.get_rect(center=(x, y)) spaceship_x_pos = spaceship_rect.left + 170 bullet_speed = 10 missile_rect = missile.get_rect(center=(round(spaceship_x_pos // 2), z)) spaceship_direction = 10 while True: for event in pygame.event.get(): if event == pygame.QUIT: pygame.display.quit() sys.exit(0) keys = pygame.key.get_pressed() if keys[pygame.K_RIGHT] and x < 288: x += velocity if keys[pygame.K_LEFT] and x > 0: x -= velocity if keys[pygame.K_SPACE]: bg.blit(missile, missile_rect) screen.fill(0) screen.blit(bg, (0, 0)) screen.blit(spaceship, (x, y)) pygame.display.update() clock.tick(120)
The problem with your code is that your indentation is not right. while True: for event in pygame.event.get(): if event == pygame.QUIT: pygame.display.quit() sys.exit(0) keys = pygame.key.get_pressed() if keys[pygame.K_RIGHT] and x < 288: x += velocity if keys[pygame.K_LEFT] and x > 0: x -= velocity if keys[pygame.K_SPACE]: bg.blit(missile, missile_rect) screen.fill(0) # THIS screen.blit(bg, (0, 0)) #THIS screen.blit(spaceship, (x, y)) #THIS pygame.display.update() #THIS clock.tick(120) #THIS The lines where i commented this have to be indented like this: while True: for event in pygame.event.get(): if event == pygame.QUIT: pygame.display.quit() sys.exit(0) keys = pygame.key.get_pressed() if keys[pygame.K_RIGHT] and x < 288: x += velocity if keys[pygame.K_LEFT] and x > 0: x -= velocity if keys[pygame.K_SPACE]: bg.blit(missile, missile_rect) screen.fill(0) screen.blit(bg, (0, 0)) screen.blit(spaceship, (x, y)) pygame.display.update() clock.tick(120) That's because you want to do those things every single frame while the game is running. One more thing, you are filling the screen with black in line screen.fill(0), which is not necessary since you are already rendering a background image, so you basically cannot see it. With that being said, i recommend taking an object oriented approach as well because you wont get very far without it. Also, set velocity to like 0.5 or something. Its currently 30, which means 30 pixels every frame and that's not what you want. Now to fire bullets. What you are doing right now wont work because you are only "blitting" a missile if space is pressed. Below i wrote a separate code for you that only fires missiles, so hopefully its clear and you can implement in your own code. import pygame import sys pygame.init() d = pygame.display.set_mode((1200, 600)) # WE WILL USE FIRING BOOLEAN TO KEEP TRACK OF IF WE ARE FIRING MISSILES firing = False missile = pygame.Surface((10, 50)) while True: d.fill((255, 255, 255)) for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() # Assign initial positions only if it isnt firing if not firing: missilex = 600 # This is the initial position of the missile. This will be missiley = 500 # your player position in your game if pygame.key.get_pressed()[pygame.K_SPACE]: # if space pressed set firing to true firing = True # if firing is true, we want to display the missile and move it. if firing: d.blit(missile, (missilex, missiley)) missiley -= 1 # if missile is off the screen, set firing to false so it resets to initial position (600, 500). if missiley < -20: firing = False pygame.display.update()
The way you are approaching it doesn't seem right to me, unless ofc that isn't your whole code. But you are using the same variable to represent the x and y coordinate of your bullet and the spaceship. You want to bullet to move independently from the space ship. So if you change the variable y in your code, that will move space ship up too, and same with the x variable. What you need to do is to create 2 separate classes. One for you bullet, and the other for the space ship. Here is a simple example of its implementation, which you can improve upon by adding whatever features you want later. class Spaceship: image = pygame.image.load(r'C:\Users\Soorya\Anonymous\space game folder\spaceship.png').convert() def __init__(self, x, y, vel): self.x = x self.y = y self.vel = vel def draw(self, screen): screen.blit(Spaceship.image, (self.x, self.y)) class Bullet: image = pygame.image.load(r'C:\Users\Soorya\Anonymous\space game folder\bullet2.png').convert() bullet_list = [] # holds the list of bullets in the screen def __init__(self, x, y, vel): self.x = x self.y = y self.vel = vel Bullet.bullet_list.append(self) def move(self): self.y -= self.vel if self.y < 0: # remove bullet if it goes beyond screen Bullet.bullet_list.remove(self) def draw(self, screen): screen.blit(Bullet.image, (self.x, self.y)) spaceship = Spaceship(130, 480, 30) # set up screen and bg as before while True: for event in pygame.event.get(): if event == pygame.QUIT: pygame.display.quit() sys.exit(0) keys = pygame.key.get_pressed() if keys[pygame.K_RIGHT] and x < 288: spaceship.x += spaceship.vel if keys[pygame.K_LEFT] and x > 0: spaceship.x -= spaceship.vel if keys[pygame.K_SPACE]: # create a bullet if space is pressed Bullet(spaceship.x, spaceship.y, 10) screen.blit(bg, (0, 0)) spaceship.draw() for bullet in Bullet.bullet_list(): bullet.move() # actually moves the bullet on each iteration of the loop bullet.draw() pygame.display.update() clock.tick(120) Important note for future if you want to create games, make everything object oriented lol. Trust me, it will make your life a whole lot easier. Let me know if you have any problems.
How can I add a sprite when no keys are pressed?
How can I add a sprite when no keys are pressed? I have each four directions covered when the arrow keys are pressed but when they are released the sprite goes obviously but cant think of how to add it. I tried adding else statements and other things best thing i got was the standing forward sprite being underneath the others but cant seem to get it to go when one of the arrow keys is pressed and return when they are relased. Any help appreciated. Thanks in advance. my code: import pygame pygame.init() BLACK = (0, 0, 0) WHITE = (255, 255, 255) RED = (200, 0, 0) GREEN = (0, 200, 0) BLUE = (0, 0, 200) # background background = pygame.image.load('Playing Game state 2.png') # character standingforward = pygame.image.load('standingforward.png') standingdownward = pygame.image.load('standingdownwards.png') standingleft = pygame.image.load('standingleft.png') standingright = pygame.image.load('standingright.png') # player variables x = 375 y = 525 w = 50 h = 50 vel = 0.5 screenWidth = 800 screenHeight = 575 screen = pygame.display.set_mode((screenWidth, screenHeight)) pygame.display.set_caption("FROGGER") sprite = pygame.draw.rect running = True while running: # sprites screen.blit(background, (0, 0)) keys = pygame.key.get_pressed() if keys[pygame.K_LEFT]: screen.blit(standingleft, (x, y)) if keys[pygame.K_RIGHT]: screen.blit(standingright, (x, y)) if keys[pygame.K_DOWN]: screen.blit(standingdownward, (x, y)) if keys[pygame.K_UP]: screen.blit(standingforward, (x, y)) for event in pygame.event.get(): if event.type == pygame.QUIT: running = False pygame.display.flip() # controls keys = pygame.key.get_pressed() if keys[pygame.K_LEFT]: x -= vel if x < 0: x = 0 if keys[pygame.K_RIGHT]: x += vel if x > screenWidth-w: x = screenWidth-w if keys[pygame.K_UP]: y -= vel if y < 0: y = 0 if keys[pygame.K_DOWN]: y += vel if y > screenHeight-h: y = screenHeight-h pygame.quit()
Add a variable that refers to the current image. Change the variable when a key is pressed. Draw the current image in the application loop: current_image = standingright running = True while running: keys = pygame.key.get_pressed() if keys[pygame.K_LEFT]: current_image = standingleft if keys[pygame.K_RIGHT]: current_image = standingright if keys[pygame.K_DOWN]: current_image = standingdownward if keys[pygame.K_UP]: current_image = standingforward screen.blit(background, (0, 0)) screen.blit(current_image, (x, y)) # [...]
How do I make player_1 move with keys?
I want to make a Pong game in Python. I already have the windows and the player models. I tried to make it with if keys[pygame.K_LEFT]: x -= speed if keys[pygame.K_LEFT]: x += speed this is my whole code: import pygame from pygame import * import math import random clock = pygame.time.Clock() # fps pygame.init() # start title = pygame.display.set_caption("Pong") width = 640 height = 480 screen = pygame.display.set_mode((width, height)) # screen running = True speed = 10 white = (255, 255, 255) x = 120 y = 5 player_1 = pygame.draw.rect(screen, white, (240, 430, x, y)) player_2 = pygame.draw.rect(screen, white, (240, 40, x, y)) pong = pygame.draw.circle(screen, white, (300, 235), 4) pygame.display.update() fps = clock.tick(60) keys = pygame.key.get_pressed() if keys[pygame.K_LEFT]: x -= speed if keys[pygame.K_LEFT]: x += speed while 1: for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() running = False I wanted to make the lower player to move with the arrow keys but nothing happens at all.
Put keys = pygame.key.get_pressed() if keys[pygame.K_LEFT]: x -= speed if keys[pygame.K_LEFT]: x += speed player_1 = pygame.draw.rect(screen, white, (240, 430, x, y)) player_2 = pygame.draw.rect(screen, white, (240, 40, x, y)) pong = pygame.draw.circle(screen, white, (300, 235), 4) pygame.display.update() fps = clock.tick(60) within the while loop. Also, change if keys[pygame.K_LEFT]: x += speed to if keys[pygame.K_RIGHT]: x += speed
How do i make continuous player movement in pygame?
I've been watching a pygame tutorial on youtube on player movement, and by using this code below, the guy making the video was able to hold down a key and the character would keep moving, but when i hold down a key the character will move once and then stop. Any ideas on how to fix this? Code: import pygame pygame.init() win = pygame.display.set_mode((500, 500)) pygame.display.set_caption("huge honkabonkaros") x = 50 y = 440 width = 40 height = 60 vel = 5 run = True while run: pygame.time.delay(50) for event in pygame.event.get(): if event.type == pygame.QUIT: run = False keys = pygame.key.get_pressed() if keys[pygame.K_LEFT]: x -= vel if keys[pygame.K_RIGHT]: x += vel if keys[pygame.K_UP]: y -= vel if keys[pygame.K_DOWN]: y += vel win.fill((0, 0, 0)) pygame.draw.rect(win, (255, 0, 0), (x, y, width, height)) pygame.display.update() pygame.quit()
It is a matter of Indentation. The continuous movement must be in the application loop and not in the event loop. The application loop runs once per frame, but the event loop only runs once per event. When a key is pressed a KEYDOWN event occurs and when a key is released a KEYUP event occurs, but there is no event when a key is held down: import pygame pygame.init() win = pygame.display.set_mode((500, 500)) pygame.display.set_caption("huge honkabonkaros") x = 50 y = 440 width = 40 height = 60 vel = 5 run = True while run: pygame.time.delay(50) for event in pygame.event.get(): if event.type == pygame.QUIT: run = False # INDENTATION #<--| keys = pygame.key.get_pressed() if keys[pygame.K_LEFT]: x -= vel if keys[pygame.K_RIGHT]: x += vel if keys[pygame.K_UP]: y -= vel if keys[pygame.K_DOWN]: y += vel win.fill((0, 0, 0)) pygame.draw.rect(win, (255, 0, 0), (x, y, width, height)) pygame.display.update() pygame.quit()