Apologies for asking so many questions recently. I'm just starting to get into pygame.
With my previous questions I don't think I've been wording it properly for what I am trying to do.
Here is a quick picture I did to try demonstrate
This is a single background image or map that I would like the player to move across. The red X is just a starting place for the character.
I'm try to make it so when I move the player the background will also follow as if the player is moving through the map. I've already limited the player from not being able to go off the borders of the actual screen. Just having a bit of trouble now trying to make it so the single image will move along the player and if the player reaches the end of the map picture movement stops. I have seen people use scrolling and duplicating the image when the player moves. I just want to see it to the single image that the player will move across. I don't want to worry about collisions just be able to get the movement working.
This is the code I am currently using:
from pygame.locals import *
from math import sin
pygame.display.set_caption("TEST")
clock = pygame.time.Clock()
time_passed = 0
class Player():
def __init__(self,x,y):
self.Image = pygame.image.load("myAvatar.png").convert()
self.x = 200
self.y = 200
def getX(self):
return self.rect.x
def getY(self):
return self.rect.y
def handle_keys(self,screenHeight,screenWidth):
key = pygame.key.get_pressed()
dist = 2
if key[K_LEFT] and self.x > 0:
self.x -= 500 * time_passed
if key[K_RIGHT] and self.x < screenWidth -20:
self.x += 500 * time_passed
if key[K_UP] and self.y > 0:
self.y -= 500 * time_passed
if key[K_DOWN] and self.y < screenHeight -20:
self.y += 500 * time_passed
def draw(self, game_window):
self.Image = pygame.transform.scale(self.Image,(20,20))
game_window.blit(self.Image, (int(self.x), int(self.y)))
class Map():
def __init__(self):
self.Image = pygame.image.load("test2.png").convert()
self.rect = self.Image.get_rect()
self.x = 0
self.y = 0
def draw(self, game_window,screenHeight,screenWidth):
self.x = min(max(self.x, player.x - 2 * screenWidth / 2), player.x - screenWidth / 2)
self.y = min(max(self.y, player.y -2 * screenHeight / 2), player.y - screenHeight / 2)
game_window.blit(self.Image,(-self.x,-self.y))
class Enemy():
def __init__ (self,x,y):
self.Image = pygame.image.load("WC.jpg").convert()
self.rect = self.Image.get_rect(topleft = (x,y))
def draw(self, game_window):
self.Image = pygame.transform.scale(self.Image,(20,20))
game_window.blit(self.Image, (self.rect.x, self.rect.y))
pygame.init()
clock = pygame.time.Clock()
screenWidth = 400
screenHeight = 400
game_window = pygame.display.set_mode((screenWidth,screenHeight))
player = Player(200,200)
map = Map()
enemy = Enemy(250,250)
leave = False
while not leave:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
running = False
player.handle_keys(screenHeight,screenWidth)
game_window.fill((0,0,0))
map.draw(game_window,screenHeight,screenWidth)
#enemy.draw(game_window)
player.draw(game_window)
pygame.display.update()
pygame.display.flip()
time_passed = clock.tick() / 1000
pygame.quit()
quit()
Thanks
Shay
The player's movement depends on the size of the map. The x and y attributes of the "player" store the position on the map and are limited to the size of the map (map_size). The player is always drawn in the center of the screen, except it is near the boarders of the map:
class Player():
def __init__(self, x, y):
self.Image = pygame.image.load("myAvatar.png").convert()
self.x = 200
self.y = 200
def handle_keys(self, map_size):
key = pygame.key.get_pressed()
self.x += (key[K_RIGHT] - key[K_LEFT]) * 500 * time_passed
self.y += (key[K_DOWN] - key[K_UP]) * 500 * time_passed
self.x = max(0, min(map_size[0]-20, self.x))
self.y = max(0, min(map_size[1]-20, self.y))
def draw(self, game_window, map_size):
window_size = game_window.get_size()
center = window_size[0] // 2, window_size[0] // 2
pos = [self.x, self.y]
for i in range(2):
if center[i] < pos[i] <= map_size[i]-center[i]:
pos[i] = center[i]
elif pos[i] > map_size[i] - center[i]:
pos[i] = window_size[i] - map_size[i] + pos[i]
game_window.blit(self.Image, (int(pos[0]), int(pos[1])))
The player's position on the map is centered in the window:
class Map():
def __init__(self):
self.Image = pygame.image.load("test2.png").convert()
def draw(self, game_window):
window_size = game_window.get_size()
map_size = self.Image.get_size()
x = max(0, min(map_size[0] - window_size[0], player.x - 200))
y = max(0, min(map_size[1] - window_size[1], player.y - 200))
game_window.blit(self.Image, (-x, -y))
Application loop:
leave = False
while not leave:
for event in pygame.event.get():
if event.type == pygame.QUIT:
leave = True
player.handle_keys(map.Image.get_size())
game_window.fill((0,0,0))
map.draw(game_window)
#enemy.draw(game_window)
player.draw(game_window, map.Image.get_size())
pygame.display.update()
pygame.display.flip()
time_passed = clock.tick() / 1000
pygame.quit()
Related
My game is a top down shooter. When the player is stationary and is shooting in any direction, the bullet goes in the same direction as the mouse. However, when I move diagonally whilst shooting the bullet is no longer in the direction of the mouse position. So basically it works when the player is stationary, but not when I'm moving.
Edit: I will keep trying to fix this but here is a video to better understand the issue https://imgur.com/a/8QRr1PO
Here is the code:
import pygame
from sys import exit
import math
pygame.init()
# window and text
WIDTH = 1280
HEIGHT = 720
FPS = 60
screen = pygame.display.set_mode((WIDTH,HEIGHT))
pygame.display.set_caption('Shooting problem demo')
game_font = pygame.font.Font('freesansbold.ttf', 50)
clock = pygame.time.Clock()
# loads imgs
background = pygame.image.load("background/gamemap.png").convert()
plain_bg = pygame.image.load("background/plain_bg.png").convert()
bullet_img = pygame.image.load("bullets/bluebullet.png").convert_alpha()
class Player(pygame.sprite.Sprite):
def __init__(self, pos):
super().__init__()
self.image = pygame.image.load("handgun/move/survivor-move_handgun_0.png").convert_alpha()
self.image = pygame.transform.rotozoom(self.image, 0, 0.35)
self.base_player_image = self.image
self.pos = pos
self.base_player_rect = self.base_player_image.get_rect(center = pos)
self.rect = self.base_player_rect.copy()
self.player_speed = 10 # was 4
self.shoot = False
self.shoot_cooldown = 0
def player_turning(self):
self.mouse_coords = pygame.mouse.get_pos()
self.x_change_mouse_player = (self.mouse_coords[0] - (WIDTH // 2))
self.y_change_mouse_player = (self.mouse_coords[1] - (HEIGHT // 2))
self.angle = int(math.degrees(math.atan2(self.y_change_mouse_player, self.x_change_mouse_player)))
self.angle = (self.angle) % 360
self.image = pygame.transform.rotate(self.base_player_image, -self.angle)
self.rect = self.image.get_rect(center=self.base_player_rect.center)
def player_input(self):
self.velocity_x = 0
self.velocity_y = 0
keys = pygame.key.get_pressed()
if keys[pygame.K_w]:
self.velocity_y = -self.player_speed
if keys[pygame.K_s]:
self.velocity_y = self.player_speed
if keys[pygame.K_d]:
self.velocity_x = self.player_speed
if keys[pygame.K_a]:
self.velocity_x = -self.player_speed
if self.velocity_x != 0 and self.velocity_y != 0: # moving diagonally
self.velocity_x /= math.sqrt(2)
self.velocity_y /= math.sqrt(2)
if keys[pygame.K_SPACE]:
self.shoot = True
self.is_shooting()
else:
self.shoot = False
if event.type == pygame.KEYUP:
if event.key == pygame.K_SPACE:
self.shoot = False
def move(self):
self.base_player_rect.centerx += self.velocity_x
self.base_player_rect.centery += self.velocity_y
self.rect.center = self.base_player_rect.center
def is_shooting(self):
if self.shoot_cooldown == 0 and self.shoot:
self.bullet = Bullet(self.base_player_rect.centerx, self.base_player_rect.centery, self.angle)
self.shoot_cooldown = 20
bullet_group.add(self.bullet)
all_sprites_group.add(self.bullet)
def update(self):
self.player_turning()
self.player_input()
self.move()
if self.shoot_cooldown > 0:
self.shoot_cooldown -= 1
class Bullet(pygame.sprite.Sprite):
def __init__(self, x, y, angle):
super().__init__()
self.image = bullet_img
self.image = pygame.transform.rotozoom(self.image, 0, 0.1)
self.image.set_colorkey((0,0,0))
self.rect = self.image.get_rect()
self.rect.center = (x, y)
self.x = x
self.y = y
self.speed = 10
self.angle = angle
self.x_vel = math.cos(self.angle * (2*math.pi/360)) * self.speed
self.y_vel = math.sin(self.angle * (2*math.pi/360)) * self.speed
self.bullet_lifetime = 750
self.spawn_time = pygame.time.get_ticks()
def bullet_movement(self):
self.x += self.x_vel
self.y += self.y_vel
self.rect.x = int(self.x)
self.rect.y = int(self.y)
if pygame.time.get_ticks() - self.spawn_time > self.bullet_lifetime:
self.kill()
def update(self):
self.bullet_movement()
class Camera(pygame.sprite.Group):
def __init__(self):
super().__init__()
self.offset = pygame.math.Vector2()
self.floor_rect = background.get_rect(topleft = (0,0))
def custom_draw(self):
self.offset.x = player.rect.centerx - (WIDTH // 2)
self.offset.y = player.rect.centery - (HEIGHT // 2)
#draw the floor
floor_offset_pos = self.floor_rect.topleft - self.offset
screen.blit(background, floor_offset_pos)
for sprite in all_sprites_group:
offset_pos = sprite.rect.topleft - self.offset
screen.blit(sprite.image, offset_pos)
# Groups
all_sprites_group = pygame.sprite.Group()
player = Player((900,900))
all_sprites_group.add(player)
bullet_group = pygame.sprite.Group()
camera = Camera()
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
exit()
screen.blit(plain_bg, (0,0))
camera.custom_draw()
all_sprites_group.update()
pygame.display.update()
clock.tick(FPS)
Actually, there is no problem at all. It is just an optical illusion. The projectile does not move relative to the player, but relative to the camera. The player is always in the center of the screen, because the player doesn't move, but the camera does. When the camera moves, all objects move with the camera.
For example, if you shoot a bullet to the right and move the player up, it will look like the bullet is moving diagonally to the right and down. To the right because it changes position, to the right and down because the player moves upwards.
To illustrate this, I reduced the speed of the player (self.player_speed = 2) and the speed of the bullet (self.speed = 4) and drew the scene on a checkered background:
if event.type == pygame.KEYUP: only makes sens in the event loop, but not in player_input. Shooting only one bullet at once just needs another condition (and not self.shoot):
if keys[pygame.K_SPACE] and not self.shoot:
self.shoot = True
self.is_shooting()
else:
self.shoot = False
import pygame
import math
#initialise pygame
pygame.init()
#game window
WINDOW_WIDTH = 1200
WINDOW_HEIGHT = 750
#create game window
win = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT))
pygame.display.set_caption('Castle Defender')
clock = pygame.time.Clock()
FPS = 60
#load images
background_img = pygame.image.load('Animations/BG.png').convert_alpha()
background = pygame.transform.scale(background_img,(1200,750))
castle_img = pygame.image.load('Animations/Castle.png').convert_alpha()
bullet_img = pygame.image.load('Animations/SmallBullet.png').convert_alpha()
b_w = bullet_img.get_width()
b_h = bullet_img.get_height()
bullet_img = pygame.transform.scale(bullet_img, (int(b_w * 0.075), int(b_h * 0.075)))
WHITE =(255,255,255)
#Castle class
class Castle():
def __init__(self, image, x, y, scale):
self.health = 1000
self.max_health = self.health
width = image.get_width()
height = image.get_height()
self.image = pygame.transform.scale(image, (int(width * scale), int(height * scale)))
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
def shoot(self):
pos = pygame.mouse.get_pos()
x_dist = pos[0] - self.rect.midleft[0]
y_dist = -(pos[1] - self.rect.midleft[1])
self.angle = math.degrees(math.atan2(y_dist, x_dist))
#mouseclick
if pygame.mouse.get_pressed()[0] and self.fired == False:
self.fired = True
bullet = Bullet(bullet_img, self.rect.right[0], self.rect.right[1], self.angle)
bullet_group.add(bullet)
#reset mouseclick
if pygame.mouse.get_pressed()[0] == False:
self.fired = False
#Method
def draw(self):
self.image = self.image
win.blit(self.image, self.rect)
class Bullet(pygame.sprite.Sprite):
def __init__(self, image, x, y, angle):
pygame.sprite.Sprite.__init__(self)
self.image = image
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
self.angle = math.radians(angle)
self.speed = 10
self.dx = math.cos(self.angle) * self.speed
self.dy = -(math.sin(self.angle) * self.speed)
def update(self):
#check if bullet has gone off the screen
if self.rect.right < 0 or self.rect.left > SCREEN_WIDTH or self.rect.bottom < 0 or self.rect.top > SCREEN_HEIGHT:
self.kill()
#move bullet
self.rect.x += self.dx
self.rect.y += self.dy
castle = Castle(castle_img, WINDOW_WIDTH - 1350, WINDOW_HEIGHT - 400, 0.7)
bullet_group = pygame.sprite.Group()
run = True
while run:
clock.tick(FPS)
win.blit(background, (0, 0))
castle.draw()
castle.shoot()
#bullet drawing
bullet_group.update()
bullet_group.draw(win)
print(len(bullet_group))
#event handler
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
#update display window
pygame.display.update()
pygame.quit()
I am trying to see the line from my base and my mouse. However I get an error of the following
bullet = Bullet(bullet_img, self.rect.right[0], self.rect.right[1], self.angle)
(My end goal is for bullets to come out of the castle and i am relatively new to coding and this will be my first project) . Also i keep getting an error when trying to submit this saying it is mostly code so the parenthisis was me rambling on
The issue the code is trying to use self.rect.right as if it was a python list. But self.rect.right is an integer.
self.rect.right[0]
self.rect.right[1]
Probably this should be self.rect.right and self.rect.top (since it deals with the y-dimension).
Then you also need to correct references to SCREEN_WIDTH and SCREEN_HEIGHT. It looks like these should be WINDOW_ etc.
After these changes are made, your program does not exit with an error when the mouse is clicked.
This question already has answers here:
How do I detect collision in pygame?
(5 answers)
How do I prevent the player from moving through the walls in a maze?
(3 answers)
Closed 9 months ago.
I am trying to learn the basics of pygame by making a simple pacman game with a friend, but I have been having trouble figuring out how to make walls and check collision with the pacman and the wall, and also stopping the movement through a wall.
(this is a 2 player pacman, ghost is arrow keys, and pacman is wasd)
This is main.py
import pygame
import random
import time
from Pacman import pacman
from Ghost import ghost
#colors
Yellow = (255,255,0)
Blackish_Blue = (20,0,70)
Red = (255,0,0)
P_B = (40,60,100)
clock = pygame.time.Clock()
#display
pygame.init()
pygame.display.set_caption(' Scuffed Pacman')
width, height = 640, 480
screen = pygame.display.set_mode((width, height))
pacman = pacman(screen)
ghost = ghost(screen)
font = pygame.font.Font('freesansbold.ttf', 32)
text = font.render('Game Over', True, Yellow)
textRect = text.get_rect()
textRect.center = (width / 2, height / 2)
run = True
while run == True:
pygame.time.delay(10)
clock.tick(60)
screen.fill(Blackish_Blue)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
color = (182,163,192)
#attempt to make wall and check collision
ghostspawn = pygame.Rect(0,0,60,40)
ghostspawn.center = (width / 2, (height / 2)-50)
pygame.draw.rect(screen, color, ghostspawn)
if ghostspawn.collidepoint(pacman.x, pacman.y):
print("collision detected")
pacman.draw(screen)
ghost.draw(screen)
ghost.update()
pacman.update()
distance = (((pacman.x - ghost.x)**2) + ((pacman.y - ghost.y)**2))**(1/2)
sumrad = pacman.radius + ghost.radius
if distance < sumrad:
while True:
screen.fill(P_B)
screen.blit(text, textRect)
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
pygame.display.update()
pygame.display.update()
pygame.quit()
This is the code for pacman:
import pygame
Yellow = (255,255,0)
class pacman(pygame.sprite.Sprite):
def __init__(self, mainscreen):
super().__init__()
self.x = 320
self.y = 240
self.radius = 15
self.velocity = 2
self.origin = (self.x, self.y)
def draw(self, mainscreen):
pygame.draw.circle(mainscreen, Yellow, (self.x, self.y), self.radius)
def update(self):
self.movement()
self.origin = (self.x, self.y)
def movement(self):
keys = pygame.key.get_pressed()
if keys[pygame.K_d] and self.velocity > 0 and self.x < 625:
self.x += self.velocity
if keys[pygame.K_a] and self.velocity > 0 and self.x > 15:
self.x -= self.velocity
if keys[pygame.K_w] and self.velocity > 0 and self.y > 15:
self.y -= self.velocity
if keys[pygame.K_s] and self.velocity > 0 and self.y < 465:
self.y += self.velocity
and this is the code for ghost:
import pygame
Red = (255,0,0)
class ghost(pygame.sprite.Sprite):
def __init__(self, mainscreen):
super().__init__()
self.x = 213
self.y = 240
self.radius = 15
self.velocity = 2
self.origin = (self.x, self.y)
def draw(self, mainscreen):
pygame.draw.circle(mainscreen, Red, (self.x, self.y), self.radius)
def update(self):
self.movement()
self.origin = (self.x, self.y)
def movement(self):
keys = pygame.key.get_pressed()
if keys[pygame.K_RIGHT] and self.velocity > 0 and self.x < 625:
self.x += self.velocity
if keys[pygame.K_LEFT] and self.velocity > 0 and self.x > 15:
self.x -= self.velocity
if keys[pygame.K_UP] and self.velocity > 0 and self.y > 15:
self.y -= self.velocity
if keys[pygame.K_DOWN] and self.velocity > 0 and self.y < 465:
self.y += self.velocity
this is my attempt at checking for wall collision, but I am unaware of how to stop pacman and the ghost from going through. the collision also only checks the middle of the circle.
ghostspawn = pygame.Rect(0,0,60,40)
ghostspawn.center = (width / 2, (height / 2)-50)
pygame.draw.rect(screen, color, ghostspawn)
if ghostspawn.collidepoint(pacman.x, pacman.y):
print("allowed")
here is how i detect collision between pacman and ghost, as it may be helpful for doing it with walls, but i don't know how.
distance = (((pacman.x - ghost.x)**2) + ((pacman.y - ghost.y)**2))**(1/2)
sumrad = pacman.radius + ghost.radius
ive looked at a few similar questions on here, but I can't quite grasp how it works.
So, if anyone could help, I'm having trouble with checking collision between a circle and rectangle, and also preventing the circle/pacman from moving through.
To check if a circle is colliding with a wall you just need to do 2 things
Get the distance between the circle and the wall
Then check if the distance is smaller or equal to the circles distance
Pretty much like this:
distance = abs(circle.x - wall.x) + abs(circle.y - wall.y)
if distance <= circle.radius: # abs() Makes the value in the brackets positive
circle.x = oldX
circle.y = oldY
To implement this I with your game would first add a self.oldX and a self.oldY in the self.__init__() in both of the pacman and ghost classes. And I would set them to 0 for now.
Then I would update the oldX and oldY in the movement function before I move the object, like this:
def movement(self):
keys = pygame.key.get_pressed()
self.oldX = self.x
self.oldY = self.y
if keys[pygame.K_d] and self.velocity > 0 and self.x < 625:
self.x += self.velocity
if keys[pygame.K_a] and self.velocity > 0 and self.x > 15:
self.x -= self.velocity
if keys[pygame.K_w] and self.velocity > 0 and self.y > 15:
self.y -= self.velocity
if keys[pygame.K_s] and self.velocity > 0 and self.y < 465:
self.y += self.velocity
Then I would have a list that containes every wall in the game and a list that containes every ghost in the game (That's if you want to have more than one ghost).
Then I would go in the main loop (The while loop that you have) and I would add this After calling the movement function of the ghosts and the pacman:
for wall in walls:
distance = abs(pacman.x - wall.x) + abs(pacman.y - wall.y)
if distance <= pacman.radius:
pacman.x = pacman.oldX
pacman.y = pacman.oldY
for ghost in ghosts:
distance = abs(ghost.x - wall.x) + abs(ghost.y - wall.y)
if distance <= ghost.radius:
ghost.x = ghost.oldX
ghost.y = ghost.oldY
and that should work, Thanks.
Apologies for asking so many questions recently. I'm just starting to get into pygame.
With my previous questions I don't think I've been wording it properly for what I am trying to do.
Here is a quick picture I did to try demonstrate
This is a single background image or map that I would like the player to move across. The red X is just a starting place for the character.
I'm try to make it so when I move the player the background will also follow as if the player is moving through the map. I've already limited the player from not being able to go off the borders of the actual screen. Just having a bit of trouble now trying to make it so the single image will move along the player and if the player reaches the end of the map picture movement stops. I have seen people use scrolling and duplicating the image when the player moves. I just want to see it to the single image that the player will move across. I don't want to worry about collisions just be able to get the movement working.
This is the code I am currently using:
from pygame.locals import *
from math import sin
pygame.display.set_caption("TEST")
clock = pygame.time.Clock()
time_passed = 0
class Player():
def __init__(self,x,y):
self.Image = pygame.image.load("myAvatar.png").convert()
self.x = 200
self.y = 200
def getX(self):
return self.rect.x
def getY(self):
return self.rect.y
def handle_keys(self,screenHeight,screenWidth):
key = pygame.key.get_pressed()
dist = 2
if key[K_LEFT] and self.x > 0:
self.x -= 500 * time_passed
if key[K_RIGHT] and self.x < screenWidth -20:
self.x += 500 * time_passed
if key[K_UP] and self.y > 0:
self.y -= 500 * time_passed
if key[K_DOWN] and self.y < screenHeight -20:
self.y += 500 * time_passed
def draw(self, game_window):
self.Image = pygame.transform.scale(self.Image,(20,20))
game_window.blit(self.Image, (int(self.x), int(self.y)))
class Map():
def __init__(self):
self.Image = pygame.image.load("test2.png").convert()
self.rect = self.Image.get_rect()
self.x = 0
self.y = 0
def draw(self, game_window,screenHeight,screenWidth):
self.x = min(max(self.x, player.x - 2 * screenWidth / 2), player.x - screenWidth / 2)
self.y = min(max(self.y, player.y -2 * screenHeight / 2), player.y - screenHeight / 2)
game_window.blit(self.Image,(-self.x,-self.y))
class Enemy():
def __init__ (self,x,y):
self.Image = pygame.image.load("WC.jpg").convert()
self.rect = self.Image.get_rect(topleft = (x,y))
def draw(self, game_window):
self.Image = pygame.transform.scale(self.Image,(20,20))
game_window.blit(self.Image, (self.rect.x, self.rect.y))
pygame.init()
clock = pygame.time.Clock()
screenWidth = 400
screenHeight = 400
game_window = pygame.display.set_mode((screenWidth,screenHeight))
player = Player(200,200)
map = Map()
enemy = Enemy(250,250)
leave = False
while not leave:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
running = False
player.handle_keys(screenHeight,screenWidth)
game_window.fill((0,0,0))
map.draw(game_window,screenHeight,screenWidth)
#enemy.draw(game_window)
player.draw(game_window)
pygame.display.update()
pygame.display.flip()
time_passed = clock.tick() / 1000
pygame.quit()
quit()
Thanks
Shay
The player's movement depends on the size of the map. The x and y attributes of the "player" store the position on the map and are limited to the size of the map (map_size). The player is always drawn in the center of the screen, except it is near the boarders of the map:
class Player():
def __init__(self, x, y):
self.Image = pygame.image.load("myAvatar.png").convert()
self.x = 200
self.y = 200
def handle_keys(self, map_size):
key = pygame.key.get_pressed()
self.x += (key[K_RIGHT] - key[K_LEFT]) * 500 * time_passed
self.y += (key[K_DOWN] - key[K_UP]) * 500 * time_passed
self.x = max(0, min(map_size[0]-20, self.x))
self.y = max(0, min(map_size[1]-20, self.y))
def draw(self, game_window, map_size):
window_size = game_window.get_size()
center = window_size[0] // 2, window_size[0] // 2
pos = [self.x, self.y]
for i in range(2):
if center[i] < pos[i] <= map_size[i]-center[i]:
pos[i] = center[i]
elif pos[i] > map_size[i] - center[i]:
pos[i] = window_size[i] - map_size[i] + pos[i]
game_window.blit(self.Image, (int(pos[0]), int(pos[1])))
The player's position on the map is centered in the window:
class Map():
def __init__(self):
self.Image = pygame.image.load("test2.png").convert()
def draw(self, game_window):
window_size = game_window.get_size()
map_size = self.Image.get_size()
x = max(0, min(map_size[0] - window_size[0], player.x - 200))
y = max(0, min(map_size[1] - window_size[1], player.y - 200))
game_window.blit(self.Image, (-x, -y))
Application loop:
leave = False
while not leave:
for event in pygame.event.get():
if event.type == pygame.QUIT:
leave = True
player.handle_keys(map.Image.get_size())
game_window.fill((0,0,0))
map.draw(game_window)
#enemy.draw(game_window)
player.draw(game_window, map.Image.get_size())
pygame.display.update()
pygame.display.flip()
time_passed = clock.tick() / 1000
pygame.quit()
I am making a simple variation of space invaders using pygame. Here is some working code:
import pygame, random, time, tkinter
pygame.init()
def main():
X = 672
Y = 500
win = pygame.display.set_mode((X,Y))
pygame.display.set_caption('Space Invaders')
class player(object):
def __init__(self, x, y, width, height):
self.x = x
self.y = y
self.width = width
self.height = height
self.lives = 3
self.vel = 5
self.points = 0
self.explosionYN = False
self.explosionCount = 0
self.highScore = int(text)
def explosion(self, win):
if self.explosionYN:
win.blit(explosion[self.explosionCount], (self.x-20, self.y-30, 100, 100))
self.explosionCount += 1
if not self.explosionYN:
self.explosionCount = 0
if self.explosionCount + 1 > 6:
self.explosionYN = False
self.explosionCount = 0
def move(self, win):
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT] and self.x > -1:
self.x -= self.vel
if keys[pygame.K_RIGHT] and self.x < 623:
self.x += self.vel
if keys[pygame.K_q]:
if self.x >= 623:
self.x = 0
if self.x < 0:
self.x = 623
class invader(object):
def __init__(self, x, y, width, height):
self.x = x
self.y = y
self.width = width
self.height = height
self.vel = 1
def reset(self, win):
self.y = 0
self.x = random.randint(5, (X-35))
class bullet(object):
def __init__(self, x, y, width, height):
self.x = x
self.y = y
self.width = width
self.height = height
self.vel = 0
def shoot(self, win):
laser.play(0)
self.x = ship.x + 22
self.y = ship.y
self.vel = 15
def reset(self, win):
self.vel = 0
self.y = 510
ship = player(X//2 - (0.5*52), 435, 52, 52)
alien = invader(random.randint(0,707),0,31,25)
bullet = bullet(750, 510, 5, 7)
while run:
pygame.time.delay(25)
alien.y += alien.vel
bullet.y -= bullet.vel
if alien.y > 500:
ship.explosionYN = True
ship.explosion(win)
loseLife.play(0)
if ship.explosionCount+ 1 >= 6:
win.fill((0,0,0))
pause()
ship.lives -= 1
alien.reset(win)
elif ship.lives <= 1:
test()
if bullet.y <= 0:
bullet.reset(win)
alien1 = pygame.draw.rect(win, (0,0,0), (alien.x,alien.y,31,25))
bullet1 = pygame.draw.rect(win, (0,100,255), (bullet.x, bullet.y, bullet.width, bullet.height))
if pygame.Rect.colliderect(alien1, bullet1):
ship.points += 1
if ship.highScore < ship.points:
ship.highScore += 1
bullet.reset(win)
kill.play(0)
alien.y = 0
alien.reset(win)
alien.vel += 0.5
ship.vel += 0.25
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
keys = pygame.key.get_pressed()
ship.move(win)
if keys[pygame.K_SPACE] or keys[pygame.K_UP]:
bullet.shoot(win)
if keys[pygame.K_p]:
pause()
drawGame()
main()
I have omitted some code that I don't think is relevant
The problem is that only one bullet can be displayed on screen at a time.
So I tried this instead.
if keys[pygame.K_SPACE] or keys[pygame.K_UP]:
bullet1 = pygame.draw.rect(win, (#stuff))
bullet.shoot(win)
But now the bullet doesn't show at all.
Literally nothing happens.
I have looked at some other posts but as I am new to pygame I can't make head or tail of them.(Multiple Bullets pygame)
What is an easy and effiecient way to be able show multiple bullets on pygame?
thanks.
The typical way that this is done is by creating a list of bullets.
bullets = []
Then when you fire a bullet you add it to the list
bullets.append(Bullet(750, 510, 5, 7))
And inside your while loop, you will update and redraw each bullet in turn using a for loop to iterate over each bullet
for bullet in bullets:
bullet.y -= bullet.vel # Move Bullet
# Draw bullet
# Check for collision with player/enemy
This obviously isn't a complete code listing but hopefully it is enough to get you started.
You'll also end up having to create a list of enemies too if you want to create a space invaders clone.
You may find the recently released book "Code the Classics" from the Raspberry Pi Foundation helpful as it explains how to create some classic games using Pygame. It's a free download (or you can buy the hardcopy)
Edit: Consider following the Python style guide PEP-8 and renaming your classes to be title case. For example
class bullet():
should be
class Bullet():
This will help with any confusion between the variable bullet and the class of the same name.