I'm doing a final project for my coding class at school. I learnt from a tutorial online on how to use pygame by making pong. Then, I decided to create an Undertale battle system with the knowledge I had gained from learning how to make pong in pygame. I have come across an issue however, and its regarding the heart's speed.
Here is the code:
import pygame
import sys
# setup
pygame.init()
clock = pygame.time.Clock()
# main window
screen_width = 900
screen_height = 600
screen = pygame.display.set_mode((screen_width, screen_height))
pygame.display.set_caption('Undertale')
icon = pygame.image.load('heart.png')
pygame.display.set_icon(icon)
# game rectangles
heart = pygame.image.load('heart.png')
DEFAULT_IMAGE_SIZE = (20, 20)
heart_img = pygame.transform.scale(heart, DEFAULT_IMAGE_SIZE)
battle_width = 10
battle_height = 200
middle_offset = 30
length = 200 + 2*battle_width
battle_left = pygame.Rect(screen_width/2 - 100, screen_height/2 + middle_offset, battle_width, battle_height)
battle_right = pygame.Rect(screen_width/2 + 100 + battle_width, screen_height/2 + 30, battle_width, battle_height)
battle_up = pygame.Rect(screen_width/2 - 100, screen_height/2 + middle_offset, length, battle_width)
battle_down = pygame.Rect(screen_width/2 - 100, screen_height/2 + middle_offset + battle_height, length, battle_width)
# colours
bg_color = pygame.Color(0, 0, 0)
red = (255, 0, 0)
white = (255, 255, 255)
# game vars
heart_x = screen_width/2
heart_y = screen_height/2 + middle_offset + battle_height/2 - 10
# Using half of Default Image Size Width
heart_speed_x = 0
heart_speed_y = 0
speed = 4
while True:
# input handles
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_LEFT:
heart_speed_x -= speed
if event.key == pygame.K_RIGHT:
heart_speed_x += speed
if event.key == pygame.K_UP:
heart_speed_y -= speed
if event.key == pygame.K_DOWN:
heart_speed_y += speed
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT:
heart_speed_x += speed
if event.key == pygame.K_RIGHT:
heart_speed_x -= speed
if event.key == pygame.K_UP:
heart_speed_y += speed
if event.key == pygame.K_DOWN:
heart_speed_y -= speed
# logic
heart_x += heart_speed_x
heart_y += heart_speed_y
heart_rect = heart_img.get_rect(topleft=(heart_x, heart_y))
if heart_rect.colliderect(battle_left) or heart_rect.colliderect(battle_right):
heart_speed_x *= -1
if heart_rect.colliderect(battle_up) or heart_rect.colliderect(battle_down):
heart_speed_y *= -1
# visuals
screen.fill(bg_color)
pygame.draw.rect(screen, white, battle_left)
pygame.draw.rect(screen, white, battle_right)
pygame.draw.rect(screen, white, battle_up)
pygame.draw.rect(screen, white, battle_down)
screen.blit(heart_img, (heart_x, heart_y))
# window update
pygame.display.flip()
clock.tick(60)
The heart is the player. I want it to be able to move around inside the box, and I do not want it to come out, I want it to stay inside. I made it so that the heart image is a rectangle so that it can collide with the box. It worked, but the speed makes it so that the heart is constantly moving, I want it to stop whenever the KEYUP event occurs. And that's what I did, yet it refused to cooperate.
I figured out the solution:
heart_x += 0 - heart_speed_x
and
heart_y += 0 - heart_speed_y
The problem was that the either or both of the x and y position constantly changed after hitting the surface. This was because the speed of the variables stayed the same. So in the solution, I made it so that the x any y positions only change once once it conditionally checks for collision.
Related
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.
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
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'm trying to create a little game as a training, but I'm blocked because I don't know how I can collide 2 moving cubes.
The game is simple, there is a red box that you can move and if this box touches a green cube, then you lost. (the green cubes are always moving)
I tried to read some documentations but it's not really easy to understand as a beginner.
Here is the code:
import pygame
import random
from threading import Timer
pygame.init()
screenWidth = 1100
screenHeight = 600
white = (255,255,255)
red = (255, 0, 0)
yellow = (50, 250, 20)
FPS = 60
gameDisplay = pygame.display.set_mode((screenWidth, screenHeight))
pygame.display.set_caption('Tekken')
pygame.display.update()
clock = pygame.time.Clock()
font = pygame.font.SysFont(None, 28)
class Players:
def __init__(self, playerName, playerAttribute, cubeheight, cubewidth, missilesHeight, missilesWidth):
self.playerName = playerName
self.playerAttribute = playerAttribute
self.playerLife = 100
self.droite_x = 300
self.droite_y = 600
self.cubeheight = cubeheight
self.cubewidth = cubewidth
self.missiles = True
self.missilesHeight = missilesHeight
self.missilesWidth = missilesWidth
self.missiles_droite_x = 0
self.missiles_droite_y = round(random.randrange(50, screenHeight-50))
self.missiles_droite_x_inverse = screenWidth-50
self.missiles_droite_y_inverse = round(random.randrange(50, screenHeight-50))
self.vitesse_missiles = 10
print(self.playerName, self.playerAttribute, self.playerLife)
def environment_un(self):
gameExit = False
gameOver = False
droite_x_change = 0
droite_y_change = 0
missiles_droite_x_change = 0
missiles_droite_x_change_inverse = 0
while not gameExit:
while gameOver:
gameDisplay.fill(red)
screen_text = font.render("Game Over, do you want to play again? [Q] to quit", True, white)
gameDisplay.blit(screen_text, [100, 300])
pygame.display.update()
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_q:
gameOver = False
gameExit = True
break
if event.type == pygame.QUIT:
gameOver = False
gameExit = True
break
for event in pygame.event.get(): #va chercher les events
if event.type == pygame.QUIT: #Si j'appuie sur X
gameExit = True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
droite_x_change = -3
if event.key == pygame.K_RIGHT:
droite_x_change = +3
if event.key == pygame.K_UP:
droite_y_change = -3
if event.key == pygame.K_DOWN:
droite_y_change = +3
if event.key == pygame.K_SPACE:
missiles_droite_x_change = self.vitesse_missiles
missiles_droite_x_change_inverse = -self.vitesse_missiles
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT:
droite_x_change = 0
if event.key == pygame.K_RIGHT:
droite_x_change = 0
if event.key == pygame.K_UP:
droite_y_change = 0
if event.key == pygame.K_DOWN:
droite_y_change = 0
self.missiles_droite_x_inverse += missiles_droite_x_change_inverse
self.missiles_droite_x += missiles_droite_x_change
self.droite_x += droite_x_change
self.droite_y += droite_y_change
if self.droite_y + self.cubeheight <= 0:
self.droite_y = 0
elif self.droite_y + self.cubeheight >= screenHeight:
self.droite_y = screenHeight-self.cubeheight
elif self.droite_x + self.cubewidth <= 0:
self.droite_x = 0
elif self.droite_x + self.cubewidth >= screenWidth:
self.droite_x = screenWidth-self.cubewidth
gameDisplay.fill(white)
gameDisplay.fill(red, rect=[self.droite_x, self.droite_y, self.cubewidth, self.cubeheight])
gameDisplay.fill(yellow, rect=[self.missiles_droite_x, self.missiles_droite_y, self.missilesWidth, self.missilesHeight])
gameDisplay.fill(yellow, rect=[self.missiles_droite_x_inverse, self.missiles_droite_y_inverse, self.missilesWidth, self.missilesHeight])
pygame.display.update()
if self.missiles_droite_x + self.missilesWidth >= screenWidth:
missiles_droite_x_change = 0
if missiles_droite_x_change == 0:
self.missiles_droite_x = 0
self.missiles_droite_y = round(random.randrange(50, screenHeight-50))
missiles_droite_x_change = self.vitesse_missiles
if self.missiles_droite_x_inverse <= 0:
missiles_droite_x_change_inverse = 0
if missiles_droite_x_change >= 0:
self.missiles_droite_x_inverse = screenWidth-50
self.missiles_droite_y_inverse = round(random.randrange(50, screenHeight-50))
missiles_droite_x_change_inverse = -12
clock.tick(FPS)
pygame.quit()
Player_1 = Players('John', 'sometext', 50, 50, 100, 100)
Player_1.environment_un()
What should do I in order to detect the collision?
I can not run your code at the moment as I dont have pygame installed. However, you can use the pygame.sprite.collide_rect() if you declare your objects to have in their class an pygame.sprite.Sprite-object or inherit from that class (as suggested below). The code below may note work as I can not test it but it should be close to a functioning code snippet. In the case you would like to test collision of a sprite against multiple other sprites - consider looking at pygame.sprite.Group(). I believe that something like this should work:
class SpriteObject(pygame.sprite.Sprite):
def __init__(self,pos_x, pos_y):
pygame.sprite.Sprite.__init__(self)
self.rect = self.original.get_rect()
self.rect.center = (pos_x, pos_y)
class Players:
def __init__(self, playerName, playerAttribute, cubeheight, cubewidth, missilesHeight, missilesWidth):
sprite1 = SpriteObject(1,2)
sprite2 = SpriteObject(1,2)
sprite1.rect.collide_rect(sprite2)
If you are looking for a conceptual answer:
Since you are considering just cubes and if they are of the same size, two cubes will occupy the same space 'if and only if' a corner of one cube is between (inclusive) two parallel planes of another. There are many ways to do this in practice.
I would check if between by evaluating an inward normal vector of cube 1 dotted with a vector to a corner (of cube 2) from any corner (of cube 1) . Do so for both parallel sides. If both are positive, its inside.
It's slightly more complicated for different shapes and varying sizes.
Use pygame.Rect() to keep cube position and size - and then you can use pygame.Rect.colliderect() to check collision between two cubes.
cube1 = pygame.Rect((x1, y1), (width, height))
cube2 = pygame.Rect((x2, y2), (width, height))
if cube1.colliderect(cube2):
print("Collision !")
PyGame has other usefull classes - pygame.sprite.Sprite and pygame.sprite.Group - which use Rect and collision detection functions.
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!