Before this I used the code to say 'every button press it moves' but now I have changed it to 'when you press the button it moves in one direction until further instructions', but now the colliderect doesn't work. It worked before, and I'm still new to pygame. I have found a few similar issues but I think I've done what the people asking the questions have done. Any help at all is accepted.
import pygame, sys, random
from pygame.locals import *
from time import sleep
pygame.init()
def render():
windowSurface.fill(black)
player = pygame.Rect(225 + xmod,450 - ymod,30,30)
pygame.draw.rect(windowSurface,white,player)
pygame.draw.rect(windowSurface,white,wall_1)
pygame.draw.rect(windowSurface,white,wall_2)
pygame.display.update()
black = (0,0,0)
white = (255,255,255)
windowSurface = pygame.display.set_mode((500, 500),0,32)
windowSurface.fill(black)
xmod = 0
ymod = 0
direction = 'none'
player = pygame.Rect(225 + xmod,450 - ymod,30,30)
wall_1 = pygame.Rect(0,225,250,50)
wall_2 = pygame.Rect(300,250,200,50)
render()
while True:
render()
for event in pygame.event.get():
if event.type == KEYDOWN:
if event.key == K_LEFT:
direction = 'left'
if event.key == K_RIGHT:
direction = 'right'
if event.key == K_UP:
direction = 'up'
if event.key == K_DOWN:
direction = 'down'
if event.type == QUIT:
pygame.quit()
sys.exit()
if player.colliderect(wall_1) or player.colliderect(wall_2):
xmod = 0
ymod = 0
player = pygame.Rect(225 + xmod,450 - ymod,30,30)
render()
print('again')
if direction == 'left':
xmod -= 1
sleep(0.004)
if direction == 'right':
xmod += 1
sleep(0.004)
if direction == 'up':
ymod += 1
sleep(0.004)
if direction == 'down':
ymod -= 1
sleep(0.004)
You never update the global player variable, so it stays at its original coordinates. In the render function you create a new rect and assign it to a local player variable, but it is not the same as the global player which you use for the collision detection.
I suggest adding variables for the velocity speed_x, speed_y and adding them to the player.x and .y attributes every frame to move the rect directly.
The local player rect in the render function can be removed.
import sys
import pygame
from pygame.locals import *
pygame.init()
def render():
windowSurface.fill(black)
pygame.draw.rect(windowSurface, white, wall_1)
pygame.draw.rect(windowSurface, white, wall_2)
pygame.draw.rect(windowSurface, white, player)
pygame.display.update()
black = (0,0,0)
white = (255,255,255)
windowSurface = pygame.display.set_mode((500, 500),0,32)
clock = pygame.time.Clock() # A clock to limit the frame rate.
player = pygame.Rect(225, 450, 30, 30)
wall_1 = pygame.Rect(0,225,250,50)
wall_2 = pygame.Rect(300,250,200,50)
speed_x = 0
speed_y = 0
while True:
# Handle events.
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
elif event.type == KEYDOWN:
if event.key == K_LEFT:
speed_x = -5
speed_y = 0
elif event.key == K_RIGHT:
speed_x = 5
speed_y = 0
elif event.key == K_UP:
speed_y = -5
speed_x = 0
elif event.key == K_DOWN:
speed_y = 5
speed_x = 0
# Add the speed to the x and y attributes to move the rect.
player.x += speed_x
player.y += speed_y
# Game logic.
if player.colliderect(wall_1) or player.colliderect(wall_2):
player = pygame.Rect(225, 450, 30, 30)
print('again')
# Render everything.
render()
clock.tick(60) # Limit the frame rate to 60 FPS.
Related
For a school project I am building a recreation of Among Us in python with Pygame. I have already set up all the server and client side code and that's all working fine. I'm now in the process of making the camera follow the player. Only I can't get it to work.
My idea was: when a player moves, everything in his surroundings has to move in the opposite direction. But when you have a multiplayer game this doesn't work. Because then the other player moves as well which breaks the system.
If anyone has any idea how to make such a code, please let me know.
Thank you in advance
You don't have to move the background and object rects around the player, you can just move the player around and have a scroll offset value that keeps track of how much the blitted objects have to be offset. You don't apply the scroll value to the rect position because the rect position isn't relative to the window like the blit objects are. Here is an example of how you could achieve this.
import pygame, sys
clock = pygame.time.Clock()
from pygame.locals import *
pygame.init()
pygame.display.set_caption("Scrolling example")
WINDOW_SIZE = (600, 400)
screen = pygame.display.set_mode(WINDOW_SIZE, 0, 32)
scroll = [0, 0]
player = pygame.Rect(100, 100, 10, 10)
up = False
down = False
left = False
right = False
blocks = [pygame.Rect(250,250,50,50)]
while True:
screen.fill((0, 0, 0))
scroll[0] += (player.x - scroll[0] - (WINDOW_SIZE[0]/2)) // 20
scroll[1] += (player.y - scroll[1] - (WINDOW_SIZE[1]/2)) // 20
player_movement = [0, 0]
if right == True:
player_movement[0] += 2
if left == True:
player_movement[0] -= 2
if up == True:
player_movement[1] -= 2
if down == True:
player_movement[1] += 2
player.x += player_movement[0]
player.y += player_movement[1]
player_scroll_rect = player.copy()
player_scroll_rect.x -= scroll[0]
player_scroll_rect.y -= scroll[1]
pygame.draw.rect(screen, (255,255,255), player_scroll_rect)
for block in blocks:
scroll_block = block.copy()
scroll_block.x = scroll_block.x - scroll[0]
scroll_block.y = scroll_block.y - scroll[1]
pygame.draw.rect(screen, (0,0,255), scroll_block)
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
if event.type == KEYDOWN:
if event.key == K_RIGHT:
right = True
if event.key == K_LEFT:
left = True
if event.key == K_UP:
up = True
if event.key == K_DOWN:
down = True
if event.type == KEYUP:
if event.key == K_RIGHT:
right = False
if event.key == K_LEFT:
left = False
if event.key == K_UP:
up = False
if event.key == K_DOWN:
down = False
pygame.display.update()
clock.tick(60)
If you want a solution for using images, ask me.
Also, you can find more about scrolling here: https://www.youtube.com/watch?v=5q7tmIlXROg
#enable pygame mode
import pygame
pygame.init()
#create screen
screen = pygame.display.set_mode((1000,600))
#Title + Logo
pygame.display.set_caption("Space Invader")
icon = pygame.image.load("chicken.png")
pygame.display.set_icon(icon)
#Player icon
player_icon = pygame.image.load("spaceship.png")
playerX = 400
playerY = 500
player_changeX = 0
player_changeY = 0
def player(x, y):
screen.blit(player_icon, (x, y))
surface.blit(image,((1920/2)-(image.get_width()/2),(1080/2)-
(image.get_height()/2)))
#game loop
running = True
while running:
# backround colour RGB
screen.fill((0, 0, 0))
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
#If key pressed check wether its right or left
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
player_changeX = -1
if event.key == pygame.K_RIGHT:
player_changeX = 1
if event.key == pygame.K_UP:
player_changeY = -1
if event.key == pygame.K_DOWN:
player_changeY = 1
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT or event.key ==pygame.K_RIGHT:
player_changeX = 0
if event.key == pygame.K_UP or event.key == pygame.K_DOWN:
player_changeY = 0
# If player reaches boarder
if playerX >= 936:
player_changeX = -1
if playerX <= 0:
player_changeX = 1
if playerY <= 0:
player_changeY = 1
if playerY >= 550:
player_changeY = -1
#Player change in coordinates
playerX += player_changeX
playerY += player_changeY
player(playerX, playerY)
pygame.display.update()
I am creating a simple game as i just got into programing and I was wondering if you could make the game screen appear in the centre of your own screen as when I run it it keeps appearing on the bottom of my screen and I then have to manually move it into the centre. If you can please tell me how. Hope my question was formated good enough. Thank you for any help.
It depends; if it's a image you can do:
surface.blit(image,((screenwidth/2)-(image.get_width()/2),(screenheight/2)-(image.get_height()/2)))
Please tell me it it's different
I have used pygame for a while now, but now the player rect isn't updating or noticing collisions. It is still moving though. This just happened after I modified a bit of code. I have looked at the .draw functions and the walls and the border is being drawn, but the player isn't, and the screen is being updated. (The code snippet is in javascript because I still don't know how to use a code snippet in python.)
import pygame, sys, random
from pygame.locals import *
from time import sleep
pygame.init()
def render():
windowSurface.fill(black)
pygame.draw.rect(windowSurface,white,player1)
if level == 1:
pygame.draw.rect(windowSurface,white,wall_lvl_1_1)
pygame.draw.rect(windowSurface,white,wall_lvl_1_2)
pygame.draw.rect(windowSurface,white,border1_lvl_1)
elif level == 2:
filler = 'done'
pygame.display.update()
black = (0,0,0)
white = (255,255,255)
windowSurface = pygame.display.set_mode((500, 500),0,32)
windowSurface.fill(black)
level = 1
xmod = 0
ymod = 0
direction = 'none'
player1 = pygame.Rect(225 + xmod,450 - ymod,30,30)
wall_lvl_1_1 = pygame.Rect(0,225,250,50)
wall_lvl_1_2 = pygame.Rect(300,250,200,50)
border1_lvl_1 = pygame.Rect(0,0,25,500)
border2_lvl_1 = pygame.Rect(0,0,500,25)
border3_lvl_1 = pygame.Rect(0,0,1,1)
pygame.draw.rect(windowSurface,white,wall_lvl_1_1)
render()
while True:
render()
for event in pygame.event.get():
if event.type == KEYDOWN:
if event.key == K_LEFT:
direction = 'left'
if event.key == K_RIGHT:
direction = 'right'
if event.key == K_UP:
direction = 'up'
if event.key == K_DOWN:
direction = 'down'
if event.type == QUIT:
pygame.quit()
sys.exit()
if player1.colliderect(wall_lvl_1_1) or player1.colliderect(wall_lvl_1_2):
xmod = 0
ymod = 0
player1 = pygame.Rect(225 + xmod,450 - ymod,30,30)
print('again')
if direction == 'left':
xmod -= 1
sleep(0.004)
if direction == 'right':
xmod += 1
sleep(0.004)
if direction == 'up':
ymod += 1
sleep(0.004)
if direction == 'down':
ymod -= 1
sleep(0.004)
if ymod == 450:
level = 2
render()
You need to update the position of the player1 rect each frame.
player1.topleft = (xmod, ymod)
I know this is going to be (hopefully) an easy fix, but I cannot get the gameover screen to blit on my screen. I have thought through this for the past two hours, and none of my tweaks are working. Any help would be greatly appreciated!
This file contains the main file loop as while as sprite group
updates and general updates/renders for the program
import pygame, sys
import player
import random
import math
from constants import *
from bullet import *
from block import *
pygame.init()
screen = pygame.display.set_mode((800,600))
pygame.display.set_caption("Open")
clock = pygame.time.Clock()
def main():
moveX = 0
moveY = 0
sprite_list = pygame.sprite.Group()
bullet_list = pygame.sprite.Group()
block_list = pygame.sprite.Group()
main_player = player.Player()
sprite_list.add(main_player)
main_player.rect.x = 400
main_player.rect.y = 550
for i in range(1,10):
blocks = Block()
blocks.center_x = random.randrange(760)
blocks.center_y = random.randrange(400)
blocks.radius = random.randrange(10,200)
blocks.angle = random.random() * 4 * math.pi
blocks.speed = 0.04
block_list.add(blocks)
sprite_list.add(blocks)
font = pygame.font.Font(None, 36)
game_over = False
score = 0
level = 1
gameLoop = True
while gameLoop:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_RIGHT:
moveX = 5
if event.key == pygame.K_LEFT:
moveX = -5
if event.key == pygame.K_DOWN:
moveY = 5
if event.key == pygame.K_UP:
moveY = -5
if event.key == pygame.K_SPACE:
bullets = Bullet()
bullets.rect.x = main_player.rect.x + 16
bullets.rect.y = main_player.rect.y + 16
sprite_list.add(bullets)
bullet_list.add(bullets)
if event.type == pygame.KEYUP:
if event.key == pygame.K_RIGHT and moveX >= 0:
moveX = 0
if event.key == pygame.K_LEFT and moveX <= 0:
moveX = 0
if event.key == pygame.K_DOWN and moveY >= 0:
moveY = 0
if event.key == pygame.K_UP and moveY <= 0:
moveY = 0
for bullets in bullet_list:
block_hit_list = pygame.sprite.spritecollide(bullets, block_list, True)
for block in block_hit_list:
score += 1
bullet_list.remove(bullets)
sprite_list.remove(bullets)
if bullets.rect.y < 0:
bullet_list.remove(bullets)
sprite_list.remove(bullets)
if pygame.sprite.spritecollide(main_player, block_list, True):
gameLoop = False
game_over = True
sprite_list.update()
screen.fill(BLACK)
sprite_list.draw(screen)
main_player.rect.x += moveX
main_player.rect.y += moveY
score_text = font.render("Score: "+str(score), True, WHITE)
screen.blit(score_text,[10,10])
level_text = font.render("Level: "+str(level), True, WHITE)
screen.blit(level_text,[115,10])
if game_over == True:
you_lose_text = font.render("YOU SUCK", True, RED)
screen.blit(you_lose_text, [300,300])
pygame.time.wait(1000)
break
clock.tick(60)
pygame.display.update()
pygame.quit()
if __name__ == "__main__":
main()
HERE IS MY ISSUE:
if game_over == True:
you_lose_text = font.render("YOU SUCK", True, RED)
screen.blit(you_lose_text, [300,300])
pygame.time.wait(1000)
break
I am getting no error, and the pygame.time.wait function is working correctly? Why is it just skipping over displaying the text?
Maybe it is not the best solution but your code doesn't need better.
blit draws in buffer. You have to use update before wait to send data from buffer to screen.
if game_over == True:
you_lose_text = font.render("YOU SUCK", True, RED)
screen.blit(you_lose_text, [300,300])
pygame.display.update() # send on screen
pygame.time.wait(1000)
break
clock.tick(60)
pygame.display.update()
pygame.quit()
I would like to know how to create a border in Pygame to stop the user controlled object from exiting the screen. Right now, I only have it so python prints some text when the user controlled object has come near one of the 4 sides.
Here is my code so far.
import pygame
from pygame.locals import *
pygame.init()
#Display Stuff
screenx = 1000
screeny = 900
screen = pygame.display.set_mode((screenx,screeny))
pygame.display.set_caption('Block Runner')
clock = pygame.time.Clock()
image = pygame.image.load('square.png')
#Color Stuff
red = (255,0,0)
green = (0,255,0)
blue = (0,0,255)
white = (255,255,255)
black = (0,0,0)
#Variables
x_blocky = 50
y_blocky = 750
blocky_y_move = 0
blocky_x_move = 0
#Animations
def Blocky(x_blocky, y_blocky, image):
screen.blit(image,(x_blocky,y_blocky))
#Game Loop
game_over = False
while not game_over:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_UP:
blocky_y_move = -3
if event.type == pygame.KEYUP:
if event.key == pygame.K_UP:
blocky_y_move = 0
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_DOWN:
blocky_y_move = 3
if event.type == pygame.KEYUP:
if event.key == pygame.K_DOWN:
blocky_y_move = 0
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_RIGHT:
blocky_x_move = 3
if event.type == pygame.KEYUP:
if event.key == pygame.K_RIGHT:
blocky_x_move = 0
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
blocky_x_move = -3
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT:
blocky_x_move = 0
if x_blocky > 870 or x_blocky < 0:
print(' X Border')
if y_blocky > 750 or y_blocky < 2:
print(' Y Border')
y_blocky += blocky_y_move
x_blocky += blocky_x_move
screen.fill(white)
Blocky(x_blocky, y_blocky, image)
pygame.display.update()
clock.tick(60)
Don't use integers to store your position. Use a Rect.
So instead of
x_blocky = 50
y_blocky = 750
use
blocky_pos = pygame.rect.Rect(50, 750)
Now you can simply use
blocky_pos.move_ip(blocky_x_move, blocky_y_move)
to move your object.
After moving, you can simply call clamp/clamp_ip to ensure the blocky_pos Rect is always inside the screen.
blocky_pos.clamp_ip(screen.get_rect())
Also, you don't need to define basic colors yourself, you could simply use pygame.color.Color('Red') for example.
I also suggest you use pygame.key.get_pressed() to get all pressed keys to see how to move your object instead of creating 1000 lines of event handling code.
Well, simply don't increase your move variable any further, if you detect that the user object is near or at the border. Or reverse the move direction, depending on your general intent.
if x_blocky > 870 or x_blocky < 0:
print(' X Border')
blocky_x_move = 0
if y_blocky > 750 or y_blocky < 2:
print(' Y Border')
blocky_y_move = 0
Also, you have some redundant code with your keyboard movement. Instead of writing
if event.type == KEYDOWN:
over and over again, group the KEYUP if statements and KEYDOWN if statements.
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_UP:
blocky_y_move = -3
elif event.key == pygame.K_DOWN:
blocky_y_move = +3
etc, and:
if event.type == pygame.KEYUP:
if event.key == pygame.K_UP:
blocky_y_move = 0
elif event.type == pygame.K_DOWN:
blocky_y_move = 0
etc
You can set the boundaries using the min and max functions.
Here is the concept:
We have a pygame object that moves in all four directions; lets say the user holds down the LEFT arrow key, so that the object reaches the top of the screen. The y-coordinate of the top of the screen will always be 0, so we want the object to come to a stop at y-coordinate 0.
This may seem as simple as:
if char.rect.y > 0:
char.rect.y -= char.speed
But this will result in a bug ig char.speed is greater than 1. Like when the object is at y-coordinate 5,
and its speed is 10; the condition still allows for one more step for the object, resulting in the object
coming 5 pixels out of the pygame window. What we want to do is more like:
if char.rect.y > 0:
char.rect.y -= char.speed
if char.rect.y < 0:
char.rect.y = 0
to push the object back into the boundaries. The above block of code can be simplified with the max function:
self.rect.y = max([self.rect.y - self.speed, 0])
For the object moving down:
if char.rect.y < HEIGHT - char.height:
char.rect.y += char.speed
if char.rect.y > HEIGHT - char.height:
char.rect.y = HEIGHT - char.height
or, the more efficient and clean method:
self.rect.y = min([self.rect.y + self.speed, HEIGHT - self.height])
For going left and right, simply replace the ys and height (and HEIGHT) from two lines above with xs and widths (and WIDTH).
All together:
import pygame
pygame.init()
WIDTH = 600
HEIGHT = 600
wn = pygame.display.set_mode((WIDTH, HEIGHT))
class Player:
def __init__(self):
self.speed = 1
self.width = 20
self.height = 20
self.color = (255, 255, 0)
self.rect = pygame.Rect((WIDTH - self.width) / 2, (HEIGHT - self.height) / 2, 20, 20)
def up(self):
self.rect.y = max([self.rect.y - self.speed, 0])
def down(self):
self.rect.y = min([self.rect.y + self.speed, HEIGHT - self.height])
def left(self):
self.rect.x = max([self.rect.x - self.speed, 0])
def right(self):
self.rect.x = min([self.rect.x + self.speed, WIDTH - self.width])
def draw(self):
pygame.draw.rect(wn, self.color, self.rect)
char = Player()
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
keys = pygame.key.get_pressed()
if keys[pygame.K_UP]:
char.up()
if keys[pygame.K_DOWN]:
char.down()
if keys[pygame.K_LEFT]:
char.left()
if keys[pygame.K_RIGHT]:
char.right()
wn.fill((0, 0, 0))
char.draw()
pygame.display.update()
Good luck!