Pygame problem : my player image don't move with scroll - python

Firts I am french so excuse-me for my english. I have recently discoverd pygame and I love that so decided to create a rpg on pygame and... I have a little problem : with many, many difficulty I made a scrolling system on my pygame's rpg I evn do a system how make sure player's image gets back when he go up, puts himself in profile ...
BUT (a big but) my player's image don't move, the scrolling, move and the player's rect also, I don't know I can solve that so please help me !!!!! The main.py file :
from game import Game
from level import *
pygame.init()
lvl = Level()
screen = pygame.display.set_mode((1024, 768))
pygame.display.set_caption("RPG")
game = Game()
cam = Camera(1024, 768)
running = True
lvl.generer()
print(game.player.rect)
clock = pygame.time.Clock()
while running:
cam.update(game.player)
#print(cam.rect.topleft)
if game.pressed.get(pygame.K_RIGHT) and game.player.rect.x + game.player.rect.width < 1080:
game.player.move_right()
lvl.afficher(screen, 0, 0, cam.x, cam.y)
#print(game.player.rect.x)
elif game.pressed.get(pygame.K_LEFT) and game.player.rect.x > 0:
game.player.move_left()
lvl.afficher(screen, 0, 0, cam.x, cam.y)
#print(game.player.rect.x)
elif game.pressed.get(pygame.K_DOWN):
game.player.move_down()
lvl.afficher(screen, 0, 0, cam.x, cam.y)
#screen.scroll(0, -game.player.velocity)
#print(game.player.rect.y)
elif game.pressed.get(pygame.K_UP):
game.player.move_up()
lvl.afficher(screen, 0, 0, cam.x, cam.y)
#screen.scroll(0, game.player.velocity)
#print(game.player.rect.y)
#print(cam.rect.x, cam.rect.y)
#print(cam.rect)
screen.blit(game.player.image, game.player.rect)
print(game.player.rect)
pygame.display.flip()
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
pygame.quit()
elif event.type == pygame.KEYDOWN:
game.pressed[event.key] = True
elif event.type == pygame.KEYUP:
game.pressed[event.key] = False```
the player.py class :
```import pygame
class Player(pygame.sprite.Sprite):
def __init__(self, game):
super(Player, self).__init__()
self.game = game
self.health = 100
self.maxHealth = 100
self.attack = 10
self.velocity = 10
self.dimension = (64, 88)
self.image = pygame.image.load("assets/player/player_face/player_face.png")
self.original_image = pygame.image.load("assets/player/player_face/player_face.png")
self.image = pygame.transform.scale(self.image, self.dimension)
self.rect = self.image.get_rect()
self.rect.x = 512
self.rect.y = 384
self.face = [pygame.image.load("assets/player/player_face/player/sprite_00.png"), pygame.image.load("assets/player/player_face/player/sprite_01.png"), pygame.image.load("assets/player/player_face/player/sprite_02.png"), pygame.image.load("assets/player/player_face/player/sprite_03.png"), pygame.image.load("assets/player/player_face/player/sprite_04.png"), pygame.image.load("assets/player/player_face/player/sprite_05.png"), pygame.image.load("assets/player/player_face/player/sprite_06.png"), pygame.image.load("assets/player/player_face/player/sprite_07.png"), pygame.image.load("assets/player/player_face/player/sprite_08.png"), pygame.image.load("assets/player/player_face/player/sprite_09.png")]
def move_right(self):
self.rect.x += self.velocity
self.image = pygame.image.load("assets/player/player_profileLeft/player_profile_left.png")
self.image = pygame.transform.scale(self.image, self.dimension)
def move_left(self):
self.rect.x -= self.velocity
self.image = pygame.image.load("assets/player/player_profileRight/player_profile_right.png")
self.image = pygame.transform.scale(self.image, self.dimension)
def move_down(self):
self.rect.y += self.velocity
#self.image = pygame.image.load("assets/player/player_face/player_face.png")
#self.image = pygame.transform.scale(self.image, self.dimension)
i = 0
for elt in self.face:
self.image = self.face[i]
print("lol")
self.image = pygame.transform.scale(self.image, self.dimension)
i += 1
def move_up(self):
self.rect.y -= self.velocity
self.image = pygame.image.load("assets/player/player_back/player_dos.png")
self.image = pygame.transform.scale(self.image, self.dimension)
the level.py class :
from pygame.locals import *
from player import *
class Camera:
def __init__(self, widht, height):
self.rect = pygame.Rect(0, 0, widht, height)
self.widht = widht
self.height = height
self.topleft = list(self.rect.topleft)
self.x = self.topleft[0]
self.y = self.topleft[1]
def update(self, target):
self.rect.y = -target.rect.y + int(769 / 2)
self.rect.x = -target.rect.x + int(1024 / 2)
self.topleft = list(self.rect.topleft)
self.x = self.topleft[0]
self.y = self.topleft[1]
self.rect = pygame.Rect(self.rect.x, self.rect.y, self.widht, self.height)
#self.rect.topleft_x = self.rect.topleft(0)
#self.coo = (0, 0)
class Level:
def __init__(self):
self.structure = 0
def generer(self):
with open("niveau.txt", "r") as fichier:
structure_niveau = []
for ligne in fichier:
ligne_niveau = []
for sprite in ligne:
if sprite != '\n':
ligne_niveau.append(sprite)
structure_niveau.append(ligne_niveau)
self.structure = structure_niveau
def afficher(self, fenetre, x, y, camLeftX, camLeftY):
tailleSprite = 64
#Camera.__init__(self, x, y)
grass = pygame.image.load("assets/bloc/grass.png").convert_alpha()
tree = pygame.image.load("assets/bloc/tree_grass.png").convert_alpha()
no_texture = pygame.image.load("assets/bloc/no_texture.png")
num_ligne = 0
for ligne in self.structure:
num_case = 0
for sprite in ligne:
x = num_case * tailleSprite - camLeftX
y = num_ligne * tailleSprite - camLeftY
if sprite == 'G':
fenetre.blit(grass, (x, y))
elif sprite == 'T':
fenetre.blit(tree, (x, y))
#print(self.x, self.y)
else:
fenetre.blit(no_texture, (x, y))
num_case += 1
num_ligne += 1```

Ok I just found the solution but It's making an other problem I'll ask the question on a other post. At x = num_case * tailleSprite - camLeftX and y = num_ligne * tailleSprite - camLeftY on level.py just replace the - by a +

Related

Rotate a rectangle over waves

I am trying to move a rectangle over the waves,trying to simulate a boat sailing.
For that, I rotate the rectangle using the height of the drawn lines and calculating the angle they form with the rectangle.
However, for some reason, in some points of the waves the rectangle is flickering.
The code shows the problem.
import sys
import math
import pygame
from pygame.locals import *
pygame.init()
SCREEN_WIDTH = 900
SCREEN_HEIGHT = 900
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
clock = pygame.time.Clock()
BLUE = (0, 103, 247)
RED = (255,0,0)
watter_levels = [0 for _ in range(SCREEN_WIDTH)]
def draw_water(surface, dy):
amplitude = 35
global watter_levels
for x in range(SCREEN_WIDTH):
y = int(math.sin((x)*(0.01)) * amplitude + dy)
watter_levels[x] = y
pygame.draw.aaline(surface,BLUE,(x,y),(x,y))
def get_water_level(index):
if index <= 0:
return watter_levels[0]
if index >= SCREEN_WIDTH:
return watter_levels[-1]
return watter_levels[index]
font = pygame.font.Font(None,30)
def debug(info,x=10,y=10):
display_surf = pygame.display.get_surface()
debug_surface = font.render(str(info),True,'White')
debug_rect = debug_surface.get_rect(topleft=(x,y))
pygame.draw.rect(display_surf,'Black',debug_rect)
display_surf.blit(debug_surface,debug_rect)
class Ship(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.image = pygame.Surface((80,80),pygame.SRCALPHA)
self.image.fill('red')
self.rect = self.image.get_rect(topleft=(0,0))
self.copy_img = self.image.copy()
self.move = pygame.math.Vector2(0,0)
self.copy_img = self.image.copy()
self.velocity = 8
def rotate(self, angle):
self.image = pygame.transform.rotate(self.copy_img, int(angle))
self.rect = self.image.get_rect(center=(self.rect.center))
def update(self):
self.get_input()
self.rect.bottom = get_water_level(self.rect.centerx)
left_y = get_water_level(self.rect.left)
right_y = get_water_level(self.rect.right)
angle = 180*math.atan2(left_y-right_y,self.image.get_width())/math.pi
debug("angle: "+str(int(angle)))
print(self.rect.left,self.rect.right)
self.rotate(angle)
def replicate(self):
if self.rect.left == 363:
return
self.rect.x += 1
def get_input(self):
self.replicate()
# keys = pygame.key.get_pressed()
# if keys[K_LEFT]:
# self.move.x = -self.velocity
# elif keys[K_RIGHT]:
# self.move.x = self.velocity
# else:
# self.move.x = 0
# if keys[K_UP]:
# self.move.y = -self.velocity
# elif keys[K_DOWN]:
# self.move.y = self.velocity
# else:
# self.move.y = 0
# self.rect.x += self.move.x
# self.rect.y += self.move.y
# if self.rect.left <= 0:
# self.rect.left = 0
# if self.rect.right >= SCREEN_WIDTH:
# self.rect.right = SCREEN_WIDTH
ship_sprite = pygame.sprite.GroupSingle()
ship_sprite.add(Ship())
while True:
screen.fill((200,210,255,0))
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
ship_sprite.update()
ship_sprite.draw(screen)
draw_water(screen,SCREEN_HEIGHT-300)
clock.tick(60)
pygame.display.update()
It's about accuracy. You can improve the result by storing the water level with floating point precision:
def draw_water(surface, dy):
amplitude = 35
global watter_levels
for x in range(SCREEN_WIDTH):
y = math.sin(x * 0.01) * amplitude + dy
watter_levels[x] = y
pygame.draw.aaline(surface, BLUE, (x, round(y)), (x, round(y)))
Furthermore you have to get the left and right from the "unrotated" rectangle:
class Ship(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.image = pygame.Surface((80,80),pygame.SRCALPHA)
self.image.fill('red')
self.rect = self.image.get_rect(topleft = (0, 0))
self.copy_img = self.image.copy()
self.copy_rect = pygame.Rect(self.rect)
self.move = pygame.math.Vector2(0, 0)
self.velocity = 8
def rotate(self, angle):
self.image = pygame.transform.rotate(self.copy_img, round(angle))
self.rect = self.image.get_rect(center = (self.copy_rect.center))
def update(self):
self.get_input()
self.copy_rect.bottom = round(get_water_level(self.copy_rect.centerx))
left_y = get_water_level(self.copy_rect.left)
right_y = get_water_level(self.copy_rect.right)
angle = math.degrees(math.atan2(left_y-right_y, self.copy_img.get_width()))
debug("angle: " + str(round(angle)))
print(self.copy_rect.left, self.copy_rect.right)
self.rotate(angle)
def replicate(self):
if self.copy_rect.left == 363:
return
self.copy_rect.x += 1

Unable to close pygame window when try again button clicked

I am making a spaceship game where you control a spaceship and fire bullets to destroy enemy spaceships. When you click the try again button when you lose, you should be able to both replay and close the game. However, even though I was able to play multiply times, I wasn't able to close the window. I think this has something to do with the if statement that checks if the try again button is clicked. Or maybe it has something to do with something else. How can I fix it so I can close the window at all times?
This is my current code:
import pygame
from pygame.locals import *
from random import randint, choice
from tools import *
pygame.init()
pygame.font.init()
SCREEN_X = 800
SCREEN_Y = 500
CENTER_POS = (400, 225)
screen = pygame.display.set_mode((SCREEN_X, SCREEN_Y))
class Spaceship(pygame.sprite.Sprite):
"""A spaceship object. Used for the player."""
def __init__(self, s, x, y):
pygame.sprite.Sprite.__init__(self)
self.screen = s
self.x, self.y = x, y
self.image = pygame.image.load("spaceship.png")
self.image = pygame.transform.scale(self.image, (175, 175))
self.rect = self.image.get_rect()
self.rect.center = (self.x, self.y)
def update(self):
"""Updates the spaceship rect"""
self.rect.center = (self.x, self.y)
class Bullet(pygame.sprite.Sprite):
"""A bullet object. Appears when the player clicks."""
def __init__(self, s, x, y):
pygame.sprite.Sprite.__init__(self)
self.screen = s
self.x, self.y = x, y
self.image = pygame.image.load("bullet.png")
self.image = pygame.transform.scale(self.image, (100, 100))
self.rect = self.image.get_rect()
self.rect.center = (self.x, self.y)
def update(self):
"""Let's the bullet move upward."""
self.y -= 5
self.rect.center = (self.x, self.y)
if self.y < 0:
self.kill()
class Enemy(pygame.sprite.Sprite):
"""An enemy object. The player's job is to destroy enemies."""
def __init__(self, s, x, y, t):
pygame.sprite.Sprite.__init__(self)
self.type = t
self.screen, self.x, self.y = s, x, y
self.image = pygame.image.load(get_enemy_image()[self.type])
# There is an if statement because the
# N1 Galaxy Fighter and M7 Comet Glider need different sizes
if self.type == "N1 Galaxy Fighter":
self.image = pygame.transform.scale(self.image, (235, 215))
elif self.type == "M7 Comet Glider":
self.image = pygame.transform.scale(self.image, (155, 215))
self.rect = self.image.get_rect()
self.rect = self.image.get_rect()
self.rect.center = (self.x, self.y)
self.score_given = get_enemy_given_score()[self.type]
def update(self):
if self.y < 0:
self.kill()
self.y += 3
self.rect.center = (self.x, self.y)
class GameOverBackground(pygame.sprite.Sprite):
"""The game over background object."""
def __init__(self, s, x, y, size=(100, 100)):
pygame.sprite.Sprite.__init__(self)
self.screen, self.x, self.y = s, x, y
self.size = size
self.image = pygame.image.load("Game_Over.jpg")
self.image = pygame.transform.scale(self.image, self.size)
self.rect = self.image.get_rect()
def blitme(self):
"""Blits the game over image on the screen"""
self.screen.blit(self.image, self.rect)
class Coin(pygame.sprite.Sprite):
"""A coin object."""
def __init__(self, pos=(0, 0), size=(100, 100)):
pygame.sprite.Sprite.__init__(self)
self.x, self.y = pos[0], pos[1]
self.size = size
self.image = pygame.image.load("coin.png")
self.image = pygame.transform.scale(self.image, self.size)
self.rect = self.image.get_rect()
self.rect.center = (self.x, self.y)
def update(self):
"""Updates the coin rect"""
self.rect.center = (self.x, self.y)
class StartButton(pygame.sprite.Sprite):
def __init__(self, s, x, y, size=None):
pygame.sprite.Sprite.__init__(self)
self.screen = s
self.x = x
self.y = y
self.image = pygame.image.load("start_button.png")
if size is not None:
self.image = pygame.transform.scale(self.image, size)
self.rect = self.image.get_rect()
self.rect.center = (self.x, self.y)
def blitme(self):
self.screen.blit(self.image, self.rect)
class TryAgainButton(pygame.sprite.Sprite):
def __init__(self, s, x, y, size=None):
pygame.sprite.Sprite.__init__(self)
self.screen = s
self.x = x
self.y = y
self.image = pygame.image.load("try_again.png")
if size is not None:
self.image = pygame.transform.scale(self.image, size)
self.rect = self.image.get_rect()
self.rect.center = (self.x, self.y)
def blitme(self):
self.screen.blit(self.image, self.rect)
def main():
bg = GameOverBackground(screen, 0, 0, size=(800, 500))
spaceship = Spaceship(screen, 400, 400)
start_button = StartButton(screen, CENTER_POS[0], CENTER_POS[1], size=(300, 195))
button_rect = start_button.image.get_rect(topleft=(start_button.x, start_button.y))
game_started = False
try_again_button = TryAgainButton(screen, CENTER_POS[0], CENTER_POS[1]+215, size=(300, 195))
button_rect_2 = try_again_button.image.get_rect(topleft=(try_again_button.x, try_again_button.y))
try_again = False
bullets = pygame.sprite.Group()
enemies = pygame.sprite.Group()
coins = pygame.sprite.Group()
clock = pygame.time.Clock()
enemy_interval = 2000
enemy_event = pygame.USEREVENT + 1
pygame.time.set_timer(enemy_event, enemy_interval)
coin_interval = 3500
coin_event = pygame.USEREVENT + 1
pygame.time.set_timer(coin_event, coin_interval)
score = 0
lives = 3
with open("high_score.txt", "r") as file:
highscore = file.read()
font = pygame.font.SysFont("Arial", 30)
score_text_surface = font.render("Score: {:,}".format(score), True, (0, 0, 0))
lives_text_surface = font.render("HP: %s" % lives, True, (0, 0, 0))
high_score_text_surface = font.render("High Score: %s" % highscore, True, (0, 0, 0))
spaceship_collided = False
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == MOUSEBUTTONDOWN:
if not game_started:
if button_rect.collidepoint(event.pos):
game_started = True
if game_started is True and button_rect_2.collidepoint(event.pos):
try_again = True
if game_started and event.type == MOUSEBUTTONDOWN:
bullet = Bullet(screen, spaceship.x, spaceship.y - 20)
bullets.add(bullet)
if game_started and event.type == enemy_event and not lives <= 0:
enemy = Enemy(screen, randint(-100, 725), 0, choice(["N1 Galaxy Fighter", "M7 Comet Glider"]))
enemies.add(enemy)
if game_started and event.type == coin_event and not lives <= 0:
if len(coins) < 100:
coins.add(Coin((randint(-125, 750), randint(-200, 400))))
screen.fill((255, 255, 255)) # DO NOT DRAW ANYTHING IN FRONT OF THIS LINE, I'M WARNING YOU
if not game_started:
start_button.blitme()
if try_again:
main()
if game_started:
bullets.update()
key = pygame.key.get_pressed()
amount = 5
if key[pygame.K_a]:
spaceship.x -= amount
elif key[pygame.K_d]:
spaceship.x += amount
elif key[pygame.K_w]:
spaceship.y -= amount
elif key[pygame.K_s]:
spaceship.y += amount
spaceship.update()
if not lives <= 0:
screen.blit(spaceship.image, spaceship.rect)
if not lives <= 0:
bullets.draw(screen)
enemies.draw(screen)
coins.update()
coins.draw(screen)
for i in enemies:
i.update()
if pygame.sprite.spritecollide(i, bullets, True):
score += i.score_given
i.kill()
if spaceship_collided and lives <= 0:
bg.blitme()
if score > int(highscore):
with open("high_score.txt", "w") as file:
file.write(str(score))
if score >= 99999:
score = 99999
if not lives <= 0:
score_text_surface = font.render("Score: {:,}".format(score), True, (0, 0, 0))
screen.blit(score_text_surface, (590, 0))
lives_text_surface = font.render("HP: %s" % lives, True, (0, 0, 0))
screen.blit(lives_text_surface, (260, 0))
high_score_text_surface = font.render("High Score: %s" % highscore, True, (0, 0, 0))
screen.blit(high_score_text_surface, (360, 0))
if pygame.sprite.spritecollide(spaceship, enemies, dokill=True):
lives -= 1
spaceship_collided = True
if pygame.sprite.spritecollide(spaceship, coins, dokill=True):
score += 10
if lives <= 0:
try_again_button.blitme()
pygame.display.update()
clock.tick(60)
if __name__ == "__main__":
main()
You can't do it like that. Never run the main application loop recursively. The issue is
if try_again:
main()
What you are actually doing is starting a new game within the game in progress. If you want to close the game, you will need to close all games that you have started before. Hence, you have to press close several times.
Instead of calling main recursively, you either have to reset all game states or call main in a loop.
In your particular situation, the later solution is easier to implement. Remove the recursive call but set running = False, return try_again from main and call main while it returns True:
def main():
# [...]
try_again = False
running = True
while running:
# [...]
if try_again:
# main() <---- DELETE
running = False
# [...]
return try_again
if __name__ == "__main__":
keep_running = True
while keep_running:
keep_running = main()

How do I properly implement collision response in Pygame?

I'm trying to program a simple top-down dungeon crawler in Pygame and I've already hit a roadblock in designing my collision response. So far I've programmed player movement, collision detection (only knows when a player hits a wall) and player-to-mouse rotation, the latter of which is disabled to simplify this solution.
I've tried the normal method of moving the character, checking for collision, changing the character's position if needed and then drawing all elements to the screen.
import pygame
from pygame.locals import *
import os
import sys
import math
os.environ["SDL_VIDEO_CENTERED"] = "1"
pygame.init()
pygame.font.init()
clock = pygame.time.Clock()
myfont = pygame.font.SysFont('sourcecodeproblack', 12)
BLACK = [0, 0, 0]
WHITE = [255, 255, 255]
WALLS = [220, 40, 30]
SIZE = [240, 240]
DSIZE = [480, 480]
TSIZE = [720, 720]
dub = False
trip = False
def normal():
global screen
screen = pygame.display.set_mode(SIZE)
pygame.display.set_caption("METAL PACKET")
def full():
global screen
screen = pygame.display.set_mode((SIZE), pygame.FULLSCREEN)
pygame.display.set_caption("METAL PACKET: Fullscreen Edition")
def doubled():
global screen
global window
global res
global invscale
invscale = 1/2
res = DSIZE
window = pygame.display.set_mode(DSIZE)
screen = pygame.Surface(SIZE)
pygame.display.set_caption("METAL PACKET: Double Boogaloo")
def doubledfull():
global screen
global window
global res
global invscale
invscale = 1/2
res = DSIZE
window = pygame.display.set_mode((DSIZE), pygame.FULLSCREEN)
screen = pygame.Surface(SIZE)
pygame.display.set_caption("METAL PACKET: Fullscreen Boogaloo")
def tripled ():
global screen
global window
global res
global invscale
invscale = 1/3
res = TSIZE
window = pygame.display.set_mode(TSIZE)
screen = pygame.Surface(SIZE)
pygame.display.set_caption("METAL PACKET: Trifecta of Resolution")
def tripledfull ():
global screen
global window
global res
global invscale
invscale = 1/3
res = TSIZE
window = pygame.display.set_mode((TSIZE), pygame.FULLSCREEN)
screen = pygame.Surface(SIZE)
pygame.display.set_caption("METAL PACKET: Fullscreen Trifecta Edition")
print("")
print("1: 240 x 240")
print("2: 480 x 480")
print("3: 720 x 720")
print("4: 240 x 240 Fullscreen")
print("5: 480 x 480 Fullscreen")
print("6: 720 x 720 Fullscreen")
print("")
res = input("Choose a video mode. ")
if res == ("1"):
normal()
if res == ("2"):
doubled()
dub = True
if res == ("3"):
tripled()
trip = True
if res == ("4"):
full()
if res == ("5"):
doubledfull()
dub = True
if res == ("6"):
tripledfull()
trip = True
class Walls(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.currentsprite = ()
def draw(self):
self.image = pygame.image.load(self.currentsprite)
screen.blit(self.image, [0, 0])
room1 = Walls()
room1.currentsprite = ("room1.png")
collidelist = pygame.sprite.Group()
class WallColliders(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self, collidelist)
self.rectval = []
def collide(self):
self.rect = (self.rectval)
topwall = WallColliders()
topwall.rectval = [0, 0, 240, 20]
bottomwall = WallColliders()
bottomwall.rectval = [0, 160, 240, 20]
leftwall = WallColliders()
leftwall.rectval = [0, 0, 20, 180]
class Player(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.collide = 0
self.x = 0
self.y = 0
self.speed = 0
self.currentsprite = ("pac.png")
self.image = pygame.image.load(self.currentsprite)
self.rect = self.image.get_rect()
def collidedetect(self):
if pygame.sprite.spritecollideany(player, collidelist):
self.collide = 1
else:
self.collide = 0
def move(self):
key = pygame.key.get_pressed()
if key[K_LEFT] or key[ord("a")]:
self.x -= self.speed
if self.collide == 1:
self.x += self.speed
self.collide = 0
if key[K_RIGHT] or key[ord("d")]:
self.x += self.speed
if self.collide == 1:
self.x -= self.speed
self.collide = 0
if key[K_UP] or key[ord("w")]:
self.y -= self.speed
if self.collide == 1:
self.y += self.speed
self.collide = 0
if key[K_DOWN] or key[ord("s")]:
self.y += self.speed
if self.collide == 1:
self.y -= self.speed
self.collide = 0
if self.collide == 1:
print("collide")
def rotate(self):
pos = pygame.mouse.get_pos()
if dub == True or trip == True:
pos = pos[0] * invscale, pos[1] * invscale
mouse_x, mouse_y = pos
mouse_x, mouse_y = pos
rel_x, rel_y = mouse_x - self.x, mouse_y - self.y
self.angle = (180 / math.pi) * -math.atan2(rel_y, rel_x)
self.rotimage = pygame.transform.rotozoom(self.image, self.angle, 1)
self.rect = self.rotimage.get_rect(center=(self.rect.center))
def monitor(self):
textsurface = myfont.render(str(self.angle), False, (255, 255, 255))
screen.blit(textsurface,(50,210))
def draw(self):
#screen.blit(self.rotimage, [self.x, self.y])
screen.blit(self.image, [self.x, self.y])
self.rect = pygame.Rect(self.x, self.y, 20, 20)
player = Player()
player.x = 29
player.y = 89
player.speed = 3
done = False
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
if event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE:
print("")
print("See you next time.")
pygame.quit()
sys.exit(0)
done = True
screen.fill(BLACK)
room1.draw()
for x in collidelist:
x.collide()
player.collidedetect()
player.move()
#player.rotate()
#player.monitor()
player.draw()
if dub == True or trip == True:
pygame.transform.scale(screen, res, window)
pygame.display.flip()
clock.tick(60)
pygame.quit()
For some reason this will stick the player in the wall unless they press move diagonally instead of moving the player out of the wall and resetting collision. I would greatly appreciate it if someone could read through my code and suggest any improvement, optimisation or solution. Any example code would be great. Thanks.
Don't overcomplicate. When the player is moved, the calculate the new position and update the .rect property of the Player object:
class Player(pygame.sprite.Sprite):
# [...]
def move(self):
key = pygame.key.get_pressed()
if key[K_LEFT] or key[ord("a")]:
self.x -= self.speed
if key[K_RIGHT] or key[ord("d")]:
self.x += self.speed
if key[K_UP] or key[ord("w")]:
self.y -= self.speed
if key[K_DOWN] or key[ord("s")]:
self.y += self.speed
self.updaterect()
def updaterect(self):
self.rect = pygame.Rect(self.x, self.y, 20, 20)
In the main loop:
backup the player position
move the player
check for collision
if there is a collision, then restore the position of the player
while not done:
# [...]
pos = (player.x, player.y)
player.move()
player.collidedetect()
if player.collide:
player.x, player.y = pos
player.updaterect()
player.collide = False
player.draw()
# [...]
Of course this can be done in a method, too:
class Player(pygame.sprite.Sprite):
# [...]
def moveandcollide(self):
pos = (self.x, self.y)
self.move()
self.collidedetect()
if player.collide:
self.x, self.y = pos
self.updaterect()
self.collide = False
while not done:
# [...]
player.moveandcollide()

How do you get sprites to appear within this space invader game?

I am currently making a space invader game, the sprites that I have created are not appearing the only thing that happens when I run the programme is the interpreter says "processed finished with error code 0" in addition I am using the pycharm IDE. Can you help fix this issue?.
import pygame
import sys
from pygame.locals import *
class Launcher(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.image = pygame.image.load('LaserBase.png')
self.rect = self.image.get_rect()
self.rocketXPos = 512
self.rect.x = self.rocketXPos
self.rect.y = 650
def update(self, gametime):
keys = pygame.key.get_pressed()
if keys[pygame.K_RIGHT]:
self.rocketXPos += 4
elif keys[pygame.K_LEFT]:
self.rocketXPos -= 4
self.rect.x = self.rocketXPos
self.rect.y = 650
class Invader(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.image = pygame.image.load('inv12.png')
self.rect = self.image.get_rect()
self.__alienPosX = 0
self.__alienPosY = 0
self.__listPos = 0
self.alienSpeed = 4
self.alienDirection = -1
def setPosX(self, x):
self.__alienPosX = x
self.rect.x = x
def setPosY(self, y):
self.__alienPosY = y
self.rect.y = y
def setListPos(self, pos):
self.__listPos = pos
def update(self, gametime):
self.__alienPosX += self.alienSpeed * self.alienDirection
if self.__alienPosX < 100 + (self.__listPos * 32):
self.alienDirection = +1
self.__alienPosY += 4
elif self.__alienPosX > 924 - ((10 - self.__listPos) * 32) :
self.alienDirection = -1
self.__alienPosY += 4
self.rect.x = self.__alienPosX
self.rect.y = self.__alienPosY
class Missile(pygame.sprite.Sprite):
def __init__(self, xInitialPos, yInitialPos):
super().__init__()
self.image = pygame.image.load('bullet.png')
self.rect = self.image.get_rect()
self.__missilePosY = yInitialPos
self.rect.x = xInitialPos
self.rect.y = self.__missilePosY
def update(self, gametime):
self.__missilePosY -= 4
self.rect.y = self.__missilePosY
class Game:
def __init__(self):
pygame.init()
pygame.key.set_repeat(1, 1)
self.width = 1024
self.height = 768
self.screen = pygame.display.set_mode((self.width, self.height))
self.caption = "Space Invaders!!"
pygame.display.set_caption(self.caption)
self.framerate = 60
self.clock = pygame.time.Clock()
self.starfieldImg = pygame.image.load('Starfield1024x768.png')
self.allsprites = pygame.sprite.Group()
self.launcher = Launcher()
self.allsprites.add(self.launcher)
self.aliens = pygame.sprite.Group()
self.missileFired = None
xPos = 512
for i in range(11):
invader = Invader()
invader.setPosX(xPos)
invader.setPosY(100)
self.allsprites.add(invader)
self.aliens.add(invader)
xPos += 32
def update(self, gametime):
events = pygame.event.get()
for event in events:
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
self.missileFired = Missile(self.launcher.rocketXPos, 650)
self.allsprites.add(self.missileFired)
self.allsprites.update(gametime)
def draw(self):
self.screen.blit(self.starfieldImg, (0, 0))
self.allsprites.draw(self.screen)
pygame.display.flip()
You need endless loop (called "mainloop") to handle events, move/update objects, draw objects on screen.
You could add to Game class
def run(self):
while True:
self.update()
self.draw()
self.clock.tick(self.framerate)
and then use it
g = Game()
g.run()
or
Game().run()
--
BTW: "error code 0" means "program finished without problem".

Drawing images onto Pygame's background or screen

I am writing a game with pygame which involves two player-controlled tanks which go around a brick map with their own health bars and shoot each other with one kind of bullet. From what I can tell, everything else is working, but I am having trouble determining which surface to draw the bricks, tanks, and bullets on: the "background" or the "screen" (the bricks do not change during the game, only the tanks and bullets). I tried drawing everything but the health bars on the background, but that just resulted in a black screen which only displayed the health bars. I then drew everything directly onto the screen and that displays everything correctly at first, but when the tanks move around, the screen doesn't refresh (I get many many tank images overlapping each other as the tank moves) and the bullets do not fire properly as a result. The code is below but the main() method is at the very bottom and that is what is causing errors. The "effects.py" file that is imported at the very top contains just the bullets and "booms" and "bombs" classes which are just special effects but aren't used so far in the main() method so they can be ignored.
from __future__ import print_function, division
import pygame, os, sys
from pygame.locals import *
import random
import effects
from effects import *
import math
GRAD = math.pi / 180
class Brick(pygame.sprite.Sprite):
def __init__(self, pos, image, top, bottom, right, left, bricks):
pygame.sprite.Sprite.__init__(self)
self.rect = image.get_rect(topleft = pos)
self.image = image
self.pos = pos
self.top = top
self.bottom = bottom
self.right = right
self.left = left
self.health = 30
bricks.add(self)
class City(object):
def __init__(self, bricks, level):
self.level = level
self.city = self.level.convert_alpha()
self.brick = pygame.image.load("brick.png").convert_alpha()
self.bricks = bricks
self.x = self.y = 0
collidable = (255, 0, 0, 255)
self.height = self.city.get_height()
self.width = self.city.get_width()
self.vehicle_pos = (0,0)
while self.y < self.height:
color = self.city.get_at((self.x, self.y))
collidable = (255, 0, 0, 255), (0,0,0,255)
top = False
bottom = False
right = False
left = False
if color in collidable:
self.bricks.add(Brick((self.x*30, self.y*30), self.brick, top, bottom, right, left, self.bricks))
print ("brick added!")
print (self.x, self.y)
self.x += 1
if self.x >= self.width:
self.x = 0
self.y += 1
def get_size(self):
return [self.city.get_size()[0]*30, self.city.get_size()[1]*30]
class Tank(pygame.sprite.Sprite):
book = {} # a book of tanks to store all tanks
number = 0 # each tank gets his own number
firekey = (pygame.K_SPACE, pygame.K_RETURN)
forwardkey = (pygame.K_w, pygame.K_i)
backwardkey = (pygame.K_s, pygame.K_k)
tankLeftkey = (pygame.K_a, pygame.K_j)
tankRightkey = (pygame.K_d, pygame.K_l)
color = ((200,200,0), (0,0,200))
def __init__(self, pos, angle, health):
self.number = Tank.number
Tank.number += 1
Tank.book[self.number] = self
pygame.sprite.Sprite.__init__(self)
self.tank_pic = pygame.image.load("tank.png").convert_alpha()
self.image = self.tank_pic
self.image_type = self.tank_pic
self.tank1_pic = pygame.image.load("tank1.png").convert_alpha()
self._image = self.image
self.rect = self.image.get_rect()
self.rect = self.rect.move(pos)
self.tankAngle = angle # tank facing
#---handles controls---#
self.firekey = Tank.firekey[self.number] # main gun
self.forwardkey = Tank.forwardkey[self.number] # move tank
self.backwardkey = Tank.backwardkey[self.number] # reverse tank
self.tankLeftkey = Tank.tankLeftkey[self.number] # rotate tank
self.tankRightkey = Tank.tankRightkey[self.number] # rotat tank
self.health = health
self.alive = True
self.speed = 5
self.angle = angle
self.timer = 3
self.timerstart = 0
self.x, self.y = self.rect.center
self.bullet_s = pygame.mixer.Sound("bullet.wav")
self.bullet_s.set_volume(.25)
def rotate(self):
center = self.rect.center
self.image = pygame.transform.rotozoom(self._image, self.angle, 1.0)
self.rect = self.image.get_rect(center = center)
def update(self, keys, bricks, bullets, booms, bombs):
self.bricks = bricks
self.t = True
self._rect = Rect(self.rect)
self._rect.center = self.x, self.y
self.rotate()
turn_speed = 3
pressedkeys = pygame.key.get_pressed()
if pressedkeys[self.forwardkey]:
self.x += sin(radians(self.angle))*-self.speed
self.y += cos(radians(self.angle))*-self.speed
if pressedkeys[self.backwardkey]:
self.x += sin(radians(self.angle))*self.speed
self.y += cos(radians(self.angle))*self.speed
if pressedkeys[self.tankLeftkey]:
self.angle += turn_speed
if pressedkeys[self.tankRightkey]:
self.angle -= turn_speed
if keys[self.firekey]:
if self.timer >= 3:
self.timer = self.timerstart
self.b_size = "small"
bullets.add(Bullet(self.rect.center, self.angle, self.b_size, "vehicle"))
self.bullet_s.play()
if self.timer < 3:
self.timer += 1
if self.angle > 360:
self.angle = self.angle-360
if self.angle <0:
self.angle = self.angle+360
self.rect.center = self.x, self.y
x = self.rect.centerx
y = self.rect.centery
_x = self._rect.centerx
_y = self._rect.centery
for b in bricks:
if self.rect.colliderect(b.rect):
if _x+21 <= b.rect.left and x+21 > b.rect.left:
if b.left == True:
self.x = b.rect.left-21
if _x-21 >= b.rect.right and x-21 < b.rect.right:
if b.right == True:
self.x = b.rect.right+21
if _y+21 <= b.rect.top and y+21 > b.rect.top:
if b.top == True:
self.y = b.rect.top-21
if _y-21 >= b.rect.bottom and y-21 < b.rect.bottom:
if b.bottom == True:
self.y = b.rect.bottom+21
for b in bullets:
if self.rect.colliderect(b.rect):
b_size = b.get_size()
pygame.sprite.Sprite.kill(b)
if b_size == "small":
booms.add(Boom(b.rect.center, "small"))
self.health -= 1
if b_size == "big":
booms.add(Boom(b.rect.center, "big"))
self.health -=5
for b in bombs:
if self.rect.colliderect(b.rect) and b.timer == 20:
self.health -=5
if self.health <= 0:
booms.add(Boom(self.rect.center, "huge"))
self.alive = False
self.health = 0
'''if self.image_type == self.tank_pic:
self.image = self.tank1_pic
self.image_type = self.tank1_pic
print "switch 1"
if self.image_type == self.tank1_pic:
self.image = self.tank_pic
self.image_type = self.tank_pic
print "switch 2"'''
class Turret(pygame.sprite.Sprite):
def __init__(self, pos, angle, follow):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("turret.png").convert_alpha()
self.timer = 40
self.timer_start = self.timer
self.size = "big"
self.bang_s = pygame.mixer.Sound("bang.wav")
self.speed = 3
self.bang_s.set_volume(1.0)
self._image = self.image
self.rect = self.image.get_rect()
self.rect = self.rect.move(pos)
self.angle = angle
self.timer = 40
self.wait_timer = 5
self.timer_restart = 0
self.x, self.y = self.rect.center
self.follow = follow
def rotate(self):
center = self._rect.center
self.image = pygame.transform.rotozoom(self._image, self.angle, 1.0)
self.rect = self.image.get_rect(center = center)
def update(self, pos, mx, my, keys, booms, tank_angle, bricks, background, city):
self.background = background
self.city_size = city
self.t = True
self.bricks = bricks
self.end = None
self._rect = Rect(self.rect)
self._rect.center = pos
self.tank_angle = tank_angle
t_x, t_y = self.rect.center
if keys[K_m]:
if self.wait_timer >= 5:
self.follow = not self.follow
self.wait_timer = self.timer_restart
if self.follow:
self.mouse_angle = math.atan2(xd, yd)*(180/math.pi)+180 #used atan2(x,y) instead of atan2(y,x). Sprite was origanly drawn along the y axis, gave better results
if self.angle < self.mouse_angle:
if math.fabs(self.angle - self.mouse_angle) < 180:
self.angle +=self.speed
else:
self.angle -=self.speed
else:
if math.fabs(self.angle - self.mouse_angle) < 180:
self.angle -=self.speed
else:
self.angle +=self.speed
if math.fabs(self.angle - self.mouse_angle) < self.speed+.5:
self.angle = self.mouse_angle
if not self.follow:
if self.angle != self.tank_angle:
if self.angle < self.tank_angle:
if math.fabs(self.angle - self.tank_angle) < 180:
self.angle +=self.speed
else:
self.angle -=self.speed
else:
if math.fabs(self.angle - self.tank_angle) < 180:
self.angle -=self.speed
else:
self.angle +=self.speed
if math.fabs(self.angle - self.tank_angle) < self.speed+.5:
self.angle = self.tank_angle
else:
self.angle = self.tank_angle
self.rotate()
if self.angle > 360:
self.angle = self.angle-360
if self.angle <0:
self.angle = self.angle+360
if self.wait_timer < 5:
self.wait_timer += 1
# ---------- END OF CLASSES ---------- #
def main():
pygame.init()
version = "Tank Wars 2.0"
screen = pygame.display.set_mode((1170, 510),0,32)
n = 1
size = screen.get_size()
pygame.mouse.set_visible(False)
map_ = pygame.image.load("c2.png")
health = 40
health_full = health
bricks= pygame.sprite.Group()
bricks_des = pygame.sprite.Group()
bricks_non = pygame.sprite.Group()
bullets = pygame.sprite.Group()
booms = pygame.sprite.Group()
bombers = pygame.sprite.Group()
bombs = pygame.sprite.Group()
tanks = pygame.sprite.Group()
allgroup = pygame.sprite.LayeredUpdates()
#assign default groups to each sprite class
#Tank.groups = tanks, allgroup
#Turret.groups = allgroup
#Bullet.groups = bullets, allgroup
city = City(bricks, map_)
city_size = city.get_size()
clock = pygame.time.Clock()
timer = 0
chance = None
score = 0
player1 = Tank((150, 250), 360, 40)
tanks.add(player1)
player2 = Tank((1100, 250), 360, 40)
tanks.add(player2)
player1_turret = Turret((150, 250), 360, False)
player2_turret = Turret((1100, 250), 360, False)
background = pygame.Surface((city_size), 0, 32)
city.bricks.draw(screen)
font4 = pygame.font.Font("7theb.ttf", 13)
font5 = pygame.font.SysFont("Courier New", 16, bold=True)
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
if event.type == KEYDOWN:
if event.key == K_ESCAPE:
return
clock.tick(24)
time_passed = clock.tick()
keys = pygame.key.get_pressed()
m_x, m_y = pygame.mouse.get_pos()
background.fill((87, 87, 87))
if player1.alive == True:
player1.update(keys, bricks, bullets, booms, bombs)
player1_turret.update(player1.rect.center, m_x, m_y, keys, booms, 360, bricks, background, city_size)
screen.blit(player1.image, player1.rect)
screen.blit(player1_turret.image, player1_turret.rect)
if player2.alive == True:
player2.update(keys, bricks, bullets, booms, bombs)
player2_turret.update(player2.rect.center, m_x, m_y, keys, booms, 360, bricks, background, city_size)
screen.blit(player2.image, player2.rect)
screen.blit(player2_turret.image, player2_turret.rect)
bullets.update(bricks, booms)
bombs.update(booms, player1)
bombs.update(booms, player2)
booms.update(background)
bombs.draw(screen)
bullets.draw(screen)
bombers.draw(screen)
healthshow = font4.render('Health ', False, (255,255,255))
#---Player 1 Healthbar---#
pygame.draw.ellipse(screen, (255, ((player1.health*255)/health_full),0), (90, 20, 10, 13))
pygame.draw.ellipse(screen, (255, ((player1.health*255)/health_full),0), (92+(100*(float(player1.health)/float(health_full))), 20, 10, 13))
screen.fill((255,((player1.health*255)/health_full),0),(96,20,(100*(float(player1.health)/float(health_full))), 13))
screen.blit(healthshow, (5, 20))
#---Player 2 Healthbar---#
pygame.draw.ellipse(screen, (255, ((player2.health*255)/health_full),0), (90, 20, 10, 13))
pygame.draw.ellipse(screen, (255, ((player2.health*255)/health_full),0), (92+(100*(float(player2.health)/float(health_full))), 20, 10, 13))
screen.fill((255,((player2.health*255)/health_full),0),(96,20,(100*(float(player2.health)/float(health_full))), 13))
screen.blit(healthshow, (500, 20))
allgroup.clear(screen, background)
pygame.display.flip()
if __name__ == "__main__":
main()
My suggestion is to make a global screen variable (instead of being wrapped inside a function, and generate a single city image, with the bricks added to it. Since those are all the components that do not change, this can be blitted to the screen every time the frame is refreshed.
After that, on each frame, the tank (with health bar and other stuff) and bullets can be blitted directly to the screen variable.
It is probably simplest to just do pygame.display.flip() after all of the blitting is done, but keeping an array of pygame.Rects representing blit positions and then keeping the old blit Rects and then doing something like:
old_rects = current_rects
current_rects = []
#make blits, collect Rects in current_rects
pygame.display.update(current_rects + old_rects)
This way, pygame.display.update() can be used (since it is more efficient), and there won't be problems with no refreshing.
I hope this works and that you can implement something like this.

Categories

Resources