I'm making a game in pygame and I'm having some trouble with object collisions.
import pygame, sys
from pygame.math import Vector2
pygame.init()
screen = pygame.display.set_mode((500,500))
clock = pygame.time.Clock()
#Environment Variables
gravity = -1
jumpForce = 20
moveSpeed = 10
#Game Objects
playerPos = Vector2(230,230)
playerVelo = Vector2(0,0)
player = pygame.Rect(playerPos.x,playerPos.y, 20, 20)
boxPos = Vector2(350,480)
box = pygame.Rect(boxPos.x, boxPos.y, 20,20)
def Clamp(var, minClamp, maxClamp):
if minClamp > maxClamp:
raise Exception("minClamp must be less than maxClamp")
if var < minClamp:
var = minClamp
if var > maxClamp:
var = maxClamp
return var
def Draw():
global player,box
screen.fill((255,255,25))
player = pygame.Rect(playerPos.x,playerPos.y, 20, 20)
pygame.draw.rect(screen,(0,100,255),player)
box = pygame.Rect(boxPos.x, boxPos.y, 20,20)
pygame.draw.rect(screen,(10,200,20),box)
def PlayerVelocity():
global playerPos,playerVelo,player,box,boxPos
if player.colliderect(box):
playerPos = Vector2(boxPos.x,boxPos.y-20)
print("balls")
if playerPos.y < 499:
playerVelo.y += gravity
#if not pygame.Rect(playerPos.x+playerVelo.x,playerPos.y+playerVelo.y,20,20).colliderect(box):
playerPos -= playerVelo
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE or event.key == pygame.K_UP:
playerVelo.y = jumpForce
print(playerVelo)
keys = pygame.key.get_pressed()
if keys[pygame.K_a] or keys[pygame.K_LEFT]:
playerVelo.x = 1*moveSpeed
elif keys[pygame.K_d] or keys[pygame.K_RIGHT]:
playerVelo.x = -1*moveSpeed
else:
playerVelo.x = 0
#Draw things to the screen
Draw()
PlayerVelocity()
playerPos.x = Clamp(playerPos.x, 0, 480)
playerPos.y = Clamp(playerPos.y,0,480)
pygame.display.update()
clock.tick(30)
I've tried looking this up and the other solutions either don't work with the movement system I've implemented or I just plain don't understand them.
It is not enough to change the position of the player when the player hits the obstacle. You need to constrain the player's box (pygame.Rect object) with the obstacle rectangle and update the player's position. Clamp and calculate the position of the player before checking for collision:
def PlayerVelocity():
global playerPos,playerVelo,player,box,boxPos
prev_y = playerPos.y
if playerPos.y < 499:
playerVelo.y += gravity
playerPos -= playerVelo
playerPos.x = Clamp(playerPos.x, 0, 480)
playerPos.y = Clamp(playerPos.y, 0, 480)
player = pygame.Rect(playerPos.x, playerPos.y, 20, 20)
box = pygame.Rect(boxPos.x, boxPos.y, 20,20)
if player.colliderect(box):
if prev_y+20 <= box.top:
player.bottom = box.top
elif player.left < box.left:
player.right = box.left
else:
player.left = box.right
playerPos = Vector2(player.topleft)
print("balls")
Related
I can't collide rect whit rectangles, should I give up or try using x and y positions?
I don't get any errors from it but it closes right after i run it.
can you please suggest me what to do.
import pygame,sys,time,random
pygame.init()
x = 425
y = 750
player_x = x/2-25
player_y = 600
player_speed = 0
timer = 0
score = 0
screen = pygame.display.set_mode((x,y))
clock = pygame.time.Clock()
enemy_x = random.randint(0,425)
enemy_y = -(random.randint(0,500))
enemy2_x = random.randint(0,425)
enemy2_y = -(random.randint(0,500))
police_x = random.randint(0,425)
police_y = random.randint(750,1400)
police2_x = random.randint(0,425)
police2_y = random.randint(750,1400)
enemy_speed = 16
police_speed = 3
font = pygame.font.SysFont("comicsansms",50)
player = pygame.image.load("macchina.png").convert_alpha()
pygame.display.set_caption("NapoliSimulator (schiva le buche e non farti prendere dalla pula)")
def player_a():
global player_x,player_y,player_speed
player_x+=player_speed
player = pygame.image.load("macchina.png").convert_alpha()
screen.blit(player,(player_x,player_y))
def enemy_a():
global enemy_x,enemy_y,enemy_speed,enemy2_x,enemy2_y,enemy3_x,enemy3_y,enemy4_x,enemy4_y,enemy5_x,enemy5_y
enemy_y += enemy_speed
enemy2_y += enemy_speed
enemy = pygame.image.load("crepa.png").convert_alpha()
enemy_2 = pygame.image.load("crepa.png").convert_alpha()
screen.blit(enemy,(enemy_x,enemy_y))
screen.blit(enemy,(enemy2_x,enemy2_y))
def enemy_b():
global police_x,police_y,police_speed,police2_x,police2_y
police_y -= police_speed
police = pygame.image.load("polizia.png").convert_alpha()
screen.blit(police,(police_x,police_y))
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_a:
player_speed -= 5
if event.key == pygame.K_d:
player_speed += 5
if event.type == pygame.KEYUP:
if event.key == pygame.K_a:
player_speed += 5
if event.key == pygame.K_d:
player_speed -= 5
screen.fill((200,200,200))
player_a()
if enemy_y >= 700:
enemy_y = -(random.randint(500,1200))
enemy_x = random.randint(0,425)
score += 1
if enemy2_y >= 700:
enemy2_y = -(random.randint(0,750))
enemy2_x = random.randint(0,425)
score += 1
if police_y <= 40:
police_y = random.randint(750,1900)
police_x = random.randint(0,425)
score += 1
enemy_a()
if score >= 7:
enemy_b()
if score >= 15:
police_speed += 0.0001
enemy = pygame.image.load("crepa.png").convert_alpha()
enemy_2 = pygame.image.load("crepa.png").convert_alpha()
police = pygame.image.load("polizia.png").convert_alpha()
playerr = player.get_rect()
enemyr = enemy.get_rect()
policer = police.get_rect()
enemyr2 = enemy_2.get_rect()
if enemyr.colliderect(playerr):
pygame.quit()
sys.exit()
if enemyr2.colliderect(playerr):
pygame.quit()
sys.exit()
if crepar.colliderect(policer):
enemy_b()
if player.colliderect(policer):
pygame.quit()
ys.exit()
pygame.display.flip()
clock.tick(60)
pygame.Surface.get_rect.get_rect() returns a rectangle with the size of the Surface object, that always starts at (0, 0) since a Surface object has no position. A Surface is blit at a position on the screen. The position of the rectangle can be specified by a keyword argument. For example, the top left of the rectangle can be specified with the keyword argument topleft:
playerr = player.get_rect(topleft = (player_x, player_y))
enemyr = enemy.get_rect(topleft = (enemy_x, enemy_y))
policer = police.get_rect(topleft = (police_x, police_y))
enemyr2 = enemy_2.get_rect(topleft = (enemy2_x, enemy2_y))
if enemyr.colliderect(playerr):
pygame.quit()
sys.exit()
if enemyr2.colliderect(playerr):
pygame.quit()
sys.exit()
if player.colliderect(policer):
pygame.quit()
sys.exit()
This question already has answers here:
What does pygame.sprite.Group() do
(1 answer)
Is there a better way to spawn enemy locations?
(1 answer)
When I use pygame.sprite.spritecollide(), why does only the bullets disappear?
(1 answer)
Closed 5 months ago.
I am teaching myself python 3, and creating a python based game using pygame but am running into two problems.
In order to post here, I stripped my game down to the bare minimum but there is still quite a bit and I apologize for that. You have to actually be able to run my game to see the problem, so the below is the minimum required code to duplicate the problem. I stripped out all non essentials, walls, weapons, types of characters and images and replaced them with blocks so you can just copy, paste, and run it in Python 3.
This game is a "survive each round" type game.
Every level, there should be more enemy's allowed on the screen at a time. When the player shoots them, they are removed, but another one spawns to take its place.
I have 2 main problems.
The only parts of my code that currently (should be) removing enemy sprites from the sprites list, is if they get shot by the player, or they make contact with the player. About every 20 enemy's or so, one will simply disappear and I can't figure out why.
To the best of my knowledge, I have the enemy spawn set so that they will only spawn if they are at least 500 pixels away in any direction, yet they still will occasionally spawn on top of the player.
The best way to replicate these is playing the first few levels, and watch specifically for enemy's disappearing or spawning super close. It seems to be rng so it may take a few attempts.
I included notes in the code to attempt to save you from having to scan the whole thing.
import pygame,math,random,sys
#Colors
black = (0,0,0)
white = (255,255,255)
red = (188,13,13)
orange = (188,13,13)
yellow = (188,188,13)
green = (101,188,13)
blue_green = (13,188,100)
blue = (13,101,188)
purple = (100,13,188)
magenta = (188,13,101)
background1 = (93,58,23)
texture_1_1 = (116,71,25)
texture_1_2 = (75,57,31)
texture_1_3 = (105,77,49)
class Elven_Arrow_up(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.image = pygame.Surface([4,4])
self.image.fill(black)
self.rect = self.image.get_rect()
def update(self):
self.rect.y -= 4
class Elven_Arrow_down(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.image = pygame.Surface([4,4])
self.image.fill(black)
self.rect = self.image.get_rect()
def update(self):
self.rect.y += 4
class Elven_Arrow_left(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.image = pygame.Surface([4,4])
self.image.fill(black)
self.rect = self.image.get_rect()
def update(self):
self.rect.x -= 4
class Elven_Arrow_right(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.image = pygame.Surface([4,4])
self.image.fill(black)
self.rect = self.image.get_rect()
def update(self):
self.rect.x += 4
class Player(pygame.sprite.Sprite):
def __init__(self,health,speed, x, y):
super().__init__()
self.health = health
self.speed = speed
self.image = pygame.Surface([32,32])
self.image.fill(blue)
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
self.change_x = 0
self.change_y = 0
def changespeed(self, x, y):
self.change_x += x
self.change_y += y
def update(self):
self.rect.x += self.change_x
self.rect.y += self.change_y
class Enemy (pygame.sprite.Sprite):
def __init__(self,speed,health,points):
super().__init__()
self.image = pygame.Surface([32,32])
self.image.fill(red)
self.rect = self.image.get_rect()
self.speed = speed
self.health = health
self.points = points
def update(self):
dirvect = pygame.math.Vector2(player.rect.x - self.rect.x,
player.rect.y - self.rect.y)
dirvect.normalize()
dirvect.scale_to_length(self.speed)
self.rect.move_ip(dirvect)
class GameState():
def __init__(self):
self.state = 'intro'
def intro(self):
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
pygame.quit()
sys.exit()
if event.type == pygame.MOUSEBUTTONDOWN:
self.state = 'level'
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
self.state = 'level'
screen.fill(white)
score_font = pygame.font.SysFont('Calibri', 25, True, False)
score_text = score_font.render('Click the Space Bar to Begin.',True,black)
screen.blit(score_text,(screen_width/2 - 180,screen_height/2 + 250))
pygame.display.flip()
def game_over(self):
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
pygame.quit()
sys.exit()
if event.type == pygame.MOUSEBUTTONDOWN:
global enemy_list
global all_sprites_list
global player
global score
global max_num_of_enemies
global level
global score_needed
global score_needed_constant
global score_needed_add
global score_needed_add_constant
max_num_of_enemies = max_num_of_enemies_constant
enemy_list = pygame.sprite.Group()
all_sprites_list = pygame.sprite.Group()
player = Player(10,3,screen_width/2-3,screen_width/2,cinder_image)
all_sprites_list.add(player)
score_needed = score_needed_constant
score_needed_add = score_needed_add_constant
score = 0
self.state = 'intro'
screen.fill(black)
score_font = pygame.font.SysFont('Calibri', 25, True, False)
score_text = score_font.render("Click to continue.",True,white)
level_text = score_font.render("You got to Level: " + str(level),True,white)
screen.blit(score_text,(screen_width/2 + 200,screen_height/2 + 350))
screen.blit(level_text,(10,10))
pygame.display.flip()
#Below this line ends the level, removes all sprites from display lists, and returns the player to the center of the screen
def level_complete(self):
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
pygame.quit()
sys.exit()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
global enemy_list
global all_sprites_list
global player
global score
global max_num_of_enemies
global max_num_of_enemies_constant
global level
enemy_list = pygame.sprite.Group()
all_sprites_list = pygame.sprite.Group()
all_sprites_list.add(player)
player.change_x = 0
player.change_y = 0
player.rect.x = screen_width/2
player.rect.y = screen_width/2
player.update()
self.state = 'level'
screen.fill(blue)
score_font = pygame.font.SysFont('Calibri', 25, True, False)
continue_text = score_font.render("Release all keys, and Press the Spacebar to Continue.",True,white)
level_text = score_font.render("You Completed level " + str(level-1) + "",True,white)
screen.blit(continue_text,(50,screen_height - 30))
screen.blit(level_text,(screen_width/2-100,screen_height/2))
pygame.display.flip()
#Above this line ends the level, removes all sprites from display, and returns the player to the center of the screen
#Below this line is the main game loop.
def level(self):
global Enemy
global enemy_list
global score
global player
global all_sprites_list
global max_num_of_enemies
global level
global score_needed
global score_needed_add
pygame.mouse.set_visible(1)
#Below this line spawns enemy's, if there are less enemy's than the max number of enemies AND they are far enough from the player
if len(enemy_list.sprites()) < max_num_of_enemies:
x = random.randrange(-500,screen_width+500)
y = random.randrange(-500,screen_height+500)
spawn = True
for enemy in enemy_list:
ex, ey = enemy.rect.center
distance = math.hypot(ex - x, ey - y)
if distance < minimum_distance:
spawn = False
break
if spawn:
speed = 1.5
health = 1
points = 1
enemy = Enemy(speed,health,points)
enemy.rect.center = x, y
enemy_list.add(enemy)
all_sprites_list.add(enemy)
#Above this line spawns enemy's, if there are less enemy's than the max number of enemies AND they are far enough from the player
#Below this line determines when the level will end, increases the number of enemies allowed on the screen, and sends you to the level complete page
if level < 1:
level = 1
elif score >= score_needed:
level +=1
max_num_of_enemies += 3
score_needed += score_needed_add
score_needed_add += 5
player.health += 1
self.state = 'level_complete'
#Above this line determines when the level will end, increases the number of enemies allowed on the screen, and sends you to the level complete page
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
pygame.quit()
sys.exit()
if player.health <= 0:
self.state = 'game_over'
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_a:
player.changespeed(-3, 0)
elif event.key == pygame.K_d:
player.changespeed(3, 0)
elif event.key == pygame.K_w:
player.changespeed(0, -3)
elif event.key == pygame.K_s:
player.changespeed(0, 3)
elif event.key == pygame.K_LEFT:
projectile = Elven_Arrow_left()
projectile.rect.x = player.rect.x + 3
projectile.rect.y = player.rect.y + 8
projectile_list.add(projectile)
all_sprites_list.add(projectile)
elif event.key == pygame.K_RIGHT:
projectile = Elven_Arrow_right()
projectile.rect.x = player.rect.x + 3
projectile.rect.y = player.rect.y + 8
projectile_list.add(projectile)
all_sprites_list.add(projectile)
elif event.key == pygame.K_UP:
projectile = Elven_Arrow_up()
projectile.rect.x = player.rect.x + 3
projectile.rect.y = player.rect.y + 8
projectile_list.add(projectile)
all_sprites_list.add(projectile)
elif event.key == pygame.K_DOWN:
projectile = Elven_Arrow_down()
projectile.rect.x = player.rect.x + 3
projectile.rect.y = player.rect.y + 8
projectile_list.add(projectile)
all_sprites_list.add(projectile)
elif event.type == pygame.KEYUP:
if event.key == pygame.K_a:
player.changespeed(3, 0)
elif event.key == pygame.K_d:
player.changespeed(-3, 0)
elif event.key == pygame.K_w:
player.changespeed(0, 3)
elif event.key == pygame.K_s:
player.changespeed(0, -3)
all_sprites_list.update()
if player.rect.y > screen_height + 10:
player.rect.y = -10
elif player.rect.y < -10:
player.rect.y = screen_height + 10
if player.rect.x > screen_width + 10:
player.rect.x = -10
elif player.rect.x < -10:
player.rect.x = screen_width + 10
#Below this line removes an enemy if they are shot by the player, and gives them a point
for projectile in projectile_list:
player_hit_list = pygame.sprite.spritecollide(projectile,enemy_list,True)
for enemy in player_hit_list:
projectile_list.remove(projectile)
all_sprites_list.remove(projectile)
score += 1
#Above this line removes an enemy if they are shot by the player, and gives them a point
if projectile.rect.y < -10:
projectile_list.remove(projectile)
all_sprites_list.remove(projectile)
elif projectile.rect.y > screen_height + 10:
projectile_list.remove(projectile)
all_sprites_list.remove(projectile)
elif projectile.rect.x < -10:
projectile_list.remove(projectile)
all_sprites_list.remove(projectile)
elif projectile.rect.x > screen_width + 10:
projectile_list.remove(projectile)
all_sprites_list.remove(projectile)
#Below this line removes an enemy if they make contact with the player.
for block in enemy_list:
enemy_hit_list = pygame.sprite.spritecollide(player, enemy_list, True)
for block in enemy_hit_list:
enemy_list.remove(block)
all_sprites_list.remove(block)
player.health -= block.points
#Above this line removes an enemy if they make contact with the player.
screen.fill(background1)
for i in texture_list1:
texture1 = pygame.draw.rect(screen,texture_1_1,[i[0],i[1],10,10])
for i in texture_list2:
texture1 = pygame.draw.rect(screen,texture_1_2,[i[0],i[1],10,10])
for i in texture_list3:
texture1 = pygame.draw.rect(screen,texture_1_3,[i[0],i[1],10,10])
all_sprites_list.draw(screen)
score_font = pygame.font.SysFont('Calibri', 25, True, False)
score_text = score_font.render("Score: " + str(score),True,blue_green)
noob_text = score_font.render("w,a,s,d to move, arrow keys to shoot. Good luck.",True,white)
level_text = score_font.render("Level: " + str(level),True,blue_green)
screen.blit(score_text,[10,10])
screen.blit(level_text,[screen_width - 150,10])
if score < 10:
screen.blit(noob_text,[100,10])
if player.health >= health_status[0]:
health_text = score_font.render("Health: " + str(player.health),True,blue_green)
elif player.health >= health_status[1]:
health_text = score_font.render("Health: " + str(player.health),True,green)
elif player.health >= health_status[2]:
health_text = score_font.render("Health: " + str(player.health),True,yellow)
elif player.health >= health_status[3]:
health_text = score_font.render("Health: " + str(player.health),True,orange)
elif player.health >= health_status[4]:
health_text = score_font.render("Health: " + str(player.health),True,red)
screen.blit(health_text, [10,40])
pygame.display.flip()
#Above this line is the main game loop
def state_manager(self):
if self.state == 'intro':
self.intro()
if self.state == 'game_over':
self.game_over()
if self.state == 'level':
self.level()
if self.state == 'level_complete':
self.level_complete()
pygame.init()
screen_width = 1000
screen_height = 800
screen = pygame.display.set_mode([screen_width, screen_height])
game_state = GameState()
enemy_list = pygame.sprite.Group()
projectile_list = pygame.sprite.Group()
item_list = pygame.sprite.Group()
texture_list1 = []
texture_list2 = []
texture_list3 = []
all_sprites_list = pygame.sprite.Group()
player = Player(10,3,screen_width/2 - 3,screen_height/2)
all_sprites_list.add(player)
for i in range(50):
x=random.randrange(screen_width)
y=random.randrange(screen_width)
texture_list1.append([x,y])
for i in range(50):
x=random.randrange(screen_width)
y=random.randrange(screen_width)
texture_list2.append([x,y])
for i in range(50):
x=random.randrange(screen_width)
y=random.randrange(screen_width)
texture_list3.append([x,y])
#Below this line sets the starting points, and constants through the game.
score = 0
health_status = (8,6,4,2,-100)
level = 1
minimum_distance = 500
score_needed_constant = 15
score_needed = score_needed_constant
score_needed_add_constant = 15
score_needed_add = score_needed_add_constant
max_num_of_enemies_constant = 8
max_num_of_enemies = max_num_of_enemies_constant
#Above this line sets the starting points, and constants through the game.
#Below this line starts, and ends the game loop
done = False
clock = pygame.time.Clock()
while not done:
game_state.state_manager()
#Above this line starts, and ends the game loop
clock.tick(60)
been trying for a while to find the problem with the following code. I'm trying to have the pointer move up and down like the title of the question states but it just won't move. Any and all help is welcome.
Code for Pause Screen event processing:
for event in pygame.event.get(): # User did something
if event.type == pygame.QUIT: # If user clicked close
pygame.quit()
sys.exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_UP or event.key == pygame.K_w:
self.pointer.moveUp()
print("Up we go")
if event.key == pygame.K_DOWN or event.key == pygame.K_s:
self.pointer.moveDown()
print("Down we go")
if event.key == pygame.K_RETURN:
self.selection = int(pointer.Pointer.getPosition(self.pointer))
print(str(pointer.Pointer.getPosition(self.pointer)))
return True
return False
Code for displaying which shows the pointer in the same place.
self.active_sprite_list.draw(screen)
font = pygame.font.SysFont("serif", 25)
text = []
center_x = []
center_y = []
for counter in range(1,5):
text.append(font.render(self.options[counter-1], True, constants.WHITE))
center_x.append(150)
center_y.append((counter * 120) - (text[counter-1].get_height() // 2) + (self.pointer.image.get_height() // 2))
screen.blit(text[counter-1], [center_x[counter-1],center_y[counter-1]])
pygame.display.flip()
And for reference the same code in the Menu which has the pointer moving up and down:
for event in pygame.event.get(): # User did something
if event.type == pygame.QUIT: # If user clicked close
pygame.quit()
sys.exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_UP or event.key == pygame.K_w:
self.pointer.moveUp()
if event.key == pygame.K_DOWN or event.key == pygame.K_s:
self.pointer.moveDown()
if event.key == pygame.K_RETURN:
self.selection = int(pointer.Pointer.getPosition(self.pointer))
#print(str(self.selection))
return True
###Some code later###
screen.fill(constants.BLACK)
font = pygame.font.SysFont("serif", 25)
for counter in range(1,5):
text = font.render(self.options[counter-1], True, constants.WHITE)
center_x = 150
center_y = (counter * 120) - (text.get_height() // 2) + (self.pointer.image.get_height() // 2)
screen.blit(text, [center_x, center_y])
self.active_sprite_list.draw(screen)
pygame.display.flip()
And before you suggest, the screen for the pause has been declared before here:
while notPaused == False:
#print("Received")
notPaused = pause.processEvents()
print(str(notPaused))
if firstTime == True:
self.pauseScreen.fill(constants.ABLACK)
pause.displayFrame(self.pauseScreen)
self.pauseScreen.set_alpha(128)
screen.blit(self.pauseScreen, [0,0])
firstTime = False
pause.displayFrame(self.pauseScreen)
clock.tick(60)
As per requested, here is the MoveUp and MoveDown functions in the Pointer Class:
def moveUp(self):
if self.rect.y <= 120:
self.rect.y = 480
else:
self.rect.y -= 120
def moveDown(self):
if self.rect.y >= 480:
self.rect.y = 120
else:
self.rect.y += 120
And as suggested, the modular/self-contained code that can be run on its own as long as you have some kind of image in a Resources Folder next to the saved code file.
import pygame, sys
"""
Global constants
"""
# Colors
ABLACK = ( 0, 0, 0, 125)
BLACK = ( 0, 0, 0)
WHITE = ( 255, 255, 255)
BLUE = ( 0, 0, 255)
YELLOW = ( 255, 255, 0)
# Screen dimensions
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600
class Pointer(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("Resources/Pointer.png")
self.rect = self.image.get_rect()
self.rect.x = 100
self.rect.y = 120
def moveUp(self):
if self.rect.y <= 120:
self.rect.y = 480
else:
self.rect.y -= 120
print("Within pointer object moving up from ",self.rect.x,self.rect.y)
def moveDown(self):
if self.rect.y >= 480:
self.rect.y = 120
else:
self.rect.y += 120
print("Within pointer object moving up from ",self.rect.x,self.rect.y)
def getPosition(self):
self.position = self.rect.y / 120
return self.position
class Pause(object):
def __init__(self,screen):
self.selection = 4
self.options = ["Resume Game","Review Controls","Back to Menu","Quit"]
self.active_sprite_list = pygame.sprite.Group()
self.pointer = Pointer()
self.active_sprite_list.add(self.pointer)
def processEvents(self):
for event in pygame.event.get(): # User did something
if event.type == pygame.QUIT: # If user clicked close
pygame.quit()
sys.exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_UP or event.key == pygame.K_w:
self.pointer.moveUp()
print("Up we go")
if event.key == pygame.K_DOWN or event.key == pygame.K_s:
self.pointer.moveDown()
print("Down we go")
if event.key == pygame.K_RETURN:
self.selection = int(Pointer.getPosition(self.pointer))
print(str(Pointer.getPosition(self.pointer)))
return False
return True
def displayFrame(self,screen):
self.active_sprite_list.draw(screen)
for pointer in self.active_sprite_list:
print("The y value of this pointer is:" + str(pointer.rect.y))
font = pygame.font.SysFont("serif", 25)
text = []
center_x = []
center_y = []
for counter in range(1,5):
text.append(font.render(self.options[counter-1], True, WHITE))
center_x.append(150)
center_y.append((counter * 120) - (text[counter-1].get_height() // 2) + (self.pointer.image.get_height() // 2))
for pointer in self.active_sprite_list:
print("The y value of this pointer is:" + str(pointer.rect.y))
screen.blit(text[counter-1], [center_x[counter-1],center_y[counter-1]])
for pointer in self.active_sprite_list:
print("The y value of this pointer is:" + str(pointer.rect.y))
pygame.display.flip()
pygame.init()
pygame.display.set_caption("Pause Error Finder")
size = [SCREEN_WIDTH, SCREEN_HEIGHT]
screen = pygame.display.set_mode(size)
Paused = True
clock = pygame.time.Clock()
pauseScreen = pygame.Surface(size,pygame.SRCALPHA,32)
pauseScreen.fill(ABLACK)
pause = Pause(screen)
pauseScreen.set_alpha(128)
Paused = pause.processEvents()
print(str(notPaused))
pause.displayFrame(pauseScreen)
screen.blit(pauseScreen, [0,0])
while Paused:
notPaused = pause.processEvents()
print(str(Paused))
pause.displayFrame(pauseScreen)
#screen.blit(pauseScreen, [0,0])
clock.tick(60)
Your issue is in the main game loop, first off, you had the blitting of Pause Screen to Screen commented out. readding that in gave the pointer seeming to multiply and go all over the place (getting closer!).
The reason it does that is you did not update your pauseScreen in each pass of the loop. Your displayFrame will add your pointer to the proper location, but the one from last frame, and 2 frames ago, and... are still there. by moving the lines
pauseScreen.fill(ABLACK)
pauseScreen.set_alpha(128)
And placing them within your game loop, the pause screen is reset ever frame and only the latest pointer is displayed. Here is the updated game loop:
pygame.init()
pygame.display.set_caption("Pause Error Finder")
size = [SCREEN_WIDTH, SCREEN_HEIGHT]
screen = pygame.display.set_mode(size)
notPaused = False
clock = pygame.time.Clock()
pauseScreen = pygame.Surface(size,pygame.SRCALPHA,32)
pause = Pause(screen)
notPaused = pause.processEvents()
print(str(notPaused))
pause.displayFrame(pauseScreen)
screen.blit(pauseScreen, [0,0])
while not notPaused:
notPaused = pause.processEvents()
print(str(notPaused))
pauseScreen.fill(ABLACK)
pauseScreen.set_alpha(128)
pause.displayFrame(pauseScreen)
screen.blit(pauseScreen, [0,0])
clock.tick(60)
So im new at pygame and coding my first project- a side scrolling shooter. The issue im having is with my bullets: when i press the space key, some of the bullets will show up but there are times when nothing happens, and no bullets spawn when i jump. Not quite sure how to go about fixing this issue- any ideas would be greatly appreciated.
Code is as follows:
import pygame
import math, random, sys, pygame.mixer
from pygame.locals import *
pygame.init()
pygame.mixer.pre_init(44100, -16, 2, 8192)
pygame.mixer.init()
jump = False
jump_offset = 0
jump_height = 250
k = pygame.key.get_pressed()
def events():
for event in pygame.event.get():
if event.type == QUIT or (event.type == KEYDOWN and event.key == K_ESCAPE):
pygame.quit()
sys.exit()
def do_jumping():
global jump_height
global jump
global jump_offset
if jump:
jump_offset += 3
if jump_offset >= jump_height:
jump = False
elif jump_offset > 0 and jump == False:
jump_offset -= 3
#Defining colours
BLACK = ( 0, 0, 0)
WHITE = ( 255, 255, 255)
#Window Settings
w = 1280
h = 720
half_w = w /2
half_h = h /2
AREA = w*h
#Initialising the window
pygame.init()
display = pygame.display.set_mode((w,h)) #Sets the size of the window
pygame.display.set_caption("Cattleman") #Sets the title of the window
Clock = pygame.time.Clock() #clockspeed for the game ie. 60fps
FPS = 600
#pygame.mouse.set_visible(True) #Allows the mouse to be shown in the game window.
background = pygame.image.load("background.png").convert()
backgroundWidth, backgroundHeight = background.get_rect().size
stageWidth = backgroundWidth*2 #sets the area which the player can move in
stagePosX = 0 #Records position of stage as the player moves
startScrollPosX = half_w
circleRadius = 25
circlePosX = circleRadius
playerPosX = circleRadius
playerPosY = 602
playerVelocityX = 0
playersprite = pygame.image.load("player_spriteR2.png").convert_alpha()
playersprite = pygame.transform.scale(playersprite, (130,130))
bullets = []
bulletSprite = pygame.image.load("Bullet1.png").convert_alpha()
bulletSprite = pygame.transform.scale(bulletSprite, (20,10))
#Sounds
#gunSounds = ["pew1.wav", "pew2.wav", "pew3.wav", "pew4.wav"]
#SOUNDS
shot = pygame.mixer.Sound("pew1.wav")
#------------------------MAIN PROGRAM LOOP------------------------#
while True:
events()
do_jumping()
k = pygame.key.get_pressed()
if k[K_RIGHT]:
playerVelocityX = 2 #Moves the player right
playersprite = pygame.image.load("player_spriteR2.png").convert_alpha()
playersprite = pygame.transform.scale(playersprite, (130,130))
if k[K_LEFT]:
playerVelocityX = -2 #Moves the player left
playersprite = pygame.image.load("player_spriteL2.png").convert_alpha()
playersprite = pygame.transform.scale(playersprite, (130,130))
if k[K_UP] and jump == False and jump_offset == 0:
jump = True
if not k[K_RIGHT] and not k[K_LEFT]:
playerVelocityX = 0 #If no input detected, the player does not move
if k[K_SPACE]:
for event in pygame.event.get():
bullets.append([circlePosX-100, playerPosY-20])
shot.play()
playerPosX += playerVelocityX
if playerPosX > stageWidth - circleRadius-25: playerPosX = stageWidth - circleRadius-25 #Checks if the player trie to go past the right boundary
if playerPosX < circleRadius+55:playerPosX = circleRadius+55 #Checks if the player tries to go past the left boundary
if playerPosX < startScrollPosX: circlePosX = playerPosX
elif playerPosX > stageWidth - startScrollPosX: circlePosX = playerPosX - stageWidth + w
else:
circlePosX = startScrollPosX
stagePosX += -playerVelocityX
for b in range(len(bullets)):
bullets[b][0] -= 3
for bullet in bullets[:]:
if bullet[0] < 0:
bullets.remove(bullet)
rel_x = stagePosX % backgroundWidth
display.blit(background,(rel_x - backgroundWidth, 0))
if rel_x < w:
display.blit(background, (rel_x, 0))
for bullet in bullets:
display.blit(bulletSprite, pygame.Rect(bullet[0], bullet[1], 0, 0,))
#pygame.draw.circle(display,WHITE, (int(circlePosX),playerPosY - jump_offset), circleRadius, 0)
display.blit(playersprite, (int(circlePosX-80),playerPosY-100 - jump_offset))
pygame.display.update()
Clock.tick(FPS)
display.fill(BLACK)
I have done this in my code that leaves multiple balls similar like bullets :
class Bullet():
def __init__(self, x, y):
# self.image = pygame.image.load("SingleBullet.png")
self.image = pygame.image.load("ball.png")
self.image = pygame.transform.scale(self.image, (25, 25))
self.rect = self.image.get_rect()
self.rect.centerx = x
self.rect.centery = y
self.is_alive = True
# --------------------
def update(self):
self.rect.y -= 15
if self.rect.y < 0:
self.is_alive = False
# --------------------
def draw(self, screen):
screen.blit(self.image, self.rect.topleft)
for getting keyboard :
def event_handler(self, event):
if event.type == KEYDOWN:
if event.key == K_LEFT:
self.move_x = -5
elif event.key == K_RIGHT:
self.move_x = 5
elif event.key == K_SPACE:
if len(self.shots) < self.max_shots:
self.shots.append(Bullet(self.rect.centerx, self.rect.top))
if event.type == KEYUP:
if event.key in (K_LEFT, K_RIGHT):
self.move_x = 0
I have been working on this pygame application, that is bascially a coin collecting game. It has a very simple idea, where you have a freely moving player (a blue ball in this case, move it by "WASD") and it should collect coins that appear on the screen after a certain amount of time. The code is pretty long, for SO standarts, I will try my best explaining my problem.
from pygame.locals import *
import pygame
import sys
import time
import random
image_resources = "C:/Users/user/Desktop/Pygame App/app_resources/image_resources/"
sound_resources = "C:/Users/user/Desktop/Pygame App/app_resources/sound_resources/"
width,height = 400,400
size = (width,height)
elapsed_seconds = 0
def quit_game():
pygame.quit()
sys.exit("System exit.")
class GetSource:
def background(self,image):
return pygame.image.load(image_resources + image).convert()
def player(self,image):
return pygame.image.load(image_resources + image).convert_alpha()
class Wall(pygame.sprite.Sprite):
def __init__(self,color,x,y,width,height):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface((width,height))
self.image.fill(pygame.color.Color(color))
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
class Player(pygame.sprite.Sprite):
def __init__(self,image):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load(image_resources + image).convert_alpha()
self.rect = self.image.get_rect()
class Coin(pygame.sprite.Sprite):
def __init__(self,image):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load(image_resources + image).convert_alpha()
self.rect = self.image.get_rect()
pygame.init()
screen = pygame.display.set_mode(size)
pygame.display.set_caption("PyGame App")
background = GetSource().background("bg_solid_black_square.jpg")
player = GetSource().player("ball_blue.png")
player_dimension = player.get_width()
x,y = width/2-player_dimension,height/2-player_dimension
movex,movey = 0,0
walls = pygame.sprite.Group()
players = pygame.sprite.Group()
coins = pygame.sprite.Group()
all_sprites = pygame.sprite.Group()
wall_1 = Wall("white", 0, 0, width, 5)
wall_2 = Wall("white", 0, 0, 5, height)
wall_3 = Wall("white", 0, height-5, width, 5)
wall_4 = Wall("white", width-5, 0, 5, height)
player = Player("ball_blue.png")
coin = Coin("coin.png")
walls.add(wall_1,wall_2,wall_3,wall_4)
players.add(player)
coins.add(coin)
all_sprites.add(wall_1,wall_2,wall_3,wall_4,player)
while True:
time.sleep(0.01)
elapsed_seconds += 0.01
collide_list_1 = pygame.sprite.spritecollideany(wall_1,players)
collide_list_2 = pygame.sprite.spritecollideany(wall_2,players)
collide_list_3 = pygame.sprite.spritecollideany(wall_3,players)
collide_list_4 = pygame.sprite.spritecollideany(wall_4,players)
for event in pygame.event.get():
if event.type == QUIT:
quit_game()
if event.type == KEYDOWN:
if event.key == K_q:
quit_game()
elif event.key == K_a:
movex = -1
elif event.key == K_d:
movex = 1
elif event.key == K_w:
movey = -1
elif event.key == K_s:
movey = 1
if event.type == KEYUP:
if event.key == K_a or event.key == K_d:
movex = 0
if event.key == K_w or event.key == K_s:
movey = 0
if collide_list_1 != None:
movey = 0
y += 1
if collide_list_2 != None:
movex = 0
x += 1
if collide_list_3 != None:
movey = 0
y -= 1
if collide_list_4 != None:
movex = 0
x -= 1
else:
x += movex
y += movey
player.rect.x = x
player.rect.y = y
coin.rect.x = random.randint(0,width)
coin.rect.y = random.randint(0,height)
screen.blit(background, (0,0))
if elapsed_seconds % 4 == 0:
coins.draw(screen)
coins.update()
all_sprites.draw(screen)
all_sprites.update()
pygame.display.update()
As you can see, I am increasing the "elapsed_seconds" variable every frame by the time a wait, in order the regulate frames per second, then check if it is a multiple of 4. But the thing is, when I monitored the "elapsed_seconds" variable, it never actually becomes 4. It generally goes around at "2,9998999128999" and stuff. I tried;
elapsed_seconds = math.floor(elapsed_seconds)
but that is no good as well. So, how can I render this coin at every set time interval?
EDIT: I want the sprites not to be flashing on the screen, I want them to be staying where they are after the "certin amount of time" is passed. So it should look as if it moved, after that "certain amount of time"! Thanks.
Firstly, pygame.time.get_ticks() will return elapsed milliseconds since your game started. Your method is not accurate as it does not take into account the time spent executing your game loop.
You could just track the elapsed time since you last added a coin. Then:
ticks = pygame.time.get_ticks()
if ticks - last_coin_ticks > 1000: # new coin once per second
last_coin_ticks = ticks
# add a new coin