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
Related
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")
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)
im new to python, and recently encountered a problem when trying to animate the Sprite of my main character.
Code error is
"IndexError: list index out of range".
The character moves a few pixels and then stops and the error is displayed, it never shows any animation.
import pygame
import sys
import os
pygame.display.set_mode()
class Adventurer(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.movex = 0
self.movey = 0
self.frame = 0
self.runRight = []
for i in range(1,6):
img = pygame.image.load(os.path.join("Characters", "ADVENTURER", "runR" + str(i) + '.png'))
img.convert_alpha()
img.set_colorkey(ALPHA)
self.runRight.append(img)
self.image = self.runRight[0]
self.rect = self.image.get_rect()
#runningLeft
self.runLeft = []
for i in range(1,6):
img = pygame.image.load(os.path.join("Characters", "ADVENTURER", "runL" + str(i) + '.png'))
img.convert_alpha()
img.set_colorkey(ALPHA)
self.runLeft.append(img)
self.image = self.runLeft[0]
self.rect = self.image.get_rect()
def control(self,x,y): #control player movement
self.movex += x
self.movey += y
def update(self):
self.rect.x = self.rect.x + self.movex
self.rect.y = self.rect.y + self.movey
#moving left
if self.movex < 0:
self.frame += 1
if self.frame > 6*ani:
self.frame = 0
self.image = self.runLeft[self.frame//ani]
#moving right
if self.movex > 0:
self.frame += 1
if self.frame > 6*ani:
self.frame = 0
self.image = self.runRight[self.frame//ani]
ALPHA = (1, 1, 1)
screenWidth = 900
screenHeight = 507
fps = 20
ani = 6
clock = pygame.time.Clock()
pygame.init()
world = pygame.display.set_mode([screenWidth, screenHeight])
backdrop = pygame.image.load(os.path.join("Backgrounds", "Background1.jpg")).convert()
backdropbox = world.get_rect()
player = Adventurer()
player.rect.x = 0
player.rect.y = 435
player_list = pygame.sprite.Group()
player_list.add(player)
steps = 10 #pixels to move
main = True
while main == True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit(); sys.exit()
main = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
pygame.quit()
sys.exit()
main = False
if event.key == pygame.K_LEFT or event.key == ord("a"):
player.control(-steps,0)
if event.key == pygame.K_RIGHT or event.key == ord("d"):
player.control(steps, 0)
if event.key == pygame.K_UP or event.key == ord("w"):
print ("jump")
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT or event.key == ord("a"):
player.control(steps,0)
if event.key == pygame.K_RIGHT or event.key == ord("d"):
player.control(-steps,0)
if event.key == pygame.K_UP or event.key == ord("w"):
print ("jump stop")
world.blit(backdrop, backdropbox)
player.update()
player_list.draw(world)
pygame.display.flip()
clock.tick(fps)
The idea is for the character to gice the idea of movement.
This is the error i get:
FromScratch.py", line 51, in update self.image = self.runLeft[self.frame//ani]
IndexError: list index out of range
In your code only the last image is append to the list, because the .append instruction is after the loop. It has to be done in the loop:
self.runRight = []
for i in range(1,6):
img = pygame.image.load(os.path.join("Characters", "ADVENTURER", "runR" + str(i) + '.png'))
img.convert_alpha()
img.set_colorkey(ALPHA)
# -->
self.runRight.append(img)
self.runLeft = []
for i in range(1,6):
img = pygame.image.load(os.path.join("Characters", "ADVENTURER", "runL" + str(i) + '.png'))
img.convert_alpha()
img.set_colorkey(ALPHA)
# -->
self.runLeft.append(img)
The "list index out of range" out of range error is caused by the look up of the image list. You've to use the modulo (%) operator, to calculate the integral remainder of a division by the number of images (See operator):
def update(self):
# [...]
if self.movex < 0:
self.frame += 1
self.image = self.runLeft[(self.frame//ani) % len(self.runLeft)]
if self.movex > 0:
self.frame += 1
self.image = self.runRight[(self.frame//ani) % len(self.runRight)]
According to the comment:
[...] it moves quite fast [...]
Add clock = pygame.time.Clock() at the initialization and clock.tick(60) inside the game loop (right after while main == True:). See pygame.time.Clock. With the parameter to .tick() you can throttle the speed:
clock = pygame.time.Clock()
while main == True:
clock.tick(60)
# [...]
The line self.runLeft.append(img) is intended too little, placing it outside of the for loop. Therefore, only the last image is added to self.runLeft, so attempts to access the second through fifth elements of the list (when self.frame becomes greater than ani) raise an error instead of producing an animation.
I have these blocks that I have made that are in the Enemy_Block class. When I try to move them they like teleport around the screen. How to I slow these enemy blocks down. Please help, thanks.
I have tried putting that for-loop that spawns enemy blocks in and outside the loop. That's it.
from random import randint
from pygame.locals import *
import pygame
import sys
# intalize Pygame
pygame.init()
# Making User Controled Block
class User_Block:
def __init__(self):
self.x_cor = 300
self.y_cor = 300
self.length = 20
self.width = 20
self.color = GREEN
self.move_x = 0
self.move_y = 0
self.rect = pygame.draw.rect(screen,self.color,[self.x_cor,self.y_cor,self.length,self.width],0)
def draw(self):
pygame.draw.rect(screen,self.color,[self.x_cor,self.y_cor,self.length,self.width],0)
self.y_cor += self.move_y
self.x_cor += self.move_x
if self.x_cor == x_size - self.width:
self.x_cor = 0
self.move_x = 0
elif self.x_cor == 0 - self.length:
self.x_cor = x_size
self.move_x = 0
elif self.y_cor == y_size - self.width:
self.y_cor = 0
self.move_y = 0
elif self.y_cor == 0 - self.length:
self.y_cor = y_size
self.move_y = 0
self.rect = pygame.draw.rect(screen,self.color,[self.x_cor,self.y_cor,self.length,self.width],0)
# Making Enemys
class Enemy_Block:
def __init__(self):
self.x_cor = randint(100,500)
self.y_cor = randint(100,500)
self.length = randint(10,100)
self.width = randint(10,100)
self.color = (255,0,255)
self.x_vel = randint(-5,5)
self.y_vel = randint(-5,5)
pygame.draw.rect(screen,self.color,[self.x_cor,self.y_cor,self.length,self.width],5)
def move_random(self):
if self.y_cor > y_size or self.y_cor < 0:
self.y_vel = -self.y_vel
elif self.x_cor > x_size or self.x_cor < 0:
self.x_vel = -self.x_vel
self.y_cor += self.y_vel
self.x_cor += self.x_vel
pygame.draw.rect(screen,self.color,[self.x_cor,self.y_cor,self.length,self.width],5)
# Set Up Screen
x_size = 1200
y_size = 700
screen = pygame.display.set_mode((x_size, y_size))
# Varible Used "while" Loop
done = False
# Setting Caption of Pygame Tab
pygame.display.set_caption("Block Rush Game")
# Colors
WHITE = (255,255,255)
BLACK = (0,0,0)
RED = (255,0,0)
GREEN = (0,255,0)
# User Controled Block
Block = User_Block()
# Enemys
Enemy_List = []
for i in range(10):
Enemy = Enemy_Block()
Enemy_List.append(Enemy)
# Most important code here
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
#Moving Character
if event.type == pygame.KEYDOWN:
if event.key == K_w:
Block.move_y = -5
elif event.key == K_s:
Block.move_y = 5
elif event.key == K_a:
Block.move_x = -5
elif event.key == K_d:
Block.move_x = 5
elif event.type == pygame.KEYUP:
if event.key == K_w or event.key == K_s:
Block.move_y = 0
elif event.key == K_a or event.key == K_d:
Block.move_x = 0
# Fill the Screen Black
screen.fill(BLACK)
# Activate draw function in Block
Block.draw()
#Spawn Enemy Blocks
Enemy_List = []
for i in range(10):
Enemy = Enemy_Block()
Enemy_List.append(Enemy)
# FPS
Clock = pygame.time.Clock()
Clock.tick(60)
# Keep Updating the Screen
pygame.display.update()
pygame.quit()
The expected result is that the game will create ten enemy blocks that move around the screen kinda slow because my velocity is low. The result is that the blocks kinda teleport around the screen, because they are moving soooo fast.
There are 2 issues. First, in your main game loop you are constantly spawning new enemies, and second, you're not telling your enemies to move
So in your main loop, change:
Enemy_List = []
for i in range(10):
Enemy = Enemy_Block()
Enemy_List.append(Enemy)
to:
for e in Enemy_List:
e.move_random()
You have already created your 10 enemies outside of the main loop, so no need to keep respawning them. Instead, you can just call move_random() on each one to move them around the screen
This seems undesirable:
Enemy_List = []
for i in range(10):
Enemy = Enemy_Block()
Enemy_List.append(Enemy)
You are producing new randomly initialized enemy blocks each time through the event loop.
You want to init just once, before the event loop begins,
and then let them move_random() within the loop.
I'm trying to create a little game as a training, but I'm blocked because I don't know how I can collide 2 moving cubes.
The game is simple, there is a red box that you can move and if this box touches a green cube, then you lost. (the green cubes are always moving)
I tried to read some documentations but it's not really easy to understand as a beginner.
Here is the code:
import pygame
import random
from threading import Timer
pygame.init()
screenWidth = 1100
screenHeight = 600
white = (255,255,255)
red = (255, 0, 0)
yellow = (50, 250, 20)
FPS = 60
gameDisplay = pygame.display.set_mode((screenWidth, screenHeight))
pygame.display.set_caption('Tekken')
pygame.display.update()
clock = pygame.time.Clock()
font = pygame.font.SysFont(None, 28)
class Players:
def __init__(self, playerName, playerAttribute, cubeheight, cubewidth, missilesHeight, missilesWidth):
self.playerName = playerName
self.playerAttribute = playerAttribute
self.playerLife = 100
self.droite_x = 300
self.droite_y = 600
self.cubeheight = cubeheight
self.cubewidth = cubewidth
self.missiles = True
self.missilesHeight = missilesHeight
self.missilesWidth = missilesWidth
self.missiles_droite_x = 0
self.missiles_droite_y = round(random.randrange(50, screenHeight-50))
self.missiles_droite_x_inverse = screenWidth-50
self.missiles_droite_y_inverse = round(random.randrange(50, screenHeight-50))
self.vitesse_missiles = 10
print(self.playerName, self.playerAttribute, self.playerLife)
def environment_un(self):
gameExit = False
gameOver = False
droite_x_change = 0
droite_y_change = 0
missiles_droite_x_change = 0
missiles_droite_x_change_inverse = 0
while not gameExit:
while gameOver:
gameDisplay.fill(red)
screen_text = font.render("Game Over, do you want to play again? [Q] to quit", True, white)
gameDisplay.blit(screen_text, [100, 300])
pygame.display.update()
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_q:
gameOver = False
gameExit = True
break
if event.type == pygame.QUIT:
gameOver = False
gameExit = True
break
for event in pygame.event.get(): #va chercher les events
if event.type == pygame.QUIT: #Si j'appuie sur X
gameExit = True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
droite_x_change = -3
if event.key == pygame.K_RIGHT:
droite_x_change = +3
if event.key == pygame.K_UP:
droite_y_change = -3
if event.key == pygame.K_DOWN:
droite_y_change = +3
if event.key == pygame.K_SPACE:
missiles_droite_x_change = self.vitesse_missiles
missiles_droite_x_change_inverse = -self.vitesse_missiles
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT:
droite_x_change = 0
if event.key == pygame.K_RIGHT:
droite_x_change = 0
if event.key == pygame.K_UP:
droite_y_change = 0
if event.key == pygame.K_DOWN:
droite_y_change = 0
self.missiles_droite_x_inverse += missiles_droite_x_change_inverse
self.missiles_droite_x += missiles_droite_x_change
self.droite_x += droite_x_change
self.droite_y += droite_y_change
if self.droite_y + self.cubeheight <= 0:
self.droite_y = 0
elif self.droite_y + self.cubeheight >= screenHeight:
self.droite_y = screenHeight-self.cubeheight
elif self.droite_x + self.cubewidth <= 0:
self.droite_x = 0
elif self.droite_x + self.cubewidth >= screenWidth:
self.droite_x = screenWidth-self.cubewidth
gameDisplay.fill(white)
gameDisplay.fill(red, rect=[self.droite_x, self.droite_y, self.cubewidth, self.cubeheight])
gameDisplay.fill(yellow, rect=[self.missiles_droite_x, self.missiles_droite_y, self.missilesWidth, self.missilesHeight])
gameDisplay.fill(yellow, rect=[self.missiles_droite_x_inverse, self.missiles_droite_y_inverse, self.missilesWidth, self.missilesHeight])
pygame.display.update()
if self.missiles_droite_x + self.missilesWidth >= screenWidth:
missiles_droite_x_change = 0
if missiles_droite_x_change == 0:
self.missiles_droite_x = 0
self.missiles_droite_y = round(random.randrange(50, screenHeight-50))
missiles_droite_x_change = self.vitesse_missiles
if self.missiles_droite_x_inverse <= 0:
missiles_droite_x_change_inverse = 0
if missiles_droite_x_change >= 0:
self.missiles_droite_x_inverse = screenWidth-50
self.missiles_droite_y_inverse = round(random.randrange(50, screenHeight-50))
missiles_droite_x_change_inverse = -12
clock.tick(FPS)
pygame.quit()
Player_1 = Players('John', 'sometext', 50, 50, 100, 100)
Player_1.environment_un()
What should do I in order to detect the collision?
I can not run your code at the moment as I dont have pygame installed. However, you can use the pygame.sprite.collide_rect() if you declare your objects to have in their class an pygame.sprite.Sprite-object or inherit from that class (as suggested below). The code below may note work as I can not test it but it should be close to a functioning code snippet. In the case you would like to test collision of a sprite against multiple other sprites - consider looking at pygame.sprite.Group(). I believe that something like this should work:
class SpriteObject(pygame.sprite.Sprite):
def __init__(self,pos_x, pos_y):
pygame.sprite.Sprite.__init__(self)
self.rect = self.original.get_rect()
self.rect.center = (pos_x, pos_y)
class Players:
def __init__(self, playerName, playerAttribute, cubeheight, cubewidth, missilesHeight, missilesWidth):
sprite1 = SpriteObject(1,2)
sprite2 = SpriteObject(1,2)
sprite1.rect.collide_rect(sprite2)
If you are looking for a conceptual answer:
Since you are considering just cubes and if they are of the same size, two cubes will occupy the same space 'if and only if' a corner of one cube is between (inclusive) two parallel planes of another. There are many ways to do this in practice.
I would check if between by evaluating an inward normal vector of cube 1 dotted with a vector to a corner (of cube 2) from any corner (of cube 1) . Do so for both parallel sides. If both are positive, its inside.
It's slightly more complicated for different shapes and varying sizes.
Use pygame.Rect() to keep cube position and size - and then you can use pygame.Rect.colliderect() to check collision between two cubes.
cube1 = pygame.Rect((x1, y1), (width, height))
cube2 = pygame.Rect((x2, y2), (width, height))
if cube1.colliderect(cube2):
print("Collision !")
PyGame has other usefull classes - pygame.sprite.Sprite and pygame.sprite.Group - which use Rect and collision detection functions.