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)
Related
I'm trying to make a Home Screen for two games in pygame, I changed the first game's name to module1 in the code Im providing and the Home Screen to Mainscreen
module1 is already done and now I'm just trying to get the Main Menu script to import the maingame when I click on the play button that I already have on the screen display, then when I finish the game (health reaches 0) , if I want to go back to the Main Menu I should just click anywhere on the "game over" screen that should appear when health reaches 0 or press escape.
here is what I tried:
this is the whole game script, the game loop is at the end of the script and sorry for how messy it is:
# Pygame skeleton
import pygame
import math
import random
import sys
import os
pygame.init()
pygame.mixer.init()
vec = pygame.math.Vector2
# Constants
WIDTH = 1306
HEIGHT = 526
FPS_INGAME = 60
FPS_HOMESCREEN = 30
FULL_SCREEN = (0,0)
bullet_img = pygame.image.load('Bullet.png')
jump = False
bullet_timer = 0
score = 0
moving_left = False
moving_right = False
shoot = False
acceleration = 0.7
friction = -0.1
gravity = 9.8
platform_color = (150,59,230)
# Classes and Sprites
class Player(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.shoot_cooldown = 0
self.anime = []
self.frame_index = 0
self.update_time = pygame.time.get_ticks()
self.action = 0
animation_types = ["Shoot","Go"]
for animation in animation_types:
temp_list = []
num_of_frames = len(os.listdir(f'MySprite/{animation}'))
for i in range(1,num_of_frames):
img = pygame.image.load(f'MySprite/{animation}/{i}.png')
temp_list.append(img)
self.anime.append(temp_list)
self.direction = 1
self.flip = False
self.image = self.anime[self.action][self.frame_index]
self.rect = self.image.get_rect()
# vectors and sprite constants
self.health = 100
self.pos = vec(WIDTH/2, HEIGHT/2)
self.vel_vec = vec(0,0)
self.acc_vec = vec(0,0)
def jump(self):
self.rect.y += 1
hits = pygame.sprite.spritecollide(player_group.sprite, platform_group,False)
self.rect.y -= -1
if hits:
self.vel_vec.y = -15
def screen_edge(self):
if self.pos.x > WIDTH:
self.pos.x = 0
if self.pos.x < 0:
self.pos.x = WIDTH
def get_damage(self,damage_mag):
self.health -= damage_mag
def update(self):
animation_cooldown = 75
self.image = self.anime[self.action][self.frame_index]
if pygame.time.get_ticks() - self.update_time >= animation_cooldown:
self.update_time = pygame.time.get_ticks()
self.frame_index += 1
if self.frame_index >= len(self.anime[self.action]):
self.frame_index = 0
if self.shoot_cooldown > 0:
self.shoot_cooldown -= 1
def update_action(self,new_action):
if new_action != self.action:
self.action = new_action
self.frame_index = 0
self.update_time = pygame.time.get_ticks()
def move(self,moving_left,moving_right):
self.acc_vec = vec(0,acceleration)
if moving_left:
self.acc_vec.x = -(acceleration)
self.direction = 1
self.flip = False
if moving_right:
self.acc_vec.x = acceleration
self.direction = -1
self.flip = True
self.acc_vec.x += self.vel_vec.x * friction
self.vel_vec += self.acc_vec
self.pos += self.vel_vec + 0.5 * self.acc_vec
self.rect.midbottom = self.pos
hits = pygame.sprite.spritecollide(player_group.sprite, platform_group,False)
if hits:
self.pos.y = hits[0].rect.top
self.vel_vec.y = 0
def draw(self):
screen.blit(pygame.transform.flip(self.image,self.flip,False),self.rect)
class Platform(pygame.sprite.Sprite):
def __init__(self,x,y,w,h):
super().__init__()
self.image = pygame.Surface((w,h))
self.image.fill(platform_color)
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
class Hostiles(pygame.sprite.Sprite):
def __init__(self,x_pos,y_pos,speed):
super(Hostiles,self).__init__()
self.images = []
self.images.append(pygame.image.load('MySprite/images/go_1.png'))
self.images.append(pygame.image.load('MySprite/images/go_2.png'))
self.images.append(pygame.image.load('MySprite/images/go_3.png'))
self.images.append(pygame.image.load('MySprite/images/go_4.png'))
self.images.append(pygame.image.load('MySprite/images/go_5.png'))
self.images.append(pygame.image.load('MySprite/images/go_6.png'))
self.images.append(pygame.image.load('MySprite/images/go_7.png'))
self.images.append(pygame.image.load('MySprite/images/go_8.png'))
self.images.append(pygame.image.load('MySprite/images/go_9.png'))
self.images.append(pygame.image.load('MySprite/images/go_10.png'))
self.index = 0
self.image = self.images[self.index]
self.rect = self.image.get_rect(center = (x_pos,y_pos))
self.speed = speed
def update(self):
self.index += 1
if self.index >= len(self.images):
self.index = 0
self.image = self.images[self.index]
self.rect.centerx += self.speed
if self.rect.centerx >= 1350 or self.rect.centerx <= -50:
self.kill()
class Hostiles2(pygame.sprite.Sprite):
def __init__(self,x_pos,y_pos,speed):
super(Hostiles2,self).__init__()
self.images2 = []
self.images2.append(pygame.image.load('MySprite/images2/go_1.png'))
self.images2.append(pygame.image.load('MySprite/images2/go_2.png'))
self.images2.append(pygame.image.load('MySprite/images2/go_3.png'))
self.images2.append(pygame.image.load('MySprite/images2/go_4.png'))
self.images2.append(pygame.image.load('MySprite/images2/go_5.png'))
self.images2.append(pygame.image.load('MySprite/images2/go_6.png'))
self.images2.append(pygame.image.load('MySprite/images2/go_7.png'))
self.images2.append(pygame.image.load('MySprite/images2/go_8.png'))
self.images2.append(pygame.image.load('MySprite/images2/go_9.png'))
self.images2.append(pygame.image.load('MySprite/images2/go_10.png'))
self.index = 0
self.image = self.images2[self.index]
self.rect = self.image.get_rect(center = (x_pos,y_pos))
self.speed = speed
def update(self):
self.index += 1
if self.index >= len(self.images2):
self.index = 0
self.image = self.images2[self.index]
self.rect.centerx += self.speed
if self.rect.centerx >= 1350 or self.rect.centerx <= -50:
self.kill()
class Bullets(pygame.sprite.Sprite):
def __init__(self,x,y,direction):
super().__init__()
self.speed = 10
self.image = bullet_img
self.rect = self.image.get_rect(center = (x,y))
self.direction = direction
def update(self):
self.rect.x -= (self.direction * self.speed)
if self.rect.left >= WIDTH or self.rect.right <= 0:
self.kill()
screen.blit(self.image,self.rect)
# Functions
def make_text(font_type,font_size,text,color,position):
font = pygame.font.Font(font_type, font_size)
title = font.render(text,True,(color))
title_rect = title.get_rect(center = (position))
screen.blit(title,title_rect)
def main_game():
pygame.draw.rect(screen,(255,0,0),(22,20,200,10))
pygame.draw.rect(screen,platform_color,(22,20,2 * player_group.sprite.health,10))
screen.blit(heart,(0,2))
bullet_group.draw(screen)
player.draw()
hostiles_group.draw(screen)
platform_group.draw(screen)
bullet_group.update()
player_group.update()
hostiles_group.update()
player_group.update()
player.screen_edge()
if shoot:
if player.shoot_cooldown == 0:
bullet = Bullets(player.rect.centerx - (0.6 * player.direction * player.rect.size[0]),player.rect.centery,player.direction)
bullet_group.add(bullet)
player.shoot_cooldown = 40
if moving_left or moving_right:
player.update_action(1)
else:
player.update_action(0)
player.move(moving_left,moving_right)
if pygame.sprite.spritecollide(player_group.sprite,hostiles_group,True):
player_group.sprite.get_damage(10)
pygame.sprite.groupcollide(hostiles_group, bullet_group,True,True)
return 2
def game_over():
screen.fill((0,0,0))
text = gamefont.render("GAME OVER",True,(255,255,255))
text_rect = text.get_rect(center = (653,243))
screen.blit(text,text_rect)
scoresurface = gamefont.render(f"Score: {score}",True,(255,255,255))
score_rect = scoresurface.get_rect(center = (653,283))
screen.blit(scoresurface,score_rect)
# Creating window
screen = pygame.display.set_mode((WIDTH,HEIGHT))
pygame.display.set_caption("game name")
clock = pygame.time.Clock()
# Groups and objects
gamefont = pygame.font.Font('Chernobyl.ttf',40)
player = Player()
platform = Platform(0,HEIGHT-96,WIDTH,100)
platform_group = pygame.sprite.GroupSingle()
platform_group.add(platform)
player_group = pygame.sprite.GroupSingle()
player_group.add(player)
hostiles_group = pygame.sprite.Group()
hostile_event = pygame.USEREVENT
pygame.time.set_timer(hostile_event,300)
bullet_group = pygame.sprite.Group()
pygame.mouse.set_visible(True)
sky = pygame.image.load('SkyNight.png')
wallpaper = pygame.image.load('GamePlatform.png')
heart = pygame.image.load('Heart.png')
# Game loop
running = True
while running:
# Events (Inputs)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == hostile_event:
random_xpos = [-40,-20]
random_xpos2 = [1340,1360]
random_hs = [-2,2]
hostile_left = Hostiles2(random.choice(random_xpos),400,random.choice(random_hs))
hostile_right = Hostiles(random.choice(random_xpos2),400,random.choice(random_hs))
hostiles_group.add(hostile_left,hostile_right)
if event.type == pygame.MOUSEBUTTONDOWN and player_group.sprite.health <= 0:
player_group.sprite.health = 100
hostiles_group.empty()
score = 0
import MainMenu
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
moving_left = True
if event.key == pygame.K_RIGHT:
moving_right = True
if event.key == pygame.K_q:
shoot = True
if event.key == pygame.K_ESCAPE:
running = False
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT:
moving_left = False
if event.key == pygame.K_RIGHT:
moving_right = False
if event.key == pygame.K_q:
shoot = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
player_group.sprite.jump()
if player_group.sprite.health > 0:
score += main_game()
print (score)
else:
game_over()
pygame.display.update()
screen.blit(sky,FULL_SCREEN)
screen.blit(wallpaper,FULL_SCREEN)
programIcon = pygame.image.load('icon.png')
pygame.display.set_icon(programIcon)
clock.tick(FPS_INGAME)
and this is all the main screen / main menu .py file:
import pygame,sys
pygame.init()
screen = pygame.display.set_mode((1306,526))
clock = pygame.time.Clock()
pygame.mouse.set_visible(True)
screen_home = pygame.image.load('HomeScreen.png')
def make_text(font_type,font_size,text,color,position):
font = pygame.font.Font(font_type, font_size)
title = font.render(text,True,(color))
title_rect = title.get_rect(center = (position))
screen.blit(title,title_rect)
while True:
font1 = pygame.font.Font('Starjedi.ttf',60)
game1 = font1.render("Play",True,(255,255,255))
game1_rect = game1.get_rect(center = (640,300))
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.MOUSEBUTTONDOWN:
if game1_rect.collidepoint(event.pos):
import MainGame.py
screen.blit(screen_home,(0,0))
screen.blit(game1,game1_rect)
make_text('Chernobyl.ttf',70,"Title Here",(255,255,255),(315,80))
pygame.display.update()
clock.tick(45)
when I run the main menu I get the Home Screen I made, then I click on the on my display screen and it imports the game script and the game starts, when my health reaches 0 and I click on the screen to quit the game loop, it takes me back to the main menu which is exactly what I wanted,however, when I press play again to go back to the game it doesn't work it gives me an error:
ModuleNotFoundError: No module named 'MainGame.py'; 'MainGame' is not a package
I know the code is a mess I'm still new at this I'm sorry if my question wasn't clear enough, any help would be appreciated!
Ok, now that I see your code I can see you have a big problem using import:
You use it like this:
import MainGame.py
Assume the file you created is MainGame.py you supposed to import it this way:
import MainGame
Same goes to
import MainMenu.py
And that's might be the problem, though if you still have an issue, so instead of:
in the game, this is part of the main game loop:
Please copy all of the code, in both files, and write the name of each file next to the code.
This question already has answers here:
Pygame doesn't let me use float for rect.move, but I need it
(2 answers)
Simple drag physics, acting differently when moving left or right [duplicate]
(1 answer)
Closed 2 years ago.
Basically I am working on a simple platformer and I have all of the basics like the gravity, acceleration, and platforms, but for some reason the character will decelerate going right, but when it goes left it will continue moving slowly instead of stopping. I even printed the value of my variable "changeX" to see what was going on, and it showed me the values I that should be happening rather than what was displayed. Sorry my comments are very limited in their helpfulness. The code regarding variables rect.x , changeX, and accelX are likely the most relevant.
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
BLUE = (50, 50, 255)
# Screen dimensions
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600
COLOR = BLUE
#Top Speed
tSpeedX = 7
tSpeedY = 20
#gravity constant
gConstant = 1
#acceleration X variable
accelX = 0
#acceleration Y variable
accelY = 0
#whether you can jump or not
jumpB = True
class player(pygame.sprite.Sprite):
def __init__(self, x, y):
super().__init__()
#iniatilized values for rect
self.image = pygame.Surface([50, 50])
self.image.fill(COLOR)
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
self.changeX = 0
self.changeY = 0
self.walls = None
#the velocity function. X and Y values are assigned based on the accelX
#and Y constants and added to the points of the rectangle
def velocity(self,x,y):
#change in speed
self.changeX += x
self.changeY += y
if abs(self.changeX) >= tSpeedX:
self.changeX = self.changeX/abs(self.changeX) * tSpeedX
if abs(self.changeY) >= tSpeedY:
self.changeY = self.changeY/abs(self.changeY) * tSpeedY
#standard update function. Will update rectangles position and deaccelerate it if no key held
def jump(self,y):
self.changeY = y
def update(self):
if accelX == 0:
self.changeX *= 0.92
if accelY == 0:
self.changeY *= .95
self.rect.x += self.changeX
print(self.changeX)
block_hit_list = pygame.sprite.spritecollide(self, self.walls, False)
for block in block_hit_list:
if self.changeX > 0:
self.rect.right = block.rect.left
else:
self.rect.left = block.rect.right
self.rect.y += self.changeY + (9*gConstant)
block_hit_list = pygame.sprite.spritecollide(self, self.walls, False)
for block in block_hit_list:
if self.changeY >= -5:
global jumpB
jumpB = True
COLOR = WHITE
self.rect.bottom = block.rect.top
else:
self.rect.top = block.rect.bottom
class wall(pygame.sprite.Sprite):
def __init__(self, sx, sy,px,py):
super().__init__()
#iniatilized values for walls
collision = False
self.image = pygame.Surface([sx, sy])
self.image.fill(WHITE)
self.rect = self.image.get_rect()
self.rect.x = px
self.rect.y = py
pygame.init()
screen = pygame.display.set_mode([SCREEN_WIDTH, SCREEN_HEIGHT])
spriteList = pygame.sprite.Group()
wallList = pygame.sprite.Group()
Player = player(100,100)
spriteList.add(Player)
Wall1 = wall(1000, 30, 0, 400)
Wall2 = wall(100, 30, 150, 350)
wallList.add(Wall2)
spriteList.add(Wall2)
wallList.add(Wall1)
spriteList.add(Wall1)
Player.walls = wallList
clock = pygame.time.Clock()
#Allows program to exit
quit = False
while not quit:
for event in pygame.event.get():
if event.type == pygame.QUIT:
quit = True
#Sets accel values
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
accelX = -.25
if event.key == pygame.K_RIGHT:
accelX = .25
if event.key == pygame.K_UP and jumpB == True:
Player.jump(-20)
jumpB = False
COLOR = BLUE
if event.key == pygame.K_DOWN:
accelY = .25
#reverses accel values to allow for deaccleration
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT:
accelX = 0
if event.key == pygame.K_RIGHT:
accelX = 0
if event.key == pygame.K_UP:
accelY = 0
if event.key == pygame.K_DOWN:
accelY = 0
#calls function to move rectangle
Player.velocity(accelX, accelY)
spriteList.update()
screen.fill(BLACK)
spriteList.draw(screen)
pygame.display.flip()
clock.tick(60)
I have been using this code from this tutorial https://opensource.com/article/18/5/pygame-enemy but I couldn't add more enemies simply by using
enemy = Enemy(40,100,'spr.png')# spawn enemy
enemy_list = pygame.sprite.Group() # create enemy group
enemy_list.add(enemy) # add enemy to group
The original images are from here https://opengameart.org/sites/default/files/opp2_sprites.zip
but I have separated in imgur for easy explanation:
content folder images:
yeti.png: https://imgur.com/GNNcU6z
stage.png: https://imgur.com/YyiEJ0q
and the image of the second enemy (sprit) that I wanted to put
spr.png: https://imgur.com/1fYXa7Y
I tried using the solution of this similar question How do I add enemies in pygame?, but just got errors or no results.
My code:
import pygame
import sys
import os
'''
Objects
'''
class Enemy(pygame.sprite.Sprite):
'''
Spawn an enemy
'''
def __init__(self, x, y, img):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load(os.path.join('images', img))
#self.image.convert_alpha()
#self.image.set_colorkey(ALPHA)
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
self.counter = 0
def move(self):
'''
enemy movement
'''
distance = 20
speed = 8
if self.counter >= 0 and self.counter <= distance:
self.rect.x += speed
elif self.counter >= distance and self.counter <= distance * 2:
self.rect.x -= speed
else:
self.counter = 0
self.counter += 1
class Level():
def bad(lvl,eloc):
if lvl == 1:
enemy = Enemy(eloc[0],eloc[1],'yeti.png') # spawn enemy
enemy_list = pygame.sprite.Group() # create enemy group
enemy_list.add(enemy) # add enemy to group
if lvl == 2:
print("Level " + str(lvl) )
return enemy_list
class Player(pygame.sprite.Sprite):
'''
Spawn a player
'''
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.movex = 0
self.movey = 0
self.frame = 0
self.health = 10
self.frame = 0
self.images = []
for i in range(1, 5):
img = pygame.image.load(
os.path.join('images', 'hero' + str(i) + '.png')).convert()
img.convert_alpha()
img.set_colorkey(ALPHA)
self.images.append(img)
self.image = self.images[0]
self.rect = self.image.get_rect()
def control(self, x, y):
'''
control player movement
'''
self.movex += x
self.movey += y
def update(self):
'''
Update sprite position
'''
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 > 3 * ani:
self.frame = 0
self.image = self.images[self.frame // ani]
# collisions
enemy_hit_list = pygame.sprite.spritecollide(self, enemy_list, False)
for enemy in enemy_hit_list:
self.health -= 1
print(self.health)
# moving right
if self.movex > 0:
self.frame += 1
if self.frame > 3 * ani:
self.frame = 0
self.image = self.images[(self.frame // ani)]
'''
Setup
'''
worldx = 560
worldy = 520
fps = 40 # frame rate
ani = 4 # animation cycles
clock = pygame.time.Clock()
pygame.init()
main = True
BLUE = (25, 25, 200)
BLACK = (23, 23, 23)
WHITE = (254, 254, 254)
ALPHA = (0, 255, 0)
world = pygame.display.set_mode([worldx, worldy])
backdrop = pygame.image.load(os.path.join('images', 'stage.png')).convert()
backdropbox = world.get_rect()
player = Player() # spawn player
player.rect.x = 0
player.rect.y = 0
player_list = pygame.sprite.Group()
player_list.add(player)
steps = 10 # how fast to move
eloc = []
eloc = [200,20]
enemy_list = Level.bad( 1, eloc )
'''
Main loop
'''
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_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 == ord('q'):
pygame.quit()
sys.exit()
main = False
# world.fill(BLACK)
world.blit(backdrop, backdropbox)
player.update()
player_list.draw(world) #refresh player position
enemy_list.draw(world)
for e in enemy_list:
e.move()
pygame.display.flip()
clock.tick(fps)
There are a number of issues to pay attention on your code.
Take a look to Level class. You need to use self in your class to refer to the class functions and variables. I have added a second function to add a second enemy (spr.png), therefore I put enemy_list outside the function, at class level, so it can be accessed by both functions.
class Level:
def __init__(self):
self.enemy_list = pygame.sprite.Group() # create enemy group
def bad_1(self, lvl, eloc):
if lvl == 1:
enemy = Enemy(eloc[0],eloc[1],'yeti.png') # spawn enemy
self.enemy_list.add(enemy) # add enemy to group
if lvl == 2:
print("Level " + str(lvl) )
return self.enemy_list
def bad_2(self, lvl, eloc):
if lvl == 1:
enemy = Enemy(eloc[0],eloc[1],'spr.png') # spawn enemy
self.enemy_list.add(enemy) # add enemy to group
if lvl == 2:
print("Level " + str(lvl) )
return self.enemy_list
I also changed this part. First, you need to instantiate the class (see l = Level()), then you can use its functions and variables. Note you were invoking Level.bad() just once, so there was just one enemy!
steps = 10 # how fast to move
l = Level()
eloc = [200,20]
enemy_list = l.bad_1(1, eloc)
eloc = [100,10]
enemy_list = l.bad_2(1, eloc)
My code is quite a "hack", something quick and easy-to-see, but it works now...
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 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