This question already has an answer here:
How can I move the ball instead of leaving a trail all over the screen in pygame?
(1 answer)
Closed 1 year ago.
I am trying to make blocks fall to fall to the ground, but sadly the old sprites won't disappear. I have tried to move sprites with .move_ip, but then I get an error message, saying that my rect doesn't have attribute 'move_ip'. Also a little bit non-related, but how do I make the blocks stack on top of eachother? I suppose it's something to do with worldy?
import pygame
import random
pygame.init()
WHITE = (255, 255, 255)
worldx = 590
worldy = 770
screen = pygame.display.set_mode([worldx, worldy])
screen.fill([0,0,0])
gravity = 1
class Block1(pygame.sprite.Sprite):
def __init__(self,x,y):
super().__init__()
self.image = pygame.image.load("img_12.png")
self.rect = self.image.get_rect(topleft = (x,y))
self.x = x
self.y = y
self.speed_y = 0
def update(self):
self.speed_y += gravity
self.y += self.speed_y
self.rect.y = self.y
if self.rect.y >= worldy:
self.speed_y = 0
x = 0
y = 1
dt = 0
timer = 1
all_sprites_list = pygame.sprite.Group()
stopped_blocks = pygame.sprite.Group()
clock = pygame.time.Clock()
score = 0
block = Block1
mäng_töötab = True
while mäng_töötab:
for event in pygame.event.get():
if event.type == pygame.QUIT:
mäng_töötab = False
timer -= dt
if timer <= 0:
x = random.randrange(0, 18) * 32
all_sprites_list.add(block(x,y))
timer = 1
all_sprites_list.draw(screen)
all_sprites_list.update()
pygame.display.flip()
dt = clock.tick(60) / 1000
pygame.quit()
You have to clear the display in every frame:
while mäng_töötab:
for event in pygame.event.get():
if event.type == pygame.QUIT:
mäng_töötab = False
timer -= dt
if timer <= 0:
x = random.randrange(0, 18) * 32
all_sprites_list.add(block(x,y))
timer = 1
screen.fill(0) # <---
all_sprites_list.draw(screen)
all_sprites_list.update()
pygame.display.flip()
dt = clock.tick(60) / 1000
The typical PyGame application loop has to:
limit the frames per second to limit CPU usage with pygame.time.Clock.tick
handle the events by calling either pygame.event.pump() or pygame.event.get().
update the game states and positions of objects dependent on the input events and time (respectively frames)
clear the entire display or draw the background
draw the entire scene (blit all the objects)
update the display by calling either pygame.display.update() or pygame.display.flip()
Related
I'm trying to make a flappy bird AI using OOP, so far everything seem to be working fine except for two problems. First my bird is flapping way to quickly. I created a user event and in the timer I put 200 milliseconds:
birdflap = pygame.USEREVENT
pygame.time.set_timer(birdflap, 200)
but for some reason, the wings are still flapping like crazy and I can't seem to understand what's causing it to do so. Secondly I had a problem with the bird rotating when it falls down. I made a function in my bird class called 'move' that creates gravity for the bird and causes it to turn using rotozoom in pygame to make it turn as it falls down.
def move(self):
self.bird_movement = 8
self.bird_movement += self.gravity
self.bird_rect.centery += self.bird_movement
pygame.transform.rotozoom(self.img[self.bird_index], -self.bird_movement * 3, 1)
The problem is that once the game starts, it falls but doesn't turn. I honestly don't know where to start with solving both of these issues. My full code is down below if anybody wanted to see what I have so far.
import pygame
import neat
import time
import os
import random
import sys
pygame.init()
clock = pygame.time.Clock()
# VARIABLES THAT DEFINE SCREEN SIZE
screen_width = 500
screen_height = 800
# CLOCK TO SET FRAME RATE
clock = pygame.time.Clock()
# VARIABLES THAT CONTAIN GAME IMAGES
bird_imgs = [pygame.transform.scale2x(pygame.image.load(os.path.join('assets', 'yellowbird-upflap.png'))), pygame.transform.scale2x(pygame.image.load(
os.path.join('assets', 'yellowbird-midflap.png'))), pygame.transform.scale2x(pygame.image.load(os.path.join('assets', 'yellowbird-downflap.png')))]
bg_img = pygame.transform.scale2x(pygame.image.load(os.path.join('assets', 'background-day.png' )))
# TIMER FOR BIRD FLAP IMAGES
birdflap = pygame.USEREVENT
pygame.time.set_timer(birdflap, 200)
class Bird:
img = bird_imgs
gravity = 0.25
def __init__(self, x, y):
self.x = x
self.y = y
self.bird_movement = 0
self.bird_index = 0
self.bird_rect = self.img[self.bird_index].get_rect(center = (self.x, self.y))
def bird_animation(self, win):
if self.bird_index < 2:
self.bird_index += 1
else:
self.bird_index = 0
win.blit(self.img[self.bird_index], self.bird_rect)
def move(self):
self.bird_movement = 8
self.bird_movement += self.gravity
self.bird_rect.centery += self.bird_movement
pygame.transform.rotozoom(self.img[self.bird_index], -self.bird_movement * 3, 1)
# FUNCTION TO DRAW THE WINDOW
def draw_window(win, bird):
win.blit(bg_img, (0,0))
bird.bird_animation(win)
pygame.display.update()
# MAIN FUNCTION OF OUR GAME
def main():
win = pygame.display.set_mode((screen_width, screen_height))
bird = Bird(200, 200)
run = True
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if event.type == birdflap:
bird.bird_animation(win)
bird.move()
draw_window(win, bird)
clock.tick(60)
pygame.quit()
sys.exit()
main()
I tried using other modules in pygame, but that doesn't seem to solve my issue either. Right now I'm really lost.
The 1st problem is that bird_animation is called in draw_window so the bird is animated all over the time. The 2nd problem is that pygame.transform.rotozoom returns a new but rotated surface (see How do I rotate an image around its center using PyGame?). The method move has to create an image, that is used in an draw method:
class Bird:
img = bird_imgs
gravity = 0.25
def __init__(self, x, y):
self.x = x
self.y = y
self.bird_movement = 0
self.bird_index = 0
self.image = self.img[self.bird_index]
self.rect = self.image.get_rect(center = (self.x, self.y))
def bird_animation(self):
if self.bird_index < 2:
self.bird_index += 1
else:
self.bird_index = 0
def move(self):
self.bird_movement = 8
self.bird_movement += self.gravity
self.y += self.bird_movement
self.image = pygame.transform.rotozoom(self.img[self.bird_index], -self.bird_movement * 3, 1)
self.rect = self.image.get_rect(center = (self.x, self.y))
def draw(self, win)
win.blit(self.img[self.bird_index], self.bird_rect)
# FUNCTION TO DRAW THE WINDOW
def draw_window(win, bird):
win.blit(bg_img, (0,0))
bird.draw(win)
pygame.display.update()
def main():
win = pygame.display.set_mode((screen_width, screen_height))
bird = Bird(200, 200)
run = True
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if event.type == birdflap:
bird.bird_animation()
bird.move()
draw_window(win, bird)
clock.tick(60)
pygame.quit()
sys.exit()
main()
So I used the collidepoint function to test out whether or not my mouse is interacting or can interact with the images on the surface Surface but the variable mouse_pos does give out a position yet the mouse cannot ever collide with the object (see A is always false rather than true when the mouse hit the object). How do I solve this
Code:
import pygame
from sys import exit
pygame.init()
widthscreen = 1440 #middle 720
heightscreen = 790 #middle 395
w_surface = 800
h_surface = 500
midalignX_lg = (widthscreen-w_surface)/2
midalignY_lg = (heightscreen-h_surface)/2
#blue = player
#yellow = barrier
screen = pygame.display.set_mode((widthscreen,heightscreen))
pygame.display.set_caption("Collision Game")
clock = pygame.time.Clock()
test_font = pygame.font.Font('font/Pixeltype.ttf', 45)
surface = pygame.Surface((w_surface,h_surface))
surface.fill('Light Yellow')
blue_b = pygame.image.load('images/blue.png').convert_alpha()
blue_b = pygame.transform.scale(blue_b,(35,35))
yellow_b = pygame.image.load('images/yellow.png').convert_alpha()
yellow_b = pygame.transform.scale(yellow_b,(35,35))
text_surface = test_font.render('Ball Option:', True, 'White')
barrier_1_x = 0
barrier_1_surf = pygame.image.load('images/yellow.png').convert_alpha()
barrier_1_surf = pygame.transform.scale(barrier_1_surf,(35,35))
barrier_1_rect = barrier_1_surf.get_rect(center = (100, 350))
player_surf = pygame.image.load('images/blue.png').convert_alpha()
player_surf = pygame.transform.scale(player_surf,(35,35))
player_rect = player_surf.get_rect(center = (0,350))
while True:
#elements & update
#event loop
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
exit()
screen.blit(surface, (midalignX_lg,midalignY_lg))
screen.blit(blue_b,(150,250))
screen.blit(yellow_b, (150,300))
screen.blit(text_surface,(150, 200))
#barrier_1_x += 3
#if barrier_1_x > 800: barrier_1_x = 0
#barrier_1_rect.x += 3
#if barrier_1_rect.x > 800: barrier_1_rect.x = 0
barrier_1_rect.x += 2
if barrier_1_rect.right >= 820: barrier_1_rect.left = -10
player_rect.x += 3
if player_rect.right >= 820: player_rect.left = -10
surface = pygame.Surface((w_surface,h_surface))
surface.fill('Light Yellow')
surface.blit(barrier_1_surf, barrier_1_rect)
surface.blit(player_surf, player_rect)
'''if player_rect.colliderect(barrier_1_rect):
print('collision')'''
A = False;
mouse_pos = pygame.mouse.get_pos()
if player_rect.collidepoint(mouse_pos):
A = True
print(A)
pygame.display.update()
clock.tick(60)
I am not sure what else to do. i think it may be something wrong with the layering of the surface?
You are not drawing the objects on the screen, but on the surface. Therefore the coordinates of player_rect are relative to the surface and you also have to calculate the mouse position relative to the surface. The top left coordinate of the surface is (midalignX_lg, midalignY_lg):
while True:
# [...]
mouse_pos = pygame.mouse.get_pos()
rel_x = mouse_pos[0] - midalignX_lg
rel_y = mouse_pos[1] - midalignY_lg
if player_rect.collidepoint(rel_x, rel_y):
print("hit")
This question already has answers here:
How does this algorithm make the character jump in pygame?
(1 answer)
How can I do a double jump in pygame?
(1 answer)
jumping too fast?
(1 answer)
Closed 1 year ago.
I'm doing own game with the help Python. I need to make a jumping to my sprite can jump. However, my sprite can't jump. If my program had 1 and more mistakes, my game wouldn't able to work. Please, find mistake to my sprite can jump. Here's my program:
from pygame.locals import *
import pygame
import os
import random
WIDTH = 800
HEIGHT = 600
FPS = 60
usr_y = 400
# Задаем цвета
GREEN = (75, 0, 130)
BLUE = (255, 20, 147)
# Создаем игру и окно
pygame.init()
pygame.mixer.init()
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Mini-games by Latypov Vildan 10'a' Class")
clock = pygame.time.Clock()
icon = pygame.image.load('icon.png')
pygame.display.set_icon(icon)
class Player(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface((50, 40))
self.image.fill(GREEN)
self.rect = self.image.get_rect()
self.rect.centerx = WIDTH - 360
self.rect.centery = HEIGHT - 200
def update(self):
self.speedx = 0
keystate = pygame.key.get_pressed()
if keystate[pygame.K_LEFT]:
self.speedx = -8
if keystate[pygame.K_RIGHT]:
self.speedx = 8
self.rect.x += self.speedx
if self.rect.right > WIDTH:
self.rect.right = WIDTH
if self.rect.left < 0:
self.rect.left = 0
all_sprites = pygame.sprite.Group()
player = Player()
all_sprites.add(player)
def print_text(message, x, y, font_color = (0, 0, 0), font_type = 'фыы.ttf', font_size = 30):
font_type = pygame.font.Font(font_type, font_size)
text = font_type.render(message, True, font_color)
screen.blit(text, (x, y))
print_text('Hi', 250, 250)
jump = False
counter = -30
def make():
global usr_y, counter, jump
if counter >= -30:
usr_y-= counter / 2.5
counter -= 1
else:
counter = 30
jump = False
# Цикл игры
running = True
while running:
# Держим цикл на правильной скорости
clock.tick(FPS)
# Ввод процесса (события)
for event in pygame.event.get():
# check for closing window
if event.type == KEYDOWN:
if event.key == K_ESCAPE:
running = False
elif event.type == QUIT:
running = False
elif event.key == K_SPACE:
jump = True
if jump:
make()
# Обновление
all_sprites.update()
# Рендеринг
screen.fill(BLUE)
all_sprites.draw(screen)
# После отрисовки всего, переворачиваем экран
pygame.display.flip()
pygame.quit()
It is a matter of Indentation. You have to do the jump in the application loop. The state jump is set once when the event occurs. However, the jumping needs to be animated in consecutive frames.
Your event loop is mixed up and you must change the coordinate of the player object instead of usr_y:
class Player(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface((50, 40))
self.image.fill(GREEN)
self.rect = self.image.get_rect()
self.rect.centerx = WIDTH - 360
self.rect.centery = HEIGHT - 200
self.y = self.rect.y # <--- floating point y coordinate
def update(self):
self.rect.y = round(self.y) # <--- update player rectangle
self.speedx = 0
# [...]
jump = False
counter = 30
def make():
global counter, jump
if counter >= -30:
player.y -= counter / 2.5 # <--- change player.y
counter -= 1
else:
counter = 30
jump = False
running = True
while running:
clock.tick(FPS)
for event in pygame.event.get():
if event.type == QUIT:
running = False
elif event.type == KEYDOWN:
if event.key == K_ESCAPE:
running = False
elif event.key == K_SPACE:
jump = True
# INDENTATION
#<----------|
if jump:
make()
# [...]
I am working on a very rough topdown 2d adventure game after skimming around the pygame documentation. However, I have hit a bit of a roadblock after not being able to find anything on a camera system and found that most tutorials for a camera are 5+ years old and don't seem to work anymore. Can anybody help me build a camera?
This is my main executed script
import sys, pygame
from PlayerObject import Player
pygame.init()
screen_height = 180
screen_width = 320
map_height = 1080
map_width = 1920
num_objects = 5
screen = pygame.display.set_mode((screen_width, screen_height))
player_image = pygame.image.load('models/hero.bmp').convert()
background = pygame.image.load('models/lobby.bmp').convert()
screen.blit(background, (0, 0))
objects = []
# randomly generates 5 entities with the 1st one being the controlled character
for i in range(num_objects):
o = Player(player_image, random.randint(0, screen_width), random.randint(0, screen_height), 10)
objects.append(o)
while 1:
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
screen.blit(background, objects[0].pos, objects[0].pos)
objects[0].move_left()
screen.blit(objects[0].image, objects[0].pos)
if keys[pygame.K_RIGHT]:
screen.blit(background, objects[0].pos, objects[0].pos)
objects[0].move_right()
screen.blit(objects[0].image, objects[0].pos)
if keys[pygame.K_UP]:
screen.blit(background, objects[0].pos, objects[0].pos)
objects[0].move_up()
screen.blit(objects[0].image, objects[0].pos)
if keys[pygame.K_DOWN]:
screen.blit(background, objects[0].pos, objects[0].pos)
objects[0].move_down()
screen.blit(objects[0].image, objects[0].pos)
screen.blit(background)
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
for o in objects:
screen.blit(background, o.pos, o.pos)
for num in range(num_objects - 1):
objects[num + 1].rand_move()
for o in objects:
screen.blit(o.image, o.pos)
pygame.display.update()
pygame.time.delay(100)
This is my Player class
import random
map_height = 180
map_width = 320
class Player:
def __init__(self, image, width, height, speed):
self.speed = speed
self.image = image
self.pos = image.get_rect().move(width, height)
self.image = image
def set_speed(self, speed):
self.speed = speed
def rand_move(self):
x = random.randint(-self.speed, self.speed)
y = random.randint(-self.speed, self.speed)
self.pos = self.pos.move(x, y)
# keeps player in boundaries
if self.pos.left < 0:
self.pos.left = 0
if self.pos.right > map_width:
self.pos.right = map_width
if self.pos.top < 0:
self.pos.top = 0
if self.pos.bottom > map_height:
self.pos.bottom = map_height
def move_left(self):
speed = self.speed
self.pos = self.pos.move(-speed, 0)
if self.pos.left < 0:
self.pos.left = 0
def move_right(self):
speed = self.speed
self.pos = self.pos.move(speed, 0)
if self.pos.right > map_width:
self.pos.right = map_width
def move_up(self):
speed = self.speed
self.pos = self.pos.move(0, -speed)
if self.pos.top < 0:
self.pos.top = 0
def move_down(self):
speed = self.speed
self.pos = self.pos.move(0, speed)
if self.pos.bottom > map_height:
self.pos.bottom = map_height
Your basic misunderstanding, is that you try to draw the background at the position of an object, then you move the object and blit it finally on its new position. That all is not necessary.
In common the entire scene is drawn in each frame in the main application loop. It is sufficient to draw the background to the entire window and blit each object on top of it. Note, you do not see the changes of the window surface immediately. The changes become visible, when the display is updated by pygame.display.update() or pygame.display.flip():
The main application loop has to:
handle the events by either pygame.event.pump() or pygame.event.get().
update the game states and positions of objects dependent on the input events and time (respectively frames)
clear the entire display or draw the background
draw the entire scene (blit all the objects)
update the display by either pygame.display.update() or pygame.display.flip()
e.g.:
while 1:
# handle events
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
# update objects (depends on input events and frames)
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
objects[0].move_left()
if keys[pygame.K_RIGHT]:
objects[0].move_right()
if keys[pygame.K_UP]:
objects[0].move_up()
if keys[pygame.K_DOWN]:
objects[0].move_down()
for num in range(num_objects - 1):
objects[num + 1].rand_move()
# draw background
screen.blit(background, (0, 0))
# draw scene
for o in objects:
screen.blit(o.image, o.pos)
# update dispaly
pygame.display.update()
pygame.time.delay(100)
Minimal example: repl.it/#Rabbid76/PyGame-MinimalApplicationLoop
I'm making a "duck hunt" game in pygame. I have everything working, my sprites move and respawn when needed, cursor is a crosshair with sound when clicked etc. The issue I'm having is trying to add points when the mouse is click on a duck. Any idea how I would do this? Posted all of the code, its a bit of a mess until I get thank working, check the main loop specifically. Thanks.
import pygame
import random
import duck_code
# Define some colors
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
RED = (255, 0, 0)
BLUE = (0, 0, 255)
GREEN = (0, 255, 0)
DUCK_BACK = (59, 202, 255)
class Player(pygame.sprite.Sprite):
""" The class is the player-controlled sprite. """
# -- Methods
def __init__(self, x, y, filename):
"""Constructor function"""
# Call the parent's constructor
super().__init__()
# Set height, width
self.image = pygame.Surface([15, 15])
self.image.fill(BLACK)
self.image = pygame.image.load(filename).convert()
# Make our top-left corner the passed-in location.
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
# -- Attributes
# Set speed vector
self.change_x = 0
self.change_y = 0
def changespeed(self, x, y):
""" Change the speed of the player"""
self.change_x += x
self.change_y += y
def update(self):
""" Find a new position for the player"""
self.rect.x += self.change_x
self.rect.y += self.change_y
# boarders for walls, reset player, play bump sound
if self.rect.x in range(1060, 1085):
self.rect.x -= 25
if self.rect.x in range(-5, 0):
self.rect.x += 25
if self.rect.y in range(-5, 0):
self.rect.y += 25
if self.rect.y in range(480, 505):
self.rect.y -= 25
# Initialize Pygame
# Loading sounds
pygame.init()
game_background = pygame.image.load("game_background.jpg")
duck_hit = pygame.mixer.Sound("duck_hit.wav")
player_click = pygame.mixer.Sound("shot_gun.ogg")
# Set the height and width of the screen
screen_width = 1280
screen_height = 1024
screen = pygame.display.set_mode([screen_width, screen_height])
# Starting score and font settings
font = pygame.font.Font(None, 36)
score = 0
# This is a list of every sprite.
all_sprites_list = pygame.sprite.Group()
duck_list = pygame.sprite.Group()
duck_hit_list = pygame.sprite.Group()
"""DUCKS"""
for i in range(5):
# This represents a block
ducks = duck_code.Duck("duck1.png")
ducks.rect.x = random.randrange(screen_width)
ducks.rect.y = random.randrange(50, 350)
# Add the block to the list of objects
duck_list.add(ducks)
all_sprites_list.add(ducks)
"""PLAYER"""
player_image = pygame.image.load("crosshair.png")
player_image.set_colorkey(WHITE)
# Loop until the user clicks the close button.
done = False
# Used to manage how fast the screen updates
clock = pygame.time.Clock()
score = 0
# Hide the mouse cursor
pygame.mouse.set_visible(0)
# -------- Main Program Loop -----------
while not done:
mouse = pygame.mouse.get_pos()
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
blocks_hit_list = pygame.sprite.spritecollide(mouse, duck_list, True)
score += 100
print(score)
player_click.play()
# --- Game logic should go here
# --- Screen-clearing code goes here
# Here, we clear the screen to white. Don't put other drawing commands
# above this, or they will be erased with this command.
# If you want a background image, replace this clear with blit'ing the
# background image.
screen.blit(game_background, [0, 0])
player_position = pygame.mouse.get_pos()
x = player_position[0]
y = player_position[1]
screen.blit(player_image, [x, y])
pos = pygame.mouse.get_pos()
pressed1, pressed2, pressed3 = pygame.mouse.get_pressed()
# Check if the rect collided with the mouse pos
# and if the left mouse button was pressed.
all_sprites_list.draw(screen)
duck_list.update()
# Showing scoreboard
text = font.render("Score: " + str(score), True, WHITE)
screen.blit(text, [10, 10])
# Go ahead and update the screen with what we've drawn.
pygame.display.flip()
# Limit to 60 frames per second
clock.tick(60)
pygame.quit()
pygame.sprite.spritecollide only works with a sprite as the first argument and a sprite group as the second argument. To check if the mouse collides with a duck, you can iterate over the duck_list with a for loop and call the collidepoint method of the current duck's rect:
if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
for duck in duck_list:
if duck.rect.collidepoint(event.pos): # event.pos is the mouse position.
score += 100