Jumping creates a distance between man and the floor Pygame [duplicate] - python
This question already has answers here:
How to simulate Jumping in Pygame for this particular code
(1 answer)
jumping too fast?
(1 answer)
How to make a circular object jump using pygame? [duplicate]
(2 answers)
Pygame Bouncy Ball Sinks Through Floor
(1 answer)
Closed 2 years ago.
The full code:
import glob
import pygame
import os
os.environ['SDL_VIDEO_WINDOW_POS'] = "%d,%d" % (100, 40)
class Man(pygame.sprite.Sprite):
# just taking random image to get height and width after trans scale to be able to crop later (see lines 23/36)
idle_images_list = glob.glob(r"C:\Users\aviro\Desktop\מחשבים\python projects\platform game\animation\fighter\PNG\PNG Sequences\Firing"+'\*')
random_image = pygame.image.load(idle_images_list[0])
new_img_width = int(random_image.get_width()/2.5)
new_img_height = int(random_image.get_height()/2.5)
random_image_after_crop = random_image.subsurface((70, 35, new_img_width-125, new_img_height-45))
# to be able to use needed images indexes
# getting idle animations list
right_idle_list = []
left_idle_list = []
for images in idle_images_list:
img = pygame.image.load(images)
wid = img.get_width()
hei = img.get_height()
img = pygame.transform.scale(img, (int(wid/2.5), int(hei/2.5)))
img = img.subsurface((70, 35, new_img_width-125, new_img_height-45))
right_idle_list.append(img)
left_idle_list.append(pygame.transform.flip(img, True, False))
# getting movement animations list
walk_animation_list = glob.glob(r"C:\Users\aviro\Desktop\מחשבים\python projects\platform game\animation\fighter\PNG\PNG Sequences\Run Firing"+'\*')
walk_right_list = []
walk_left_list = []
for files in walk_animation_list: # setting the animation list
img = pygame.image.load(files)
wid = img.get_width()
hei = img.get_height()
img = pygame.transform.scale(img, (int(wid/2.5), int(hei/2.5))) # chaging scale
img = img.subsurface((70, 35, new_img_width-125, new_img_height-45))
walk_right_list.append(img)
walk_left_list.append(pygame.transform.flip(img, True, False)) # mirror list
def __init__(self, x, y,):
super(Man, self).__init__()
self.walk_left_list = Man.walk_left_list
self.walk_right_list = Man.walk_right_list
self.width = Man.new_img_width
self.height = Man.new_img_height
self.hitbox = (x+55, y+35, self.width-125, self.height-45) # nothing special on those num, just Trial and error
self.rect = Man.random_image_after_crop.get_rect()
self.rect.x = x
self.rect.y = y
def game_redraw(): # print things in end for main loop
global right
global left
screen.blit(bg_image, (0, 0))
if right:
screen.blit(man.walk_right_list[frame_count//3], (man.rect.x, man.rect.y))
elif left:
screen.blit(man.walk_left_list[frame_count//3], (man.rect.x, man.rect.y))
else:
if last_action == "right":
screen.blit(man.right_idle_list[frame_count//13], (man.rect.x, man.rect.y))
if last_action == "left":
screen.blit(man.left_idle_list[frame_count//13], (man.rect.x, man.rect.y))
else: # just for the first move
screen.blit(man.right_idle_list[frame_count//13], (man.rect.x, man.rect.y))
pygame.draw.rect(screen, RED, man.rect, 4)
pygame.display.flip()
right = False
left = False
def input_process(key):
global right
global left
global last_action
global man
global frame_count
global is_jump
global neg
global jump_count
#
if is_jump:
if jump_count >= -10: # check if jumping
if jump_count < 0:
neg = -1
man.rect.y -= (jump_count ** 2) * neg * 0.5
jump_count -= 1
else:
neg = 1
is_jump = False
#
if key[pygame.K_RIGHT] and man.rect.right + speed < w:
if left:
frame_count = 0
right = True
left = False
last_action = "right"
man.rect.x += speed
#
if key[pygame.K_LEFT] and man.rect.left + speed > 0:
if right:
frame_count = 0
right = False
left = True
last_action = "left"
man.rect.x -= speed
#
if not is_jump:
if key[pygame.K_UP]:
jump_count = 10
is_jump = True
w = 1728
h = 972
pygame.init()
RED = (255, 0, 0)
images_folder = r'C:\Users\aviro\Desktop\מחשבים\python projects\platform game\images'+'\\'
bg_image = images_folder+"background.png" # setting background image
ground_height = h-143 # the high of the image ground
man = Man(200, ground_height)
man.rect.bottom = ground_height
clock = pygame.time.Clock()
Refresh_Rate = 54
speed = 5
right = False
left = False
frame_count = 0
finish = False
last_action = ""
# jumping ver
is_jump = False
jump_count = 10
neg = 1
#
screen = pygame.display.set_mode((w, h))
bg_image = pygame.image.load(bg_image).convert() # can do convert only after setting surface.
# main loop
while not finish:
if frame_count >= 51:
frame_count = 0
for events in pygame.event.get():
if events.type == pygame.QUIT:
finish = True
key = pygame.key.get_pressed()
input_process(key)
game_redraw()
frame_count += 1
clock.tick(Refresh_Rate)
I'm trying to create a simple shooting-platform game, using pygame module. Everything works fine except the jumping. See in line 88. The player is jumping like an x^2 parabola. I added the *0.5 at the end of the line to make the player jump slower and lower, but when I do it this is what happened.
Before jumping:
After jumping:
Look in the second picture. There's a distance between the floor and the player. When I remove the *0.5 everything works fine. Why?
Related
Pygame beginner, player animation not working despite doing it by the tutorial
First time ever working with Pygame for a school assignment and I'm following a tutorial for it with my project members (tutorial link https://youtu.be/AY9MnQ4x3zk). Problem is that despite following the tutorial to the dot at the "animating the player", my character (named "Marko" in the game and code) doesn't have his animation playing. When I start the game the character is stuck on it's first frame of animation. I've created a 3-frame animation and have the frames as separate png-files. The game so far itself works (it's on very beginner level, just a couple spawning enemies, collision and intro screens done so far), but the animation has had me and my project group scratching our heads for days. So far haven't found a solution by Googling nor searching here. Also at the "# Marko's animations" -part "marko" is darkened and when hovering mouse on it, it says ""(variable) marko: Surface - "marko" is not accessed Pylance"" Here's the entire code: import sys from pygame.locals import * from random import randint from pygame import mixer pygame.init() width = 1920 height = 1080 screen = pygame.display.set_mode((width,height)) pygame.display.set_caption("Putkimies Marko") start_time = 0 score = 0 nopeus = [3,3] clock = pygame.time.Clock() game_active = False marko_gravity = 0 # Score def display_score(): current_time = int(pygame.time.get_ticks() / 1000) - start_time score_surf = test_font.render(f'Score: {current_time}',False,(black)) score_rect = score_surf.get_rect(center = (900,50)) screen.blit(score_surf,score_rect) return current_time def obstacle_movement(obstacle_list): if obstacle_list: for obstacle_rect in obstacle_list: obstacle_rect.x -= 5 if obstacle_rect.bottom == 955: screen.blit(rat,obstacle_rect) else: screen.blit(fly,obstacle_rect) return obstacle_list else: return[] def collisions(marko,obstacles): if obstacles: for obstacle_rect in obstacles: if marko.colliderect(obstacle_rect): return False return True # Surfaces background = pygame.image.load("marko_background.png").convert_alpha() sewer = pygame.image.load("background_sewer.png").convert_alpha() ground = pygame.image.load("ground.png").convert_alpha() rat = pygame.image.load("rat.png").convert_alpha() game_over = pygame.image.load("game_over.png").convert_alpha() fly = pygame.image.load("fly.png").convert_alpha() # Marko Surfaces marko_run_1 = pygame.image.load("marko_run_1.png").convert_alpha() marko_run_2 = pygame.image.load("marko_run_2.png").convert_alpha() marko_run_3 = pygame.image.load("marko_run_3.png").convert_alpha() marko_run = [marko_run_1,marko_run_2,marko_run_3] marko_index = 0 marko_jump = pygame.image.load("marko_jump.png").convert_alpha() marko = marko_run[marko_index] # Fonts test_font = pygame.font.Font("supermario.ttf", 50) # Colors black = (0,0,0) red = (255,0,0) green = (0,255,0) blue = (0,0,255) light_blue = (94,129,162) purple = (36,5,83) # Rects game_overSurface = game_over.get_rect(midtop = (970,-200)) platform = pygame.Surface((300,50)) groundSurface = ground.get_rect(midtop = (960,480)) markoSurface = marko.get_rect() text_surface = test_font.render('Putkimies Marko', False, red) markoSurface.left = 50 markoSurface.bottom = 714 # Obstacles obstacle_rect_list = [] # Intro screen player_stand = pygame.image.load("putkimies_marko_idle.png") player_stand = pygame.transform.rotozoom(player_stand,0,2) player_stand_rect = player_stand.get_rect(center = (950,500)) game_name = test_font.render("PUTKIMIES MARKO", False,"Black") game_name_rect = game_name.get_rect(center = (950,350)) game_message = test_font.render('PRESS SPACE TO PLAY',False,"Black") game_message_rect = game_message.get_rect(center = (950,650)) game_message_start_again = test_font.render('PRESS SPACE TO PLAY AGAIN',False,"Black") game_message_start_again_rect = game_message.get_rect(center = (850,720)) # Marko's animations def marko_animation(): global markoSurface, marko_index if markoSurface.bottom < 955: marko = marko_jump else: marko_index += 0.1 if marko_index >= len(marko_run):marko_index = 0 marko = marko_run[int(marko_index)] # Timer obstacle_timer = pygame.USEREVENT + 1 pygame.time.set_timer(obstacle_timer,1500) # Background music mixer.music.load('smb_stage_clear.wav') mixer.music.play(0) # -1 Makes the music loop while True: for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() sys.exit() if event.type == KEYDOWN: if event.key == K_ESCAPE: pygame.quit() sys.exit() if game_active: if event.type == KEYDOWN: if event.key == K_SPACE and markoSurface.bottom >= 955: marko_gravity = -18 else: if event.type == pygame.KEYDOWN and event.key == pygame.K_SPACE: game_active = True start_time = int(pygame.time.get_ticks() / 1000) if event.type == obstacle_timer and game_active: if randint (0,2): obstacle_rect_list.append(rat.get_rect(midbottom = (randint(2000,2200),955))) else: obstacle_rect_list.append(fly.get_rect(midbottom = (randint(2000,2200),855))) if game_active: # Draw screen.blit(sewer, (0,0)) screen.blit(ground, (0,955)) marko_animation() screen.blit(marko,markoSurface) score = display_score() # Key uses key_use = pygame.key.get_pressed() if key_use[K_LEFT]: markoSurface.move_ip((-7,0)) if key_use[K_RIGHT]: markoSurface.move_ip((7,0)) # Marko marko_gravity += 1 markoSurface.y += marko_gravity if markoSurface.bottom >= 955: markoSurface.bottom = 955 if markoSurface.left <= 0: markoSurface.left = 0 if markoSurface.right >= 1920: markoSurface.right = 1920 # Obstacle movement obstacle_rect_list = obstacle_movement(obstacle_rect_list) # Collision game_active = collisions(markoSurface,obstacle_rect_list) else: # Intro screen screen.fill ("Light blue") screen.blit(player_stand,player_stand_rect) obstacle_rect_list.clear() markoSurface.left = 80 # returns marko to 80 # Draws score message if score > 0 score_message = test_font.render(f'Your score: {score}',False,(red)) score_message_rect = score_message.get_rect(center = (950,650)) screen.blit(game_name,game_name_rect) if score == 0: screen.blit(game_message,game_message_rect) else: screen.blit(score_message,score_message_rect) screen.blit(game_over,game_overSurface) screen.blit(game_message_start_again,game_message_start_again_rect) pygame.display.update() clock.tick(60)```
marko is a variable in global namespace. You must use the global statement to change a variable in the global namespace within a function: def marko_animation(): global marko # <--- global marko_index if markoSurface.bottom < 955: marko = marko_jump else: marko_index += 0.1 if marko_index >= len(marko_run): marko_index = 0 marko = marko_run[int(marko_index)]
TypeError: start_new_game() missing 1 required positional argument: 'max_health' [closed]
Closed. This question needs details or clarity. It is not currently accepting answers. Want to improve this question? Add details and clarify the problem by editing this post. Closed 1 year ago. Improve this question So I have been trying to figure out why I keep getting this error, even though everything is run from my game_view.py module. Everytime I press the 1 key to start a game and test to see if the players health bar and hit points works, I get this error message. TypeError: start_new_game() missing 1 required positional argument: 'max_health' The sad part is, is that it reffers me to the start_view which doesn't have anything to do with anything else but running the start screen so players can choose to play solo or with another player. Below is the game_view and start_view so you guys can see where I'm going wrong. I wanted to test this out so this way I can add other enemies, bosses and power-ups later, but running into this error for the past several days is hindering progress. Anyway, code for both will be below. Thanks in advance for any and all help. start_view: import arcade from game_view import GameView class StartView(arcade.View): def on_show(self): # This is run once when we switch to this view arcade.set_background_color(arcade.csscolor.BLACK) # Reset the viewport, necessary if we have a scrolling game arcade.set_viewport(0, self.window.width, 0, self.window.height) def on_draw(self): # Draw this view arcade.start_render() line_height = 70 line_location = self.window.height - line_height * 2 arcade.draw_text("Space Defense Force", self.window.width / 2, line_location, arcade.color.WHITE, font_size=50, anchor_x="center", font_name="SF Atarian System") line_location -= line_height line_location -= line_height arcade.draw_text("1 - Start One Player Game", self.window.width / 2, line_location, arcade.color.WHITE, font_size=20, anchor_x="center", font_name="SF Atarian System") # if len(self.window.joysticks) > 1: # color = arcade.color.WHITE # else: # color = arcade.color.GRAY color = arcade.color.GRAY line_location -= line_height arcade.draw_text("2 - Start Two Player Game", self.window.width / 2, line_location, color, font_size=20, anchor_x="center", font_name="SF Atarian System") line_location -= line_height line_location -= line_height color = arcade.color.WHITE arcade.draw_text("Use joysticks to play, or arrow keys to move and number keys to fire.", self.window.width / 2, line_location, color, font_size=20, anchor_x="center", font_name="SF Atarian System") def on_key_press(self, symbol: int, modifiers: int): if symbol == arcade.key.KEY_1: game_view = GameView() game_view.start_new_game(1) self.window.show_view(game_view) elif symbol == arcade.key.KEY_2: game_view = GameView() game_view.start_new_game(2) self.window.show_view(game_view) game_view: import random import math import arcade from health import Health from game_over_view import GameOverView from typing import cast from arcade.experimental.shadertoy import Shadertoy from constants import * from asteroid_sprite import AsteroidSprite from ship_sprite import ShipSprite from bullet import Bullet from glow_line import GlowLine from glow_ball import GlowBall from explosion import ExplosionMaker from glow_image_sprite import GlowImageSprite from window import Window as window class GameView(arcade.View): # Main application class def __init__(self): super().__init__() # Sprite lists self.player_sprite_list = arcade.SpriteList() self.asteroid_list = arcade.SpriteList() self.bullet_list = arcade.SpriteList() self.ship_life_list = arcade.SpriteList() self.health_list = arcade.SpriteList() # Sounds self.laser_sound = arcade.load_sound(":resources:sounds/hurt5.wav") self.hit_sound1 = arcade.load_sound(":resources:sounds/explosion1.wav") self.hit_sound2 = arcade.load_sound(":resources:sounds/explosion2.wav") self.hit_sound3 = arcade.load_sound(":resources:sounds/hit1.wav") self.hit_sound4 = arcade.load_sound(":resources:sounds/hit2.wav") self.dead_sound = arcade.load_sound(":resources:sounds/gameover2.wav") self.glowball_shadertoy = Shadertoy.create_from_file(self.window.get_size(), "glow_ball.glsl") self.glowline_shadertoy = Shadertoy.create_from_file(self.window.get_size(), "glow_line.glsl") self.explosion_list = [] # for joystick in self.window.joysticks: # joystick.push_handlers(self) def start_new_game(self, player_count, max_health): #Set up the game and initialize the variables self.game_over = False arcade.set_background_color(arcade.csscolor.BLACK) # Sprite lists self.player_sprite_list = arcade.SpriteList() self.asteroid_list = arcade.SpriteList() self.bullet_list = arcade.SpriteList() self.ship_life_list = arcade.SpriteList() self.health_list = arcade.SpriteList() # if len(self.window.joysticks) > 0: # joystick = self.window.joysticks[0] # else: # joystick = None joystick = None player_sprite = ShipSprite(":resources:images/space_shooter/playerShip1_orange.png", SCALE, joystick, player_no=1, player_count=player_count, max_health=5) self.player_sprite_list.append(player_sprite) self.health_list.append(max_health) if player_count > 1: joystick = None # if len(self.window.joysticks) > 1: # joystick = self.window.joysticks[1] # else: # joystick = None player_sprite = ShipSprite(":resources:images/space_shooter/playerShip1_green.png", SCALE, joystick, player_no=2, player_count=player_count, max_health=5 ) self.player_sprite_list.append(player_sprite) self.health_list.append(max_health) # Set up the player for player in self.player_sprite_list: player.score = 0 player.lives = 3 # Set up the little icons that represent the player lives. cur_pos = 10 for i in range(self.player_sprite_list[0].lives): life = arcade.Sprite(":resources:images/space_shooter/playerLife1_orange.png", SCALE) life.center_x = cur_pos + life.width life.center_y = life.height cur_pos += life.width self.ship_life_list.append(life) if len(self.player_sprite_list) > 1: cur_pos = 100 for i in range(self.player_sprite_list[1].lives): life = arcade.Sprite(":resources:images/space_shooter/playerLife1_green.png", SCALE) life.center_x = cur_pos + life.width life.center_y = life.height cur_pos += life.width self.ship_life_list.append(life) # Make the asteroids image_list = (":resources:images/space_shooter/meteorGrey_big1.png", ":resources:images/space_shooter/meteorGrey_big2.png", ":resources:images/space_shooter/meteorGrey_big3.png", ":resources:images/space_shooter/meteorGrey_big4.png") for i in range(STARTING_ASTEROID_COUNT): image_no = random.randrange(4) enemy_sprite = AsteroidSprite(image_list[image_no], SCALE) enemy_sprite.guid = "Asteroid" enemy_sprite.center_y = random.randrange(BOTTOM_LIMIT, TOP_LIMIT) enemy_sprite.center_x = random.randrange(LEFT_LIMIT, RIGHT_LIMIT) enemy_sprite.change_x = random.random() * 2 - 1 enemy_sprite.change_y = random.random() * 2 - 1 enemy_sprite.change_angle = (random.random() - 0.5) * 2 enemy_sprite.size = 4 self.asteroid_list.append(enemy_sprite) def on_draw(self): # Render the screen. # This command has to happen before we start drawing arcade.start_render() # Draw all the sprites. self.asteroid_list.draw() self.ship_life_list.draw() for bullet in self.bullet_list: bullet.draw() self.bullet_list.draw() for explosion in self.explosion_list: explosion.render() self.player_sprite_list.draw() self.health_list.draw() # Put the text on the screen. output = f"Player 1 Score: {self.player_sprite_list[0].score}" arcade.draw_text(output, 10, 40, arcade.color.AMBER, font_size=15, font_name="Arcade") if len(self.player_sprite_list) > 1: output = f"Player 2 Score: {self.player_sprite_list[1].score}" arcade.draw_text(output, 500, 40, arcade.color.AMBER, font_size=15, font_name="Arcade") output = f"Asteroid Count: {len(self.asteroid_list)}" arcade.draw_text(output, 10, 80, arcade.color.AMBER, font_size=15, font_name="Arcade") for player in health_list: player.draw_health_number() player.draw_health_bar() # def on_joybutton_press(self, joystick, button): # # What player is this? # if joystick == self.window.joysticks[0]: # player_sprite = self.player_sprite_list[0] # else: # player_sprite = self.player_sprite_list[1] # if player_sprite.player_no == 1: # color = 255, 128, 128 # else: # color = 128, 255, 128 # if button == 0: # self.fire_circle(color, player_sprite, player_no=player_sprite.player_no) # elif button == 1: # self.fire_line(color, player_sprite, player_no=player_sprite.player_no) # elif button == 2: # bullet_sprite = GlowImageSprite(":resources:images/space_shooter/laserBlue01.png", # SCALE, # glowcolor=arcade.color.WHITE, # shadertoy=self.glowball_shadertoy, # player_no=player_sprite.player_no) # self.set_bullet_vector(bullet_sprite, 10, player_sprite) # arcade.play_sound(self.laser_sound) def on_key_press(self, symbol, modifiers): # Shoot if the player hit the space bar and we aren't respawning. if symbol == arcade.key.LEFT: self.player_sprite_list[0].change_angle = 3 elif symbol == arcade.key.RIGHT: self.player_sprite_list[0].change_angle = -3 elif symbol == arcade.key.UP: self.player_sprite_list[0].thrust = 0.15 elif symbol == arcade.key.DOWN: self.player_sprite_list[0].thrust = -.2 elif symbol == arcade.key.KEY_1: color = (255, 128, 128) self.fire_circle(color, self.player_sprite_list[0], player_no=0) elif symbol == arcade.key.KEY_2: color = (128, 255, 128) self.fire_circle(color, self.player_sprite_list[0], player_no=0) elif symbol == arcade.key.KEY_3: color = (128, 128, 255) self.fire_circle(color, self.player_sprite_list[0], player_no=0) elif symbol == arcade.key.KEY_4: color = (255, 128, 255) self.fire_circle(color, self.player_sprite_list[0], player_no=0) elif symbol == arcade.key.KEY_5: color = (255, 255, 255) self.fire_line(color, self.player_sprite_list[0], player_no=0) elif symbol == arcade.key.KEY_6: color = (64, 255, 64) self.fire_line(color, self.player_sprite_list[0], player_no=0) elif symbol == arcade.key.KEY_7: bullet_sprite = GlowImageSprite(":resources:images/space_shooter/laserBlue01.png", SCALE, glowcolor=arcade.color.WHITE, shadertoy=self.glowball_shadertoy, player_no=0) self.set_bullet_vector(bullet_sprite, 13, self.player_sprite_list[0]) arcade.play_sound(self.laser_sound) def fire_circle(self, bullet_color, player_sprite, player_no): bullet_sprite = GlowBall(glowcolor=bullet_color, radius=5, shadertoy=self.glowball_shadertoy, player_no=player_no) self.set_bullet_vector(bullet_sprite, 5, player_sprite) arcade.play_sound(self.laser_sound) def fire_line(self, bullet_color, player_sprite, player_no): bullet_sprite = GlowLine(glowcolor=bullet_color, shadertoy=self.glowline_shadertoy, player=player_sprite, player_no=player_no) self.set_bullet_vector(bullet_sprite, 13, player_sprite) arcade.play_sound(self.laser_sound) def set_bullet_vector(self, bullet_sprite, bullet_speed, player_sprite): bullet_sprite.change_y = \ math.cos(math.radians(player_sprite.angle)) * bullet_speed bullet_sprite.change_x = \ -math.sin(math.radians(player_sprite.angle)) \ * bullet_speed bullet_sprite.center_x = player_sprite.center_x bullet_sprite.center_y = player_sprite.center_y self.bullet_list.append(bullet_sprite) def on_key_release(self, symbol, modifiers): # Called whenever a key is released if symbol == arcade.key.LEFT: self.player_sprite_list[0].change_angle = 0 elif symbol == arcade.key.RIGHT: self.player_sprite_list[0].change_angle = 0 elif symbol == arcade.key.UP: self.player_sprite_list[0].thrust = 0 elif symbol == arcade.key.DOWN: self.player_sprite_list[0].thrust = 0 def split_asteroid(self, asteroid: AsteroidSprite): # Split an asteroid into chunks x = asteroid.center_x y = asteroid.center_y if asteroid.size == 4: for i in range(3): image_no = random.randrange(2) image_list = [":resources:images/space_shooter/meteorGrey_med1.png", ":resources:images/space_shooter/meteorGrey_med2.png"] enemy_sprite = AsteroidSprite(image_list[image_no], SCALE * 1.5) enemy_sprite.center_y = y enemy_sprite.center_x = x enemy_sprite.change_x = random.random() * 2.5 - 1.25 enemy_sprite.change_y = random.random() * 2.5 - 1.25 enemy_sprite.change_angle = (random.random() - 0.5) * 2 enemy_sprite.size = 3 self.asteroid_list.append(enemy_sprite) self.hit_sound1.play() elif asteroid.size == 3: for i in range(3): image_no = random.randrange(2) image_list = [":resources:images/space_shooter/meteorGrey_small1.png", ":resources:images/space_shooter/meteorGrey_small2.png"] enemy_sprite = AsteroidSprite(image_list[image_no], SCALE * 1.5) enemy_sprite.center_y = y enemy_sprite.center_x = x enemy_sprite.change_x = random.random() * 3 - 1.5 enemy_sprite.change_y = random.random() * 3 - 1.5 enemy_sprite.change_angle = (random.random() - 0.5) * 2 enemy_sprite.size = 2 self.asteroid_list.append(enemy_sprite) self.hit_sound2.play() elif asteroid.size == 2: for i in range(3): image_no = random.randrange(2) image_list = [":resources:images/space_shooter/meteorGrey_tiny1.png", ":resources:images/space_shooter/meteorGrey_tiny2.png"] enemy_sprite = AsteroidSprite(image_list[image_no], SCALE * 1.5) enemy_sprite.center_y = y enemy_sprite.center_x = x enemy_sprite.change_x = random.random() * 3.5 - 1.75 enemy_sprite.change_y = random.random() * 3.5 - 1.75 enemy_sprite.change_angle = (random.random() - 0.5) * 2 enemy_sprite.size = 1 self.asteroid_list.append(enemy_sprite) self.hit_sound3.play() elif asteroid.size == 1: self.hit_sound4.play() def on_update(self, x, delta_time): # Move everything self.asteroid_list.update() self.bullet_list.update() self.player_sprite_list.update() self.health_list.update() explosion_list_copy = self.explosion_list.copy() for explosion in explosion_list_copy: explosion.update(x) if explosion.time > .9: self.explosion_list.remove(explosion) for bullet in self.bullet_list: hit_list = arcade.check_for_collision_with_list(bullet, self.player_sprite_list) # If it did hit, get rid of sprite if len(hit_list) > 0: bullet.remove_from_lists() for player in hit_list: if not isinstance(player, ShipSprite): raise TypeError("List contents must be all ints") # Remove one health point player.cur_health -= 1 # Check Health if player.cur_health <= 0: arcade.play_sound(self.dead_sound) view=GameOverView self.window.show_view(view) else: # Not Dead arcade.play_sound(self.hit_sound1) assert isinstance(bullet, Bullet) asteroids = arcade.check_for_collision_with_list(bullet, self.asteroid_list) if len(asteroids) > 0: explosion = ExplosionMaker(self.window.get_size(), bullet.position) self.explosion_list.append(explosion) for asteroid in asteroids: assert isinstance(asteroid, AsteroidSprite) self.player_sprite_list[bullet.player_no - 1].score += 1 self.split_asteroid(cast(AsteroidSprite, asteroid)) # expected AsteroidSprite, got Sprite instead asteroid.remove_from_sprite_lists() bullet.remove_from_sprite_lists() # Remove bullet if it goes off-screen size = max(bullet.width, bullet.height) if bullet.center_x < 0 - size: bullet.remove_from_sprite_lists() if bullet.center_x > SCREEN_WIDTH + size: bullet.remove_from_sprite_lists() if bullet.center_y < 0 - size: bullet.remove_from_sprite_lists() if bullet.center_y > SCREEN_HEIGHT + size: bullet.remove_from_sprite_lists() for player in self.player_sprite_list: assert isinstance(player, ShipSprite, max_health) if not player.respawning: asteroids = arcade.check_for_collision_with_list(player, self.asteroid_list) if len(asteroids) > 0: if player.lives > 0: player.lives -= 1 player.respawn() self.split_asteroid(cast(AsteroidSprite, asteroids[0])) asteroids[0].remove_from_sprite_lists() self.ship_life_list.pop().remove_from_sprite_lists() elif len(asteroids) > 0: if player.health > 0: player.health -=1 player.respawn() self.split_asteroid(cast(AsteroidSprite, asteroids[0])) asteroids[0].remove_from_sprite_lists() self.ship_list_list.pop().remove_from_sprite_lists() else: arcade.play_sound(self.dead_sound) view = GameOverView() self.window.show_view(view) Sorry in advance if I have tons of code to go through. But like I said I am adding some features that wasn't in the Arcade Repository from github. I even set a separte module for the health bar and hit points so this way I can see what conflicts. But the error above has been a royal pain.Thanks again. P.S. Remarked out joysticks because it was conflicting with another module I built.
As your title says, your start game function requires 2 arguments: player_count and max_healh. And in your code, when using start_new_game, you aren't supplying the max_health argument, thus raising an error. (function) start_new_game(self, player_count, max_health)
Trying to delete sprite with kill(), but sprite isn't disappearing
This is my first time asking here, so sorry if I don't ask very well. Lately I've been trying to make a Terraria-type game where you can break/place blocks in a randomly generated landscape. While trying to implement the breaking-block mechanic (which is triggered by clicking on a block), I ran into an issue. The block no longer became solid (that's a good thing), but the block's image is still there, and I can walk right through it. A visual example: Before breaking block vs. After breaking block Here's the code Main file (hopefully only the relevant bits): # Imports import pygame as pg import json import sys import random import os from settings import * from world_handler import * # Initialize pygame pg.mixer.pre_init() pg.init() # Fonts # NOTE: put fonts in here # Helper functions def load_image(file_path): # Loads an image img = pg.image.load(file_path) return img def play_sound(sound, loops=0, maxtime=0, fade_ms=0): # Plays some audio if sound_on: sound.play(loops, maxtime, fade_ms) def play_music(): # Plays background music if sound_on: pg.mixer.music.play(-1) # File paths current_path = os.path.dirname(__file__) assets_path = os.path.join(current_path, "assets") image_path = os.path.join(assets_path, "img") # Images player_standing = load_image((os.path.join(image_path, "player", "standing", "player-standing.png"))) player_walking1 = load_image((os.path.join(image_path, "player", "walking", "player-walking1.png"))) player_walking2 = load_image((os.path.join(image_path, "player", "walking", "player-walking2.png"))) player_walking3 = load_image((os.path.join(image_path, "player", "walking", "player-walking3.png"))) player_walking4 = load_image((os.path.join(image_path, "player", "walking", "player-walking4.png"))) player_jumping = load_image((os.path.join(image_path, "player", "jumping", "player-jumping.png"))) player_images = {"walking": [player_walking1, player_walking2, player_walking3, player_walking4], "jumping": player_jumping, "standing": player_standing} block_images = {"Grass": load_image((os.path.join(image_path, "blocks", "grass.png"))), "Dirt": load_image((os.path.join(image_path, "blocks", "dirt.png"))), "Stone": load_image((os.path.join(image_path, "blocks", "stone.png")))} cursor_tracker = load_image((os.path.join(image_path, "misc", "clear-single-pixel.png"))) class Entity(pg.sprite.Sprite): def __init__(self, x, y, image): # Initialize an entity super().__init__() self.image = image self.rect = self.image.get_rect() self.rect.x = x self.rect.y = y self.vx = 0 self.vy = 0 def apply_gravity(self, world): # Let the enemy be affected by gravity self.vy += world.gravity self.vy = min(self.vy, world.terminal_velocity) class Block(Entity): def __init__(self, x, y, image): # Initialize the block super().__init__(x, y, image) class Cursor(Entity): def __init__(self, x, y, image): # Initialize the invisible mouse cursor object # This will be used to track where the mouse goes and if the mouse is on a block super().__init__(x, y, image) self.on_block = False def follow_mouse(self): # Make object follow the mouse self.mouse_x, self.mouse_y = pg.mouse.get_pos() self.rect.x = self.mouse_x self.rect.y = self.mouse_y def detect_block_collision(self, world): # Detects collsion between cursor tracker and a block hit_list = pg.sprite.spritecollide(self, world.blocks, True) if len(hit_list) > 0: pass def update(self, world): # Update the cursor object self.follow_mouse() world.active_sprites.add(self) class Player(Entity): def __init__(self, images): # Initialize the player super().__init__(0, 0, images["standing"]) # Images in each direction self.image_standing_right = images["standing"] self.image_standing_left = pg.transform.flip(self.image_standing_right, 1, 0) self.images_walking_right = images["walking"] self.images_walking_left = [pg.transform.flip(img, 1, 0) for img in self.images_walking_right] self.image_jumping_right = images["jumping"] self.image_jumping_left = pg.transform.flip(self.image_jumping_right, 1, 0) # Player variables self.running_images = self.images_walking_right self.image_index = 0 self.steps = 0 self.speed = 3.5 self.jump_power = 12 self.vx = 0 self.vy = 0 self.direction = "right" self.on_ground = True self.score = 0 self.health = 100 self.max_health = 100 self.invincibility = 0 def move_left(self): # Move to the left self.vx = -self.speed + 0.9 self.direction = "left" def move_right(self): # Move to the rightS self.vx = self.speed self.direction = "right" def stop(self): # Stop it right there self.vx = 0 def jump(self, blocks): # Jump up, jump up, and get down self.rect.y += 1 hit_list = pg.sprite.spritecollide(self, blocks, False) if len(hit_list) > 0: self.vy = -1 * self.jump_power self.rect.y -= 1 def check_world_boundaries(self, world): # Make sure the player doesn"t walk off the world if self.rect.left < 0: self.rect.left = 0 elif self.rect.right > world.width: self.rect.right = world.width def move_and_process_blocks(self, blocks): # Detect block collisions # Block side collisions self.rect.x += self.vx hit_list = pg.sprite.spritecollide(self, blocks, False) for block in hit_list: if self.vx > 0: self.rect.right = block.rect.left self.vx = 0 elif self.vx < 0: self.rect.left = block.rect.right self.vx = 0 self.on_ground = False # Block top and bottom collisions self.rect.y += self.vy + 1 # The +1 isn"t necessary, but it helps hit_list = pg.sprite.spritecollide(self, blocks, False) for block in hit_list: if self.vy > 0: self.rect.bottom = block.rect.top self.on_ground = True self.vy = 0 elif self.vy < 0: self.rect.top = block.rect.bottom self.on_ground = True self.vy = 0 def set_image(self): # Set images and animate if self.on_ground: if self.vx != 0: if self.direction == "right": self.walking_images = self.images_walking_right elif self.direction == "left": self.walking_images = self.images_walking_left self.steps = (self.steps + 1) % self.speed if self.steps == 0: self.image_index = (self.image_index + 1) % len(self.walking_images) self.image = self.walking_images[self.image_index] else: if self.direction == "right": self.image = self.image_standing_right elif self.direction == "left": self.image = self.image_standing_left else: if self.direction == "right": self.image = self.image_jumping_right elif self.direction == "left": self.image = self.image_jumping_left def die(self): # D E D pass def check_block_breaks(self, blocks): # Break a block # mouse_pos = pg.mouse.get_pos() # for block in blocks: # if block.rect.collidepoint(mouse_pos): # print("hi") pass def respawn(self, world): # Hey, you"re back! self.rect.x = world.start_x self.rect.y = world.start_y self.health = self.max_health self.invincibility = 0 self.direction = "right" def update(self, world): # Constantly update the player self.apply_gravity(world) self.move_and_process_blocks(world.blocks) self.check_world_boundaries(world) self.set_image() self.check_block_breaks(world.blocks) if self.health > 0: if self.invincibility > 0: self.invincibility -= 1 else: self.die() class Game(): def __init__(self): # Initialize the game itself self.window = pg.display.set_mode([WINDOWWIDTH, WINDOWHEIGHT]) pg.display.set_caption(TITLE) self.clock = pg.time.Clock() self.done = False self.reset() def start(self): # Start the whole thing up self.world = World(worlds[self.current_world]) self.cursor = Cursor(0, 0, cursor_tracker) self.world.reset() self.player.respawn(self.world) def reset(self): # Reset the game self.player = Player(player_images) self.current_world = 0 self.start() def update(self): # Update things in the game self.player.update(self.world) self.cursor.update(self.world) if self.player.health <= 0: self.player.respawn(self.world) def calculate_offset(self): # Calculate x/y coordinates after screen scrolls x = -1 * self.player.rect.centerx + WINDOWWIDTH / 2 if self.player.rect.centerx < WINDOWWIDTH / 2: x = 0 elif self.player.rect.centerx > self.world.width - WINDOWWIDTH / 2: x = -1 * self.world.width + WINDOWWIDTH y = -1 * self.player.rect.centery + WINDOWHEIGHT / 2 if self.player.rect.centery < WINDOWHEIGHT / 2: y = 0 elif self.player.rect.centery > self.world.height - WINDOWHEIGHT / 2: y = -1 * self.world.height + WINDOWHEIGHT return x, y def draw(self): # Draw sprites to the screen self.offset_x, self.offset_y = self.calculate_offset() self.world.active_layer.fill(TRANSPARENT) self.world.active_sprites.draw(self.world.active_layer) if self.player.invincibility % 3 < 2: self.world.active_layer.blit(self.player.image, [self.player.rect.x, self.player.rect.y]) self.window.blit(self.world.background_layer, [self.offset_x / 3, self.offset_y]) self.window.blit(self.world.inactive_layer, [self.offset_x, self.offset_y]) self.window.blit(self.world.active_layer, [self.offset_x, self.offset_y]) self.offset_cursor_x = self.cursor.rect.x - self.offset_x self.offset_cursor_y = self.cursor.rect.y - self.offset_y self.cursor.rect.x = self.offset_cursor_x self.cursor.rect.y = self.offset_cursor_y pg.display.update(0, 0, WINDOWWIDTH, WINDOWHEIGHT) def process_events(self): # Handle events (key presses, mouse clicks, etc) for event in pg.event.get(): if event.type == pg.QUIT: self.done = True elif event.type == pg.KEYDOWN: # Jump if event.key == JUMP: self.player.jump(self.world.blocks) # Debug reset elif event.key == pg.K_r: self.reset() # Debug close elif event.key == pg.K_q: self.done = True # Break a block if you click on it if event.type == pg.MOUSEBUTTONDOWN: # for block in self.world.blocks: # if block.rect.collidepoint(self.offset_cursor_x, self.offset_cursor_y): # block.kill() self.cursor.detect_block_collision(self.world) pressed = pg.key.get_pressed() if pressed[LEFT]: self.player.move_left() elif pressed[RIGHT]: self.player.move_right() else: self.player.stop() def loop(self): # Loop through essential functions while not self.done: self.process_events() self.update() self.draw() self.clock.tick(FPS) if __name__ == "__main__": # Begin the loop and pre-initialize the game game = Game() game.start() game.loop() pg.quit() sys.exit() World Handler (generated blocks and adds them to groups): Some parts are commented out because they serve no purpose yet, but will soon. # Imports import pygame as pg import json import random import os from settings import * from main import * # Initialize pygame pg.init() class World(): def __init__(self, file_path): # Initialize the world # Starting entities self.starting_blocks = [] # Entity groups self.blocks = pg.sprite.Group() # Sprite groups (active/inactive) self.active_sprites = pg.sprite.Group() self.inactive_sprites = pg.sprite.Group() # Read the world json file with open(file_path, "r") as f: data = f.read() map_data = json.loads(data) # World width and height self.width = map_data["width"] * GRID_SIZE self.height = map_data["height"] * GRID_SIZE # Player start position self.start_x = map_data["start"][0] * GRID_SIZE self.start_y = map_data["start"][1] * GRID_SIZE # Load blocks for item in map_data["blocks"]: x, y = item[0] * GRID_SIZE, item[1] * GRID_SIZE img = block_images[item[2]] self.starting_blocks.append(Block(x, y, img)) # Layers self.background_layer = pg.Surface([self.width, self.height], pg.SRCALPHA, 32) self.inactive_layer = pg.Surface([self.width, self.height], pg.SRCALPHA, 32) self.active_layer = pg.Surface([self.width, self.height], pg.SRCALPHA, 32) # Load background color if map_data["bg-color"] != "": self.background_layer.fill(map_data["bg-color"]) # Load background image # if map_data["bg-image"] != "": # bg_image = pg.image.load(map_data["bg-image"]).convert_alpha() # # if map_data["bg-fill-y"]: # h = bg_image.get_height() # w = int(bg_image.get_width() * WINDOWHEIGHT / h) # bg_image = pg.transform.scale(bg_image, (w, WINDOWHEIGHT)) # # if "top" in map_data["bg-position"]: # start_y = 0 # elif "bottom" in map_data["bg-postion"]: # start_y = self.height = bg_image.get_height() # # if map_data["bg-repeat-x"]: # for x in range(0, self.width, bg_image.get_width()): # self.background_layer.blit(bg_image, [x, start_y]) # else: # self.background_layer.blit(bg_image, [0, start_y]) # Load background music # pg.mixer.music.load(map_data["music"]) # Set the world's gravity strength and terminal velocity self.gravity = map_data["gravity"] self.terminal_velocity = map_data["terminal-velocity"] # Grass generator if map_data["gen-type"] == "earth": gen_loop = map_data["width"] x = 0 y = 56 * GRID_SIZE # The general y coordinate for block placing y_gen = 56 * GRID_SIZE # Stored to be referenced in order to make a smoother landscape for i in range (0, map_data["width"]): # Generate grass img = block_images["Grass"] self.starting_blocks.append(Block(x, y, img)) y += GRID_SIZE # Generate dirt for i in range(0, 6): img = block_images["Dirt"] self.starting_blocks.append(Block(x, y, img)) y += GRID_SIZE # Generate stone for i in range(1, int((self.height / GRID_SIZE))): img = block_images["Stone"] self.starting_blocks.append(Block(x, y, img)) y += GRID_SIZE y = y_gen x += GRID_SIZE gen_loop -= 1 # Randomly decide what the next grass' y will be in relation to the previous one random_grass = random.randint(0, 5) # The lowest point you'll find a block of grass lowest_grass_y = 53 * GRID_SIZE # How extreme the changes in block heights will be # 0 is flat, 1 will have pretty smooth terrain, while something like 10 would be super steep gen_extremity = 1 # Keep the grass at the same y if random_grass == 0 or random_grass == 1 or random_grass == 2 or random_grass == 3: gen_loop -= 1 if y <= lowest_grass_y: y += GRID_SIZE # Increase y elif random_grass == 4: y_gen += GRID_SIZE * gen_extremity if y <= lowest_grass_y: y += GRID_SIZE # Decrease y elif random_grass == 5: y_gen -= GRID_SIZE * gen_extremity if y <= lowest_grass_y: y += GRID_SIZE else: raise ValueError("How did we get here? Grass generator somehow generated an invalid number.") # Add starting entities to their groups self.blocks.add(self.starting_blocks) # Add sprites to inactive/active sprite groups self.inactive_sprites.add(self.blocks) # Does... something? for s in self.active_sprites: s.image.convert() for s in self.inactive_sprites: s.image.convert() # Draw inactive sprites to the inactive layer self.inactive_sprites.draw(self.inactive_layer) # Convert layers self.background_layer.convert() self.inactive_layer.convert() self.active_layer.convert() Setting file (to help you recreate the issue and find out what's going on # Imports import pygame as pg import os # File paths current_path = os.path.dirname(__file__) assets_path = os.path.join(current_path, 'assets') image_path = os.path.join(assets_path, 'img') # Window settings TITLE = "Mooncraft" WINDOWWIDTH = 960 WINDOWHEIGHT = 640 FPS = 60 GRID_SIZE = 32 # Options sound_on = True # Controls LEFT = pg.K_a RIGHT = pg.K_d JUMP = pg.K_SPACE # Colors TRANSPARENT = (0, 0, 0, 0) WHITE = (255, 255, 255) BLACK = (0, 0, 0) RED = (255, 0, 0) GREEN = (0, 255, 0) BLUE = (0, 0, 255) # World files worlds = [(os.path.join(assets_path, 'worlds', 'earth.json'))] If someone could explain what I'm doing wrong, it would be much appreciated. Update 2: Added player class and settings file to help anyone willing to assist me find the issue.
From just a glance, it looks like you might not be clearing the screen at any point in the update loop, but rather drawing over what was already there. This would result in the block still being visible, but not actually there. Try adding screen.fill(#Color here) before flipping the display. Also try using pygame.display.update() instead of pygame.display.flip()
You can do this: all_sprites = pg.sprite.Group() all_sprites.add(your_sprite) #your event: all_sprites.remove(your_sprite)
Pygame 2d tile scrolling edges don't load
Im trying to make a 2d game in pygame that kinda works like pokemon. Ive gotten really stuck on a problem now that I dont know how to solve. When I move my character I scroll the map instead so the player stays centered. I've created an "animation" by offsetting the distance by 2 pixels at a time instead of moving the full tile size so I get smooth movemen. The problem I have is that when I move, the screen doesn't load the new tiles in the edges that i'm moving towards so the edges end up a white space until i've completed the full animation. I'll link my code and hopefully someone can help me :) TILESIZE = 32 MAP_WIDTH = 25 MAP_HEIGHT = 25 class Player(pygame.sprite.Sprite): def __init__(self, color, width, height): # Call the parent class (Sprite) constructor super().__init__() self.name = "Player" self.width = width self.height = height self.image = pygame.Surface([width, height]) self.image.fill(color) self.rect = self.image.get_rect() self.rect.x = int(TILESIZE * (MAP_WIDTH / 2)) - TILESIZE / 2 self.rect.y = int(TILESIZE * (MAP_HEIGHT / 2)) - TILESIZE / 2 class World: def __init__(self): self.shiftX = 0 self.shiftY = 0 self.tile_map = [ [DIRT for w in range(MAP_WIDTH)] for h in range(MAP_HEIGHT)] for row in range(MAP_HEIGHT): for column in range(MAP_WIDTH): try: if real_map[row + self.shiftY][column + self.shiftX] == 0: tile = DIRT elif real_map[row + self.shiftY][column + self.shiftX] == 1: tile = GRASS elif real_map[row + self.shiftY][column + self.shiftX] == 2: tile = WATER else: tile = DIRT self.tile_map[row][column] = tile except: self.tile_map[row][column] = WATER def shiftWorld(self): for row in range(MAP_HEIGHT): for column in range(MAP_WIDTH): try: if real_map[row + self.shiftY][column + self.shiftX] == 0: tile = DIRT elif real_map[row + self.shiftY][column + self.shiftX] == 1: tile = GRASS elif real_map[row + self.shiftY][column + self.shiftX] == 2: tile = WATER else: tile = DIRT self.tile_map[row][column] = tile except: self.tile_map[row][column] = WATER def okToMove(self, key): if key[K_w]: if self.tile_map[int(MAP_WIDTH/2 - 1)][int(MAP_HEIGHT/2)] != 2: return True elif key[K_s]: if self.tile_map[int(MAP_WIDTH/2 + 1)][int(MAP_HEIGHT/2)] != 2: return True elif key[K_a]: if self.tile_map[int(MAP_WIDTH/2)][int(MAP_HEIGHT/2) - 1] != 2: return True elif key[K_d]: if self.tile_map[int(MAP_WIDTH/2)][int(MAP_HEIGHT/2) + 1] != 2: return True def start_game(): pygame.init() clock = pygame.time.Clock() #HÄR KAN VI MÅLA UPP MER #SCREEN = pygame.display.set_mode((MAP_WIDTH*TILESIZE, MAP_HEIGHT*TILESIZE)) world = World() SCREEN = pygame.display.set_mode((TILESIZE * (MAP_WIDTH-2), TILESIZE * (MAP_HEIGHT-4))) running = True player = Player(BLACK, 32, 32) sprites = pygame.sprite.Group() sprites.add(player) movement = 0 offsetY = 0 offsetX = 0 animation_north = False animation_south = False animation_west = False animation_east = False while running: for event in pygame.event.get(): if event.type==QUIT: pygame.quit() sys.exit() elif event.type == pygame.KEYDOWN: #Get keyinput and do whatever needs to be done key = pygame.key.get_pressed() if key[K_ESCAPE]: pygame.quit() sys.exit() if animation_east or animation_north or animation_south or animation_west: pass else: if key[K_w]: okToMove = world.okToMove(key) if okToMove == True: animation_north = True else: pass elif key[K_a]: okToMove = world.okToMove(key) if okToMove == True: animation_west = True elif key[K_s]: okToMove = world.okToMove(key) if okToMove == True: animation_south = True elif key[K_d]: okToMove = world.okToMove(key) if okToMove == True: animation_east = True if animation_north == True: if movement == 32: movement = 0 world.shiftY -= 1 world.shiftWorld() offsetY = 0 animation_north = False else: offsetY += 4 movement += 4 if animation_south == True: if movement == 32: movement = 0 world.shiftY += 1 world.shiftWorld() offsetY = 0 animation_south = False intY = 0 else: offsetY -= 4 movement += 4 if animation_west == True: if movement == 32: movement = 0 world.shiftX -= 1 world.shiftWorld() offsetX = 0 animation_west = False else: offsetX += 4 movement += 4 if animation_east == True: if movement == 32: world.shiftX += 1 world.shiftWorld() movement = 0 offsetX = 0 animation_east = False else: offsetX -= 4 movement += 4 SCREEN.fill(WHITE) for row in range(MAP_HEIGHT): for column in range(MAP_WIDTH): SCREEN.blit(textures[world.tile_map[row][column]], (column*TILESIZE + offsetX, row*TILESIZE + offsetY)) sprites.draw(SCREEN) pygame.display.update() pygame.display.flip() clock.tick(60) start_game()
I am writing a similar game and I will share my logic with you. my blocks are 32x32 so each block is 32 pixesl. The outer border is the sprites screen and the inner square is the monitor. You always have one sprite extra on all sides of the screen. now if you count the pixel movement on any side of the screen it's easy for you to keep track of when you need to draw the next row or column of sprites but not that they are always DRAWN OFF SCREEN. if my pixel movement is -8 (left movement) I draw a column of sprites on the right side just on the border os the screen but OUTSIDE the visible area. Same goes for the other side. Here is some code from my program. This is the sprite adding code. def add_sprites(self): """sprites are added to the group which appear on screen right. the column number is the value in ColDrawn. We selct columns from the list according to this value. Once the end of the column list is reached we start again from the first one. We cycle thru the list depending on the NumCycle[0] value.""" if self.ColDrawn < self.Columns_in_Dungeon - 1: self.ColDrawn += 1 else: # all the columns drawn so increment the flag self.ColDrawn = 0 self.NumCycle[1] += 1 if self.NumCycle[1] >= self.NumCycle[0]: # if the flag is equal to the number of cycles the screen is scrolled then set numcycle[2] to True self.NumCycle[2] = True else: # screen can be scrolled spritecol = self.all_wall_sprite_columns_list[self.ColDrawn] self.wallspritegroup.add(spritecol) # add column of sprites to the sprite group return and here is the sprite removing code. def remove_sprites(self): """sprites are removed from the group as they exit from screen left.""" for sprt in self.wallspritegroup: # remove_basic sprites that move_basic off screen on left if sprt.rect.x <= -48: sprt.rect.x = self.screenw # reset the x position and sprt.kill() #spritegrp.remove_basic(sprt) # remove_basic the sprite from the sprite group return The code is quite easy to follow as I have commented them. Hope this helps.
Scrolling camera
I've been tinkering with a scrolling camera that follows the player around and have got it to follow the player. The problem is that it moves slower than the player and because of this the player wont stay in the middle of the screen. I believe the problem is in the offset (cameraX) and have tried a few different values but haven't found any that work. Code: import pygame, sys, time, random, math from pygame.locals import * BACKGROUNDCOLOR = (255, 255, 255) WINDOWW = 800 WINDOWH = 600 PLAYERW = 66 PLAYERH = 22 FPS = 60 MOVESPEED = 3 YACCEL = 0.13 GRAVITY = 2 BLOCKSIZE = 30 pygame.init() screen = pygame.display.set_mode((WINDOWW, WINDOWH), 0, 32) mainClock = pygame.time.Clock() testLevel = [ (1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,), (1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,), (1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,), (1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,), (1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,), (1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,), (1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,), (1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,), (1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,), (1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,), (1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,), (1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,), (1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,), (1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,), (1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,), (1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,), (1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,), (1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,), (1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,), (1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,)] def createblock(length, height, color): tmpblock = pygame.Surface((length, height)) tmpblock.fill(color) tmpblock.convert() return tmpblock def terminate(): # Used to shut down the software pygame.quit() sys.exit() def add_level(lvl, bSize): # Creates the level based on a map (lvl) and the size of blocks bList = [] # List of every block bListDisp = [] # List of every block to display bTypeList = [] # List with corresponding type of block(wall, air, etc.) for y in range(len(lvl)): for x in range(len(lvl[0])): if lvl[y][x] == 0: # If the block type on lvl[y][x] is '0', write "air" down in the type list bTypeList.append("air") elif lvl[y][x] == 1: # If the block type on lvl[y][x] is '1', write "wall" down in the type list bTypeList.append("solid") bList.append(pygame.Rect((bSize * x), (bSize * y), bSize, bSize)) #Append every block that is registered bListDisp.append(pygame.Rect((bSize * x), (bSize * y), bSize, bSize)) #Append every block to display that is registered return bList, bListDisp, bTypeList player = pygame.Rect((WINDOWW/2), (WINDOWH - BLOCKSIZE*3), PLAYERW, PLAYERH) wallblock = createblock(BLOCKSIZE, BLOCKSIZE,(20,0,50)) lastTime = pygame.time.get_ticks() isGrounded = False vx = 0 vy = 0 allLevels = [testLevel] # A list containing all lvls(only one for now) maxLevel = len(allLevels) # Checks which level is the last currLevel = allLevels[0] # Current level(start with the first lvl) blockList, blockListDisp, blockTypeList = add_level(currLevel, BLOCKSIZE) # A list with every block and another list with the blocks types thrusters = True jumping = False falling = True while True: """COLLISION""" collision = False for i in range(len(blockTypeList)): if blockTypeList[i] == "solid": if player.colliderect(blockList[i]): collision = True if vx > 0 and not falling: player.right = blockListDisp[i].left vx = 0 print('Collide Right') if vx < 0 and not falling: player.left = blockListDisp[i].right vx = 0 print('Collide Left') if vy > 0: player.bottom = blockListDisp[i].top isGrounded = True falling = False vy = 0 print('Collide Bottom') if vy < 0: player.top = blockListDisp[i].bottom vy = 0 print('Collide Top') else: player.bottom += 1 if player.colliderect(blockList[i]): collision = True #isGrounded = True #falling = False player.bottom -= 1 if not collision: falling = True isGrounded = False # Input pressedKeys = pygame.key.get_pressed() # Checks which keys are being pressed timeDiff = pygame.time.get_ticks() - lastTime # Calculates time difference lastTime += timeDiff # Last time checked reset to current time # Shut-down if the ESC-key is pressed or the window is "crossed down" for event in pygame.event.get(): if event.type == QUIT or event.type == KEYDOWN and event.key == K_ESCAPE: terminate() """X-axis control""" if pressedKeys[ord('a')]: vx = -MOVESPEED if pressedKeys[ord('d')]: vx = MOVESPEED if not pressedKeys[ord('d')] and not pressedKeys[ord('a')]: vx = 0 """Y-axis control""" # Controls for jumping if pressedKeys[ord('w')] and thrusters == True: vy -= YACCEL * timeDiff; # Accelerate along the y-xis when "jumping", but not above/below max speed if vy <= -4: vy = -4 isGrounded = False # You are airborne jumping = True # You are jumping if event.type == KEYUP: # If you let go of the "jump"-button, stop jumping if event.key == ord('w') and vy < 0 and not isGrounded: jumping = False falling = True player.x += vx player.y += vy cameraX = player.x - WINDOWW/2 # Gravity if not isGrounded or falling: vy += 0.3 if vy > 80: vy = 80 screen.fill(BACKGROUNDCOLOR) for i in range(len(blockTypeList)): if blockTypeList[i] == "solid": screen.blit(wallblock, (blockListDisp[i].x-cameraX, blockListDisp[i].y)) #blit the wall-block graphics pygame.draw.rect(screen, (0, 0, 0), player) pygame.display.update() mainClock.tick(FPS)
You don't apply the camera-offset to the player itself, only to the wallblocks. So change pygame.draw.rect(screen, (0, 0, 0), player) to pygame.draw.rect(screen, (0, 0, 0), player.move(-cameraX, 0)) Some more notes: Using three lists (blockList, blockListDisp, blockTypeList) to keep track of your level is way to complex, use a single list :-) Change your add_level to: # use a dict to keep track of possible level blocks, so adding new ones becomes simple types = {0: "air", 1: "solid"} def add_level(lvl, bSize): # Creates the level based on a map (lvl) and the size of blocks for y in range(len(lvl)): for x in range(len(lvl[0])): # no more if/elif yield types[lvl[y][x]], pygame.Rect((bSize * x), (bSize * y), bSize, bSize) your lists to: blocks = list(add_level(currLevel, BLOCKSIZE)) # a single list which holds the type and rect for each block of the level Then your collision detection can look like this: while True: """COLLISION""" collision = False for type, rect in blocks: # list contains a tuple of type, rect if type == "solid": if player.colliderect(rect): collision = True if vx > 0 and not falling: player.right = rect.left # now you can always use the rect directly instead of accesing other lists vx = 0 print('Collide Right') ... Also, the drawing code becomes simpler: for type, rect in blocks: if type == "solid": screen.blit(wallblock, rect.move(-cameraX, 0)) #blit the wall-block graphics pygame.draw.rect(screen, (0, 0, 0), player.move(-cameraX, 0)) In the long run, you may want to use a class instead of a tuple, but that's another topic.