Adding boundaries in Pygame with movable characters/images - python

I have been creating a game where an image moves according to player input with Keydown and Keyup methods. I want to add boundaries so that the user cannot move the image/character out of the display (I dont want a game over kind of thing if boundary is hit, just that the image/character wont be able to move past that boundary)
import pygame
pygame.init()#initiate pygame
black = (0,0,0)
white = (255,255,255)
red = (255,0,0)
display_width = 1200
display_height = 800
display = pygame.display.set_mode((display_width,display_height))
characterimg_left = pygame.image.load(r'/Users/ye57324/Desktop/Make/coding/python/characterimg_left.png')
characterimg_right = pygame.image.load(r'/Users/ye57324/Desktop/Make/coding/python/characterimg_right.png')
characterimg = characterimg_left
def soldier(x,y):
display.blit(characterimg, (x,y))
x = (display_width * 0.30)
y = (display_height * 0.2)
pygame.display.set_caption('No U')
clock = pygame.time.Clock()#game clock
flip_right = False
x_change = 0
y_change = 0
bg_x = 0
start = True
bg = pygame.image.load(r'/Users/ye57324/Desktop/Make/coding/python/bg.png').convert()
class player:
def __init__(self, x, y):
self.jumping = False
p = player(x, y)
while start:
for event in pygame.event.get():
if event.type == pygame.QUIT or (event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE):
start = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
x_change += -4
if flip_right == True:
characterimg = characterimg_left
flip_right = False
x += -150
elif event.key == pygame.K_RIGHT:
x_change += 4
if flip_right == False:
characterimg = characterimg_right
flip_right = True
x += 150
elif event.key == pygame.K_UP:
y_change += -4
elif event.key == pygame.K_DOWN:
y_change += 4
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT:
x_change += 4
elif event.key == pygame.K_RIGHT:
x_change += -4
elif event.key == pygame.K_UP:
y_change += 4
elif event.key == pygame.K_DOWN:
y_change += -4
x += x_change
y += y_change
display.fill(white)
soldier(x,y)
pygame.display.update()
clock.tick(120)#fps
pygame.quit()
I have tried several times including switching to the key pressed method but they all failed. Help please, thank you.

Basically you want to limit the player's movement.
So everytime you want to "move" the player (I'm guessing this is "x_change" / "y_change") you need to check whether they would still be inside your boundaries after the move.
Example: Your display x boundary is 0 pixels on the left of your screen and 500 to the right. I only allow the actual movement if the result of the movement is within my boundaries.
boundary_x_lower = 0
boundary_x_upper = 500
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
if boundary_x_lower < (x_change - 4):
# I allow the movement if I'm still above the lower boundary after the move.
x_change -= 4
elif event.key == pygame.K_RIGHT:
if boundary_x_upper > (x_change +4):
# I allow the movement if I'm still below the upper boundary after the move.
x_change += 4
PS: I am confused by your code as you subtract when you move to the right... I am used to 2D games where you increment the player's position if you move to the right... and subtract if you go to the left.
Feel free to adapt the code to fit your project. The basic principle applies also to the y-axis movement: with boundary_y_lower & _y_upper. if you have further questions, just ask!

Just clamp the x and y values between 0 and the display width and height.
# In the main while loop after the movement.
if x < 0:
x = 0
elif x + image_width > display_width:
x = display_width - image_width
if y < 0:
y = 0
elif y + image_height > display_height:
y = display_height - image_height
I also recommend checking out how pygame.Rects work. You could define a rect with the size of the display,
display_rect = display.get_rect()
and a rect for the character which will be used as the blit position:
rect = characterimg_left.get_rect(center=(x, y))
Then move and clamp the rect in this way:
rect.move_ip((x_change, y_change))
rect.clamp_ip(display_rect)
display.fill(white)
# Blit the image at the `rect.topleft` coordinates.
display.blit(characterimg, rect)

Related

How can i make the ball bounce in the right directions

Im making an air hokey game using pygame , but i have no idea how to make the ball bounce in the right direction when the player hits it.
i tried making the ball move in the x direction if the player hits it and if the player is under the ball or aboce it i made it move in the y and x direction but that didnt work
import pygame
import math
pygame.init()
screen = pygame.display.set_mode((800, 400))
background = pygame.image.load("ER.png")
player1 = pygame.image.load("eee.png")
px = 20
py = 148
change = 0
cy = 0
player2 = pygame.image.load("a.png")
px2 = 700
py2 = 148
cx2 = 0
cy2 = 0
ball = pygame.image.load("qw.png")
bx = 351
by = 148
chx = 0
chy = 0
def balls(x,y):
screen.blit(ball,(x,y))
def p1(x, y):
screen.blit(player1,(x , y))
def p2(x, y):
screen.blit(player2,(x , y))
def colid(ex,ey, bx, by):
d = math.sqrt((math.pow(ex - bx, 2)) + (math.pow(by - ey,2)))
if d < 40:
return True
else:
return False
run = True
while run:
screen.blit(background,(0,0))
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_d:
change += 1
if event.key == pygame.K_a:
change += -1
if event.key == pygame.K_s:
cy += 1
if event.key == pygame.K_w:
cy += -1
if event.key == pygame.K_LEFT:
cx2 -= 1
print(px2)
print(py2)
if event.key == pygame.K_RIGHT:
cx2 += 1
print(px2)
print(py2)
if event.key == pygame.K_DOWN:
cy2 += 1
print(px2)
print(py2)
if event.key == pygame.K_UP:
cy2 += -1
print(px2)
print(py2)
if event.type == pygame.KEYUP:
if event.key == pygame.K_d:
change -= 1
if event.key == pygame.K_a:
change += 1
if event.key == pygame.K_s:
cy -= 1
if event.key == pygame.K_w:
cy += 1
if event.key == pygame.K_LEFT:
cx2 += 1
if event.key == pygame.K_RIGHT:
cx2 -= 1
if event.key == pygame.K_DOWN:
cy2 -= 1
if event.key == pygame.K_UP:
cy2 += 1
colide = colid(bx, by, px, py)
if colide:
print("colided")
bx += ch
py2 += cy2
px2 += cx2
py += cy
px += change
balls(bx,by)
p1(px,py)
p2(px2, py2)
if px <= -8:
px = -8
if px >= 326:
px = 326
if py <= -8:
py = -8
if py >= 312:
py = 312
if px2 >= 712:
px2 = 712
if py2 <= -8:
py2 = -8
if py2 >= 312:
py2 = 312
if px2 <= 378:
px2 = 378
pygame.display.update()
You update the ball position with
bx += ch
but the colide result does not influence ch.
Therefore the ball behavior does not change when Player1 hits it.
Have your if statement do something like this
after printing that the ball collided:
ch = -ch
This assumes values like 1 or -1.
The code you posted does not set ch.
If ch is zero the ball will remain stationary.
You might also make your bounds check code flip the sign,
so the ball bounces off the left and right walls
independent of what Player1 is doing.
Or try one of these special effects within the bounds check:
ch *= -0.95 # friction slows the ball down
ch *= -1.05 # hot walls continually impart more energy to the ball
You have an inconveniently large number of variables.
You could get away with roughly half as many if a class introduced
the concept of a Point located at some (x, y).
You might even create a Ball class that models both position and velocity.
A related difficulty is that you almost adhered to a consistent
naming scheme. Clean that up and you'll find design and debugging much easier.

How to add borders to pygame [duplicate]

This question already has answers here:
Not letting the character move out of the window
(2 answers)
I made a border in this pong game, but the paddles can cross it. How do I stop that?
(2 answers)
Closed 2 years ago.
I have tried many sites but still cannot come up with anything. All online tutorials are not helpful. I have just started learning python and every time I try to move it goes out of the border. I have tried basically all online guide and came across an error...........................
pygame.init()
screen_width = 800
screen_height = 600
window = pygame.display.set_mode((screen_width, screen_height))
pygame.display.set_caption('Test')
bg_color1 = (135,142,142) #MAIN BG COLOR
bg_color2 = (255,0,0) #red
bg_color3 = (255,255,0) #yellow
clock = pygame.time.Clock()
crashed = False
UFO = pygame.image.load('ufo.png')
rect = UFO.get_rect()
obstacle = pygame.Rect(400, 200, 80, 80)
def car(x, y):
window.blit(UFO, (x, y))
x = (screen_width * 0.45)
y = (screen_height * 0.8)
x_change = 0
car_speed = 0
y_change = 0
while not crashed:
for event in pygame.event.get():
if event.type == pygame.QUIT:
crashed = True
############SIDE TO SIDE################
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
x_change = -5
elif event.key == pygame.K_RIGHT:
x_change = 5
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT:
x_change = 0
###########UP AND DOWN#################
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_UP:
y_change = -5
elif event.key == pygame.K_DOWN:
y_change = 5
if event.type == pygame.KEYUP:
if event.key == pygame.K_UP or event.key == pygame.K_DOWN:
y_change = 0
##
x += x_change
y += y_change
##
window.fill(bg_color1)
car(x, y)
pygame.display.update()
clock.tick(100)
pygame.quit()
quit()
Check that the coordinate is less than 0 or greater than the width or height of the screen. Limit the coordinate if it is out of bounds:
while not crashed:
# [...]
x += x_change
if x < 0:
x = 0
elif x > screen_width - UFO.get_width():
x = screen_width - UFO.get_width()
y += y_change
if y < 0:
y = 0
elif y > screen_height - UFO.get_height():
y = screen_height - UFO.get_height()
You can simplify the code using the min and max functions:
while not crashed:
# [...]
x = max(0, min(screen_width - UFO.get_width(), x + x_change))
y = max(0, min(screen_height - UFO.get_height(), y + y_change))
Another option is to use pygame.Rect objects and clamp_ip. See clamp_ip:
moves the rectangle inside another, in place
while not crashed:
# [...]
x += x_change
y += y_change
border_rect = window.get_rect()
ufo_rect = UFO.get_rect(topleft = (x, y))
ufo_rect.clamp_ip(border_rect)
x, y = ufo_rect.topleft

Pygame won't let me make boundaries on a screen with the event module

So I'm just making a simple game that allows a red rectangle to move around the screen, but the boundaries that should make the red rectangle stop before it gets off the screen won't work. Can someone tell me what I'm doing wrong?
while Game:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_1:
gameDisplay = pygame.display.set_mode((display_width,display_height), pygame.FULLSCREEN)
if event.key == pygame.K_2:
gameDisplay = pygame.display.set_mode((display_width,display_height))
if event.key == pygame.K_RIGHT:
x_change = 5
if event.key == pygame.K_LEFT:
x_change = -5
if event.key == pygame.K_UP:
y_change = -5
if event.key == pygame.K_DOWN:
y_change = 5
if x > display_width - 100 or x < 0 and event.key == pygame.K_RIGHT:
if event.key == pygame.K_LEFT:
x_change = -5
else:
x_change = 0 #I did this for all directions
x += x_change
y += y_change
Just so you know, clock.tick is 80 and I have imported pygame and did the pygame.init() thing. Also, movement and every thing else works, just not this.
Try this code:
def clamp(value, minimum=0, maximum=1): return max(minimum, min(value, maximum))
maxX = display_width-rectangle_width
maxY = display_height-rectangle_height
if x not in range(maxX): x_change = 0
if y not in range(maxY): y_change = 0
x = clamp(x, maximum=maxX)
y = clamp(y, maximum=maxY)
However, you are changing the velocity and not the position, when it is out of the screen, the velocity is not moving it back, it keeps there or the speed from the pressed key in the next frame moves it again.

Detecting whether the player has collided w/ the bottom of an object (rectangles)

I'm trying to create a bird's-eye-view game (e.g. hotline miami) in pygame. I've gotten stuck at the collision detection. I'm trying to to see if the player hits a block on the left, right, in front or behind . I've gotten only to doing the 'in front' collision but that doesn't work; the player will hit the block 'head first', stop, but is then able to move through the block if he spams the arrow key. I know what the problem is (in the if else statement in the collision detection) but I can't for the life of me find the solution. Everything I tried doesn't seem to work. Help! Any help would be greatly appreciated, thanks in advance! (btw this is my first time on stack overflow, so sorry if I'm not asking the question well) (I removed some of the unnecessary code like the pygame.init() and variables)
def drawBlock(block_width,block_height,x,y):
pygame.draw.rect(gameDisplay, red, [x,y,block_width,block_height])
def gameLoop(x,y):
while not gameExit:
level = ["W","W","W","W","W","W","W","W","W","W","W","W",
"N","N","N","N","N","N","N","N","N","N","N","N","L",
"N","N","N","N","N","N","N","N","N","N","N","N","L",
"N","N","N","N","P","N","N","N","N","N","N","N","L",
"N","N","N","N","N","N","N","N","N","N","N","N","L",
"N","N","N","N","N","N","N","N","N","N","N","N","L",
"N","N","N","N","N","N","N","N","N","N","N","N","L",
"N","N","N","N","N","N","N","N","N","N","N","N","L",
"N","N","N","N","N","N","N","N","N","P","N","N","L",
"N","N","N","N","P","N","N","N","N","N","N","N","L",
"N","N","N","N","N","N","N","N","N","N","N","N","L","S"]
#EVENT HANDLING
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if canMoveUp:
if event.key == pygame.K_UP:
y_change = -player_movement
if canMoveDown:
if event.key == pygame.K_DOWN:
y_change = player_movement
if event.key == pygame.K_LEFT:
x_change = -player_movement
if event.key == pygame.K_RIGHT:
x_change = player_movement
if event.type == pygame.KEYUP:
if event.key == pygame.K_UP or event.key == pygame.K_DOWN:
y_change = 0
if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT:
x_change = 0
pX += x_change
pY += y_change
gameDisplay.fill(black)
#CALCULATING THE SIZE OF THE BLOCKS SO THEY FIT W/ A VARIETY OF RESOLUTIONS
if calculateBlockX:
for element in level:
if element == "W":
W_count += 1
if element == "S":
block_width = (display_width/W_count)
calculateBlockX = False
if calculateBlockY:
for element in level:
if element == "L":
L_count += 1
if element == "S":
block_height = (display_height/L_count)
calculateBlockY = False
#COUNTING HOW MANY BLOCKS THERE ARE IN THE LEVEL ARRAY (P)
if P_countFunction:
for element in level:
if element == "P":
P_count += 1
if element == "S":
print(P_count)
P_countFunction = False
#ALL THE X AND Ys OF ALL THE BLOCKS IN THE LEVEL, AND ACTUALLY DRAWING THEM
blockXY = []
for element in level:
if element == "N":
x += block_width
if element == "L":
y += block_height
x = 0
if element == "P":
drawBlock(block_width,block_height,x,y)
blockXY.append(x)
blockXY.append(y)
if appendBlockXY:
if len(collisionArray) > P_count:
del(collisionArray[P_count])
print(collisionArray)
appendBlockXY = False
collisionArray.append(blockXY)
blockXY = []
x += block_width
if element == "S":
y = 0
#COLLISION DETECTION
for XnY in collisionArray:
if pX >= XnY[0] and pX <= XnY[0] + block_width and pY + playerSize <= XnY[1] or pX + playerSize >= XnY[0] and pX <= XnY[0] + block_width:
if pY - block_height == XnY[1]:
canMoveUp = False
y_change = 0
if pY - block_height != XnY[1]:
canMoveUp = True
else:
if pY - block_height >= XnY[1]:
canMoveUp = True
#gameDisplay.blit(img,[pX,pY])
pygame.draw.rect(gameDisplay, green, [pX,pY,playerSize,playerSize])
clock.tick(60)
pygame.display.update()
pygame.quit()
quit()
gameLoop(x,y)
pygame.display.update()
Your collision detection is written in a way that allows the last iteration to override all earlier checks. Instead of that, have canMoveUp set to True before the loop, and the loop should only set it to False or leave it alone.

Pygame - shooting bullets

I have problem with my code, I started to make 2D tank game, the problem is the shooting bullets from the tank position.. Here's my code, check it out, I'm trying to figure it out like 3-4 hours.. I hope someone knows how to do it, thanks!:)
by the way, sorry for the creepy code, I'm new to Pygame :)
import pygame
pygame.init()
#---WINDOW----
display_width = 1000
display_height = 600
gameDisplay = pygame.display.set_mode((display_width,display_height))
pygame.display.set_caption('powpypow')
black = (0,0,0)
white = (255,255,255)
red = (255,0,0)
background = pygame.image.load('background.png')
tank1 = pygame.image.load('tank1.png')
tankfire = pygame.image.load('tankfire.png')
shot = pygame.image.load('shot.png')
clock = pygame.time.Clock()
def tank(x,y):
gameDisplay.blit(tank1, (x,y))
x = (display_width * 0.10)
y = (display_height * 0.58)
x_change = 0
tank_width = 73
#---GAME LOOP----
gameExit = False
while not gameExit:
for event in pygame.event.get():
if event.type == pygame.QUIT:
gameExit = True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_a:
x_change = -10
elif event.key == pygame.K_d:
x_change = 10
elif event.key == pygame.K_SPACE:
tank1 = pygame.image.load('tankfire.png')
if event.type == pygame.KEYUP:
if event.key == pygame.K_a or event.key == pygame.K_d or event.key == pygame.K_SPACE:
tank1 = pygame.image.load('tank1.png')
x_change = 0
if x >= display_width - tank_width or x <= 0:
x = 0
if x > display_width / 2:
x = 0
x += x_change
gameDisplay.blit(background, (0,0))
tank(x,y)
pygame.display.update()
clock.tick(60)
pygame.quit()
quit()
If you are going to want to render bullets, you are going to need to keep track of them as they move across the screen. This will require some sort of list or group of bullets that you iterate through and draw, one at a time.
I recommend you have a look at a tutorial to help you switch to using Sprites in a group, rather than blitting each image onto the screen individually. You will find that it is much easier to track each object and adjust its position.
The Chimp tutorial from the Pygame website is pretty good: https://www.pygame.org/docs/tut/chimp/ChimpLineByLine.html

Categories

Resources