The left paddle works fine it moves up and down no problem. But the right is okay when I don't move but when I do it moves to the directions I coded to but doesn't erase the previously drawn location which in the end just draws a straight line. Trying to make my first ever game with no tutorial and I'm kind of stuck
Here's the code
import pygame
pygame.init()
screen_width = 1280
screen_height = 720
window = pygame.display.set_mode((screen_width, screen_height),0,0)
pygame.display.set_caption("PongGame")
clock = pygame.time.Clock()
#background
background = pygame.image.load("C:/Users/teamb/Desktop/PythonWorkspace/myGame/background.png")
#paddle image
paddle = pygame.image.load("C:/Users/teamb/Desktop/PythonWorkspace/myGame/paddle.png")
paddle_size = paddle.get_rect().size
#left paddle
left_paddle_width = paddle_size[0]
left_paddle_height = paddle_size[1]
left_paddle_xpos = 10
left_paddle_ypos = (screen_height/2 - left_paddle_height/2)
to_x = 0
to_y = 0
character_speed = 10
#right paddle
right_paddle_width = paddle_size[0]
right_paddle_height = paddle_size[1]
right_paddle_xpos = screen_width - right_paddle_width - 10
right_paddle_ypos = (screen_height/2 - left_paddle_height/2)
to_y_2 = 0
# ball
ball = pygame.image.load("C:/Users/teamb/Desktop/PythonWorkspace/myGame/ball.png")
running = True
while running:
dt = clock.tick(60)
print("fps : " + str(clock.get_fps()))
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
#left paddle
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_w:
to_y -= character_speed
elif event.key == pygame.K_s:
to_y += character_speed
if event.type == pygame.KEYUP:
if event.key == pygame.K_w or event.key == pygame.K_s:
to_y = 0
#right paddle
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_UP:
to_y_2 -= character_speed
elif event.key == pygame.K_DOWN:
to_y_2 += character_speed
if event.type == pygame.KEYUP:
if event.key == pygame.K_UP or event.key == pygame.K_DOWN:
to_y_2 = 0
left_paddle_ypos += to_y
right_paddle_ypos += to_y_2
if left_paddle_ypos < 0:
left_paddle_ypos = 0
if left_paddle_ypos > screen_height - left_paddle_height:
left_paddle_ypos = screen_height - left_paddle_height
window.blit(background,(0,0))
window.blit(paddle, (left_paddle_xpos,left_paddle_ypos))
window.blit(paddle, (right_paddle_xpos, right_paddle_ypos))
window.blit(ball, (640, 360))
pygame.display.update()
pygame.quit()
Moste likely the background Surface (background) has a smaller width than the display Surface (window).
Clear the display before drawing the scene:
while running:
# [...]
window.fill(0) # <--- clear display
window.blit(background,(0,0))
window.blit(paddle, (left_paddle_xpos,left_paddle_ypos))
window.blit(paddle, (right_paddle_xpos, right_paddle_ypos))
window.blit(ball, (640, 360))
pygame.display.update()
Or scale the background image by pygame.transform.smoothscale:
background = pygame.image.load("C:/Users/teamb/Desktop/PythonWorkspace/myGame/background.png")
background = pygame.transform.smoothscale(background, window.get_size())
This line is redrawing your background on every movement:
window.blit(background,(0,0))
However, I suppose your background image is actually smaller than your play field, so you are not redrawing the background on that side. You can either make your background image larger, or draw it again using an offset, or even draw it stretched. The idea is cover the entire play field when you are drawing the background.
It is worth pointing out this is not necessarily the most optimized way to do that. Ideally, you would redraw only the parts that had changed, but this is way more complex. Drawing the entire background is an easy fix.
This question already has answers here:
Not letting the character move out of the window
(2 answers)
Closed 2 years ago.
I need a rectangular border around an image so my character stops walking through it. It would be nice if my character stopped at certain coordinates instead of walking over the image.
I've tried to create a border with my 'x' and 'y' coordinates, but the border seems to stretch across the screen.
import pygame
from pygame.locals import *
pygame.init()
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 700
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT,))
pygame.display.set_caption("Zombie Hunters")
background = pygame.image.load("background.jpg").convert()
background = pygame.transform.scale(background, (SCREEN_WIDTH,SCREEN_HEIGHT))
player = pygame.image.load("character no gun.png").convert_alpha()
player = pygame.transform.scale(player, (270, 270))
# these are the coordinates to move the player
x, y = 0, 0
MOVE_RIGHT = 1
MOVE_LEFT = 2
MOVE_UP = 3
MOVE_DOWN = 4
direction = 0
speed = 1
#House barrier
barrier_xlocation = 345
barrier_ylocation = 80
barrier_width = 190
barrier_height = 260
while True:
for event in pygame.event.get():
if event.type == QUIT:
exit()
if event.type == KEYDOWN:
if event.key == ord('q'):
pygame.quit()
exit()
if event.key == K_LEFT:
direction = MOVE_LEFT
if event.key == K_RIGHT:
direction = MOVE_RIGHT
if event.key == K_UP:
direction = MOVE_UP
if event.key == K_DOWN:
direction = MOVE_DOWN
elif event.type == KEYUP:
if event.key == K_LEFT:
direction = 0
if event.key == K_RIGHT:
direction = 0
if event.key == K_UP:
direction = 0
if event.key == K_DOWN:
direction = 0
if(direction == MOVE_LEFT):
x-= speed
if(direction == MOVE_RIGHT):
x+= speed
if(direction == MOVE_UP):
y-= speed
if(direction == MOVE_DOWN):
y += speed
#Background
screen.blit(background, (0, 0))
#House border
pygame.draw.rect(screen, (255,0,0), (barrier_xlocation,barrier_ylocation,barrier_width,barrier_height), 2)
#Player hitbox
pygame.draw.rect(screen, (255,0,0), (x + 117,y + 105, 50,50),2)
screen.blit(player, (x,y))
pygame.display.update()
I don't get any error messages, but I need to create a border around the house.
Use pygame.Rect objects and .colliderect() to check for the collision of two rectangles.
Store the current position of the player. After the player position has change, check for a collision with the barrier. When the player and the barrier are colliding, then reset the position of the player.
The size of as [pygame.Surface] object can be get by .get_size():
# store current position
px, py = x, y
# change position
if(direction == MOVE_LEFT):
x-= speed
if(direction == MOVE_RIGHT):
x+= speed
if(direction == MOVE_UP):
y-= speed
if(direction == MOVE_DOWN):
y += speed
# set player and barrier rectangle
playerRect = pygame.Rect(x, y, *player.get_size())
barrierRect = pygame.Rect(
barrier_xlocation, barrier_ylocation, barrier_width, barrier_height)
# check for collision
if playerRect.colliderect(barrierRect):
# reset position
x, y = px, py
I am creating a game, that uses a map for collision, this all worked until I attempted to add scrolling to the game. It is supposed to make the background move instead of the player, which it does, but the problem lies within the collision detection.
The size of each collision point goes from 16 by 16, to 1 by 1.
This has proven to be quite problematic, and any help with fixing it will be greatly appreciated
I have tried changed to player's collision values, screen sizes, but in the end I am not sure what the exact cause of this problem is, my best guess would be that my removal of the player's movement and instead having it remain at the same position on the screen, has lead to problem with how the collision is suppose to act with the change in position, but this doesn't explain the shrinking of the collision points.
import pygame, sys
clock = pygame.time.Clock()
from pygame.locals import *
pygame.init() # initiates pygame
pygame.display.set_caption('The Game')
WINDOW_SIZE = (600,400)
screen = pygame.display.set_mode(WINDOW_SIZE,0,32)
display = pygame.Surface((300,200))
moving_right = False
moving_left = False
moving_up = False
moving_down = False
game_map = [['2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2'],
['2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2'],
['2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2'],
['0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'],
['0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'],
['0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'],
['0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'],
['0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'],
['0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'],
['0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'],
['2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2'],
['2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2'],
['0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0']]
player_rect = pygame.Rect(100,100,16,16)
black = (45,45,45)
black1 = (60,60,60)
def collision_test(rect,tiles):
hit_list = []
for tile in tiles:
if rect.colliderect(tile):
hit_list.append(tile)
return hit_list
def move(rect,movement,tiles):
collision_types = {'top':False,'bottom':False,'right':False,'left':False}
rect.x += movement[0]
hit_list = collision_test(rect,tiles)
for tile in hit_list:
if movement[0] > 0:
rect.right = tile.left
collision_types['right'] = True
elif movement[0] < 0:
rect.left = tile.right
collision_types['left'] = True
rect.y += movement[1]
hit_list = collision_test(rect,tiles)
for tile in hit_list:
if movement[1] > 0:
rect.bottom = tile.top
collision_types['bottom'] = True
elif movement[1] < 0:
rect.top = tile.bottom
collision_types['top'] = True
return rect, collision_types
while True:
display.fill((155,155,155))
tile_rects = []
y = 0
for layer in game_map:
x = 0
for tile in layer: # tiles
if tile == '2':
pygame.draw.rect(display,black,(x*16-player_rect.x,y*16-player_rect.y,16,16))
if tile != '0':
tile_rects.append(pygame.Rect(x*16-player_rect.x,y*16-player_rect.y,16,16))
x += 1
y += 1
player_movement = [0,0]
if moving_right == True:
player_movement[0] += 2
if moving_left == True:
player_movement[0] -= 2
if moving_up == True:
player_movement[1] -= 2
if moving_down == True:
player_movement[1] += 2
player_rect,collisions = move(player_rect,player_movement,tile_rects)
pygame.draw.rect(display,black1,(142,100,16,16)) #replacing the 142 and 100 with the rect.x and y, and remove the rect.x and y from the tiles, will make it work like the original
for event in pygame.event.get(): # event loop
if event.type == QUIT:
pygame.quit()
sys.exit()
if event.type == KEYDOWN:
if event.key == K_RIGHT:
moving_right = True
if event.key == K_LEFT:
moving_left = True
if event.key == K_UP:
moving_up = True
if event.key == K_DOWN:
moving_down = True
if event.type == KEYUP:
if event.key == K_RIGHT:
moving_right = False
if event.key == K_LEFT:
moving_left = False
if event.key == K_UP:
moving_up = False
if event.key == K_DOWN:
moving_down = False
screen.blit(pygame.transform.scale(display,WINDOW_SIZE),(0,0))
pygame.display.update()
clock.tick(60)
My expected result was for the collision points not to change and remain 16 by 16, unfortunately, instead the collision points for the tiles has shrank to 1 by 1, leading to many problems.
Your code is a bit hard to follow, but I've understood where the problem is.
In your move function you change the coordinates of player_rect to make it move. But then when you draw it (pygame.draw.rect(display,black1,(142,100,16,16))) you draw it at the center. So there is a mismatch between what you draw and what is tested for movement.
Honestly, I cannot find a way to solve it without changing a lot of code.
If you want to keep the backgroung scrolling, consider to not move the player but to move the tiles in the opposite direction. I mean, if the player goes left, move the tiles right, and so on.
Currently you are creating the tiles each iteration. I would recommend to create them outside the main loop, and in the loop move them (editing the coordinates of their rects).
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.
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!