How to implement jump in Pygame without sprites? - python

I'm new to programming and to Python as well as Pygame. As such, I'm not yet comfortable with sprites in Pygame. I'm trying to make a game where a block jumps whenever the spacebar is pressed - similar to Mario.
My code doesn't work as desired because whenever the spacebar is pressed, the block incrementally moves up (I've added a gravity component), instead of "jumping".
import pygame
pygame.init()
game_display = pygame.display.set_mode((800, 800))
# fixed variables at the start
x_pos = 400
y_pos = 400
current_speed = 15
def jump_coords(y_position, speed):
if speed >= 0:
#to move up, reduce the y-coordinate
y_position -= speed
return y_position
game_exit = False
# main loop
while not game_exit:
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
y_pos = jump_coords(y_pos, current_speed)
# 1 represents gravity value
current_speed -= 1
rect_one = pygame.Rect(x_pos, y_pos, 10, 10)
pygame.draw.rect(game_display, (255, 0, 0), rect_one)
pygame.display.update()
I know that I have to somehow make y_pos keep updating in the while loop whilst speed >= 0 but I'm not sure how to implement it.

I made the minimal changes to your code to get the block to bounce:
import pygame
pygame.init()
game_display = pygame.display.set_mode((800, 800))
# fixed variables at the start
x_pos = 400
y_pos = 400
x_old = x_pos
y_old = y_pos
current_speed = 15
def jump_coords(y_position, speed):
# to move up, reduce the y-coordinate
y_position -= speed
if y_position > 400:
y_position = 400
global jump_flag
jump_flag = False
global current_speed
current_speed = 15
return y_position
game_exit = False
jump_flag = False
# main loop
while not game_exit:
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
jump_flag = True
elif event.key == pygame.K_ESCAPE:
exit(0)
if jump_flag:
x_old = x_pos
y_old = y_pos
y_pos = jump_coords(y_pos, current_speed)
# 1 represents gravity value
current_speed -= 1
rect_old = pygame.Rect(x_old, y_old, 10, 10)
pygame.draw.rect(game_display, (0, 0, 0), rect_old)
rect_one = pygame.Rect(x_pos, y_pos, 10, 10)
pygame.draw.rect(game_display, (255, 0, 0), rect_one)
pygame.display.update()
The most important changes was the removal of the check for speed greater than zero. The speed has to go negative if the block is going to come back down. The next change was to save the old x and y coordinates so that we can draw a black square over the old position. I also made it possible to exit the program by pressing the Escape key.

I made this from scratch, I hope it's not too daunting!
import pygame,sys
pygame.init()
screen = pygame.display.set_mode((800, 800))
tm = 20 # Terminal Velocity
gravity = 1
class Player:
def __init__(self,speed,x,y):
self.speed = speed
self.x = x; self.y = y
self.yVelocity = 0
self.xVelocity = 0
def getKeys(self):
key = pygame.key.get_pressed()
if key[pygame.K_a]: self.xVelocity -= self.speed
if key[pygame.K_d]: self.xVelocity += self.speed
if key[pygame.K_SPACE]:
if isGround(self.x,self.y):
self.yVelocity -= 20
def move(self,dt):
if self.x < 0:
self.x = 0
if self.x > 800-15:
self.x = 800-15
if self.y < 0:
self.y = 0
if self.y > 800-10:
self.y = 800-10
self.x += self.xVelocity
self.y += self.yVelocity
if self.xVelocity != 0:
self.xVelocity /= 70*dt
if self.yVelocity < tm and not isBlocking(self.x,self.y+self.yVelocity):
self.yVelocity += gravity
if isBlocking(self.x,self.y):
self.yVelocity = 0
def draw(self):
screen.fill((255,0,0),(self.x,self.y,10,10))
def isBlocking(x,y):
if x < 0 or x > 800 or y < 0 or y > 800:
return True
elif y >= 400:
return True
else:
return False
def isGround(x,y):
if y >= 400:
return True
else:
return False
player = Player(1,400,400)
clock = pygame.time.Clock()
while True:
dt = clock.tick(60)/1000 # limit to 60 FPS.
screen.fill((0,0,0))
if pygame.event.poll().type == pygame.QUIT: pygame.quit(); sys.exit()
player.getKeys()
player.move(dt)
player.draw()
pygame.display.flip()
Hope it helps!

Related

Collisions in python ping pong game [duplicate]

This question already has answers here:
How do I detect collision in pygame?
(5 answers)
How to make ball bounce off wall with PyGame?
(1 answer)
Closed 1 year ago.
So, im having this trouble with collisions in my pygame Python Ping-pong game. Exactly in that fragment of code
#computer
if (x_ball > (x*9) and x_ball < (x*9)+15) and (y_ball < y+55 and y_ball > y-55):
print(f"col at x={x_ball} y= {y_ball}")
x_ball = 890
speed_x*=-1
So it is basic computer movement, repeating the y position of ball. But when i implemented AI movement, ball is going through the computer pallete, sometimes bouncing away. How to make it right? I lost my mind tbh.
import pygame
from pygame.constants import DROPTEXT
pygame.init()
#window
w_width = 1000
w_height = 600
screen = pygame.display.set_mode((w_width, w_height))
clock = pygame.time.Clock()
open = True
#player
x,y = 100,250
#define player action variables
speed = 5
speed_x,speed_y = -5,3
moving_down = False
moving_up = False
#define ball action variables
x_ball,y_ball = 500,250
radius = 10
class palette(pygame.sprite.Sprite):
global x,y
def __init__(self, x, y, speed):
self.speed = speed
pygame.sprite.Sprite.__init__(self)
self.player_rect = pygame.Rect(x,y,30,100)
def draw(self):
pygame.draw.rect(screen, 'White', self.player_rect)
def move(self, moving_up, moving_down):
#reset movement variables
global dy
dy = 0
#assing movement variables if moving up or down
if moving_up:
dy = -self.speed
if moving_down:
dy = self.speed
#update pallete possition
self.player_rect.y += dy
class EnemyPalette(pygame.sprite.Sprite):
global x,y
def __init__(self, x, y, speed):
self.speed = speed
pygame.sprite.Sprite.__init__(self)
self.enemy_rect = pygame.Rect(x,y,30,100)
def draw(self):
pygame.draw.rect(screen, 'White', self.enemy_rect)
#ai move
def move(self, speed,x_ball,y_ball):
self.speed = speed
self.x_ball = x_ball
self.y_ball = y_ball
global dy
dy = 0
dy = y_ball-50
#update enemy pallete possition
self.enemy_rect.y = dy
def ball():
global speed_x,speed_y,x_ball,y_ball
#update pos of bal
x_ball += speed_x
y_ball += speed_y
#basic colision with screen
y = player.player_rect.y
x = player.player_rect.x
#turn off left and right collisions
# if x_ball>=w_width-(0.5*radius) or x_ball <=0+(0.5*radius):
# speed_x*=-1
if y_ball>=w_height-(0.5*radius) or y_ball <=0+(0.5*radius):
speed_y*=-1
#set ball on middle when crosses screen
if x_ball>=w_width or x_ball<=0:
x_ball=500
#collision with pallettes
#player
if (x_ball < x+30 and x_ball > x) and (y_ball < y+120 and y_ball > y):
print(f"left paddle col at x={x_ball} y= {y_ball}")
x_ball = x+30
speed_x*=-1
#computer
if (x_ball > (x*9) and x_ball < (x*9)+15) and (y_ball < y+55 and y_ball > y-55):
print(f"right paddle col at x={x_ball} y= {y_ball}")
x_ball = 890
speed_x*=-1
pygame.draw.circle(screen, (255,255,255), (x_ball,y_ball), radius, 5)
return x_ball,y_ball
#ai movement
#build players and enemies
player = palette(x,y, speed)
enemy = EnemyPalette(x*9,y,speed)
#game
while open:
for event in pygame.event.get():
#quit game
if event.type == pygame.QUIT:
open = False
#keyboard presses
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_w:
moving_up = True
if event.key == pygame.K_s:
moving_down = True
if event.key == pygame.K_ESCAPE:
open = False
#keyboard button released
if event.type == pygame.KEYUP:
if event.key == pygame.K_w:
moving_up = False
if event.key == pygame.K_s:
moving_down = False
screen.fill((0,0,0))
clock.tick(60)
pygame.display.flip
#init players
player.draw()
enemy.draw()
player.move(moving_up, moving_down)
enemy.move(speed,x_ball,y_ball)
ball()
pygame.display.update()
You have to test against the enemy rectangle. Get the x and y coordinate form the enemy rectangle before the collision test:
y = enemy.enemy_rect.y
x = enemy.enemy_rect.x
if (x_ball > x and x_ball < x+15) and (y_ball < y+100 and y_ball > y):
print(f"right paddle col at x={x_ball} y= {y_ball}")
x_ball = 890
speed_x*=-1
Simplify the code with chained Comparisons:
y = enemy.enemy_rect.y
x = enemy.enemy_rect.x
if x < x_ball < x+15 and y < y_ball < y+100:
# [...]
Or even better pygame.Rect.collidepoint:
if enemy.enemy_rect.collidepoint(x_ball, y_ball):
# [...]
I recommend reading How do I detect collision in pygame? and Sometimes the ball doesn't bounce off the paddle in pong game.

My Simple Platformer Character Drifts Left but not Right and I Can't Find the Bug That Causes It [duplicate]

This question already has answers here:
Pygame doesn't let me use float for rect.move, but I need it
(2 answers)
Simple drag physics, acting differently when moving left or right [duplicate]
(1 answer)
Closed 2 years ago.
Basically I am working on a simple platformer and I have all of the basics like the gravity, acceleration, and platforms, but for some reason the character will decelerate going right, but when it goes left it will continue moving slowly instead of stopping. I even printed the value of my variable "changeX" to see what was going on, and it showed me the values I that should be happening rather than what was displayed. Sorry my comments are very limited in their helpfulness. The code regarding variables rect.x , changeX, and accelX are likely the most relevant.
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
BLUE = (50, 50, 255)
# Screen dimensions
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600
COLOR = BLUE
#Top Speed
tSpeedX = 7
tSpeedY = 20
#gravity constant
gConstant = 1
#acceleration X variable
accelX = 0
#acceleration Y variable
accelY = 0
#whether you can jump or not
jumpB = True
class player(pygame.sprite.Sprite):
def __init__(self, x, y):
super().__init__()
#iniatilized values for rect
self.image = pygame.Surface([50, 50])
self.image.fill(COLOR)
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
self.changeX = 0
self.changeY = 0
self.walls = None
#the velocity function. X and Y values are assigned based on the accelX
#and Y constants and added to the points of the rectangle
def velocity(self,x,y):
#change in speed
self.changeX += x
self.changeY += y
if abs(self.changeX) >= tSpeedX:
self.changeX = self.changeX/abs(self.changeX) * tSpeedX
if abs(self.changeY) >= tSpeedY:
self.changeY = self.changeY/abs(self.changeY) * tSpeedY
#standard update function. Will update rectangles position and deaccelerate it if no key held
def jump(self,y):
self.changeY = y
def update(self):
if accelX == 0:
self.changeX *= 0.92
if accelY == 0:
self.changeY *= .95
self.rect.x += self.changeX
print(self.changeX)
block_hit_list = pygame.sprite.spritecollide(self, self.walls, False)
for block in block_hit_list:
if self.changeX > 0:
self.rect.right = block.rect.left
else:
self.rect.left = block.rect.right
self.rect.y += self.changeY + (9*gConstant)
block_hit_list = pygame.sprite.spritecollide(self, self.walls, False)
for block in block_hit_list:
if self.changeY >= -5:
global jumpB
jumpB = True
COLOR = WHITE
self.rect.bottom = block.rect.top
else:
self.rect.top = block.rect.bottom
class wall(pygame.sprite.Sprite):
def __init__(self, sx, sy,px,py):
super().__init__()
#iniatilized values for walls
collision = False
self.image = pygame.Surface([sx, sy])
self.image.fill(WHITE)
self.rect = self.image.get_rect()
self.rect.x = px
self.rect.y = py
pygame.init()
screen = pygame.display.set_mode([SCREEN_WIDTH, SCREEN_HEIGHT])
spriteList = pygame.sprite.Group()
wallList = pygame.sprite.Group()
Player = player(100,100)
spriteList.add(Player)
Wall1 = wall(1000, 30, 0, 400)
Wall2 = wall(100, 30, 150, 350)
wallList.add(Wall2)
spriteList.add(Wall2)
wallList.add(Wall1)
spriteList.add(Wall1)
Player.walls = wallList
clock = pygame.time.Clock()
#Allows program to exit
quit = False
while not quit:
for event in pygame.event.get():
if event.type == pygame.QUIT:
quit = True
#Sets accel values
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
accelX = -.25
if event.key == pygame.K_RIGHT:
accelX = .25
if event.key == pygame.K_UP and jumpB == True:
Player.jump(-20)
jumpB = False
COLOR = BLUE
if event.key == pygame.K_DOWN:
accelY = .25
#reverses accel values to allow for deaccleration
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT:
accelX = 0
if event.key == pygame.K_RIGHT:
accelX = 0
if event.key == pygame.K_UP:
accelY = 0
if event.key == pygame.K_DOWN:
accelY = 0
#calls function to move rectangle
Player.velocity(accelX, accelY)
spriteList.update()
screen.fill(BLACK)
spriteList.draw(screen)
pygame.display.flip()
clock.tick(60)

Repeat drawing in pygame

I am making a BrickBreaker/Breakout game using pygame. I want my game to create rows of bricks until the a brick hits the paddle but I can't figure out how to do so. Currently it only creates 1 row of bricks. I also want to make the bricks dissappear when the ball hits them. Currently when the bricks are hit they just move off the screen, but I want them to get permanently deleted.
Thanks!
My current code:
# Brick Breaker Game
import pygame
import random
# Initialize the pygame
pygame.init()
# create the screen
screen = pygame.display.set_mode((800, 600))
# background
background = pygame.image.load("realBackground.png")
# Title and Icon
pygame.display.set_caption("Brick Breaker")
icon = pygame.image.load("Brick Breaker Icon.png")
pygame.display.set_icon(icon)
# Paddle
paddleImage = pygame.image.load("scaledPaddle.png")
paddleX = 335
paddleY = 550
paddleX_change = 0
# BrickCoordinates
brickX = []
brickY = []
brickX_change = []
brickY_change = []
numOfBricks = 6
brickXValue = 15
for i in range(numOfBricks):
brickX.append(brickXValue)
brickY.append(0)
brickX_change.append(0.3)
brickY_change.append(0)
# Add 120 if thick lines in middle bricks
# Add 110 if uniform thickness
brickXValue += 130
#Bricks
yellowBrickImage = pygame.image.load("yellowBrick.png")
greenBrickImage = pygame.image.load("greenBrick.png")
blueBrickImage = pygame.image.load("blueBrick.png")
pinkBrickImage = pygame.image.load("pinkBrick.png")
# ball
ballImage = pygame.image.load("Ball.png")
ballX = 380
ballY = 280
ballX_change = 1.5
ballY_change = 1.5
#Score
scoreValue = 0
font = pygame.font.Font("Neufreit-ExtraBold.otf",24)
textX = 10
textY = 10
def showScore(x,y):
score = font.render("Score : " + str(scoreValue), True, (255,255,255))
screen.blit(score,(x,y))
def paddle(x, y):
screen.blit(paddleImage, (x, y))
def yellowBrick(x, y, i):
screen.blit(yellowBrickImage, (x, y))
def greenBrick(x, y, i):
screen.blit(greenBrickImage, (x, y))
def blueBrick(x, y, i):
screen.blit(blueBrickImage, (x, y))
def pinkBrick(x, y, i):
screen.blit(pinkBrickImage, (x, y))
def ball(x, y):
screen.blit(ballImage, (x, y))
#To pick random brick colours
colourOfBrick = []
for i in range(numOfBricks):
colourOfBrick.append(random.randint(1,4))
# Game Loop (makes sure game is always running)
running = True
while running:
# To change background colour
screen.fill((128, 128, 128))
# background image
screen.blit(background, (0, 0))
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
# If keystroke is pressed check whether left or right
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
paddleX_change = -5
if event.key == pygame.K_RIGHT:
paddleX_change = 5
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT:
paddleX_change = 0
# Checking boudries of paddle
paddleX += paddleX_change
if paddleX <= 0:
paddleX = 0
elif paddleX >= 669:
paddleX = 669
#Draw Rectangles around bricks
brickRect = []
for i in range(numOfBricks):
brickRect.append(pygame.draw.rect(screen, (0, 0, 0), (brickX[i], brickY[i], 120, 42),1))
# Brick Movement
for i in range(numOfBricks):
brickY[i] += brickY_change[i]
if brickY[i] <= 0:
brickY_change[i] = 0.3
elif brickY[i] >= 500:
brickY_change[i] = -0.3
# Makes brick show up on screen
if colourOfBrick[i] == 1:
yellowBrick(brickX[i], brickY[i], i)
elif colourOfBrick[i] == 2:
greenBrick(brickX[i], brickY[i], i)
elif colourOfBrick[i] == 3:
blueBrick(brickX[i], brickY[i], i)
elif colourOfBrick[i] == 4:
pinkBrick(brickX[i], brickY[i], i)
# Ball Movement and boundary checking
ballX += ballX_change
if ballX <= 0:
ballX_change *= -1
elif ballX >= 760:
ballX_change *= -1
ballY += ballY_change
if ballY <= 0:
ballY_change *= -1
elif ballY >= 560:
ballX = 380
ballY = 280
# Paddle and Ball Collision
if ballY > 530 and ballY < 535 and (ballX+20) < paddleX + 131 and (ballX+20) > paddleX:
ballY_change *= -1
paddle(paddleX, paddleY)
ballCircle = pygame.draw.circle(screen, (255,0,0), (int(ballX+20),int(ballY+20)) ,20)
ball(ballX, ballY)
#Ball and Brick Collision
for i in range (numOfBricks):
if ballCircle.colliderect(brickRect[i]):
if abs(ballCircle.top - brickRect[i].bottom < 10) and ballY_change < 0:
brickX[i] = -400
ballY_change *= -1
scoreValue += 1
showScore(textX,textY)
pygame.display.update()
In your code all bricks have brickY.append(0) so all bricks are in one row. You have to create bricks with different Y values to create other rows.
You may need nested for-loops for this - like this
row_number = 3
brickYValue = 0
for row in range(row_number):
brickXValue = 15
for column in range(numOfBricks):
brickX.append(brickXValue)
brickY.append(brickYValue)
brickX_change.append(0.3)
brickY_change.append(0)
brickXValue += 130
# after `for column`
brickYValue += 15 # row height
But it will create more bricks then numOfBricks - you will have numOfBricks*row_number bricks so you would have to change other for-loops and use range(numOfBricks*row_number) instead of range(numOfBricks)
Or you should learn how to use for-loop without range()
brickRect = []
for x, y in zip(brickX, brickY):
brickRect.append(pygame.draw.rect(screen, (0, 0, 0), x, y, 120, 42),1))
BTW: you should also learn how to use pygame.Rect() to keep size and position of brick, paddle and ball. Rect() has methods to check collisions and you would no need long if ... and ... and ...
EDIT: I added rows in this code but I made many other changes so it may not be good example.
I draw surfaces instead of loading images so everyone can run it without images.
import pygame
import random
# --- classes ---
class Brick():
def __init__(self, x, y, image):
self.image = image
self.rect = self.image.get_rect(x=x, y=y)
self.x = x
self.y = y
self.x_change = 0
self.y_change = 1
def draw(self, screen):
self.rect.x = int(self.x)
self.rect.y = int(self.y)
screen.blit(self.image, self.rect)
pygame.draw.rect(screen, (0, 0, 0), self.rect, 1)
def update(self):
self.y += self.y_change
self.rect.y = int(self.y)
if self.rect.y <= 0:
self.y_change = 1
elif self.rect.y >= 500:
self.y_change = -1
class Ball():
def __init__(self):
#self.image = pygame.image.load("Ball.png")
self.image = pygame.Surface((16, 16)).convert_alpha()
self.image.fill((0,0,0,0)) # transparent background
pygame.draw.circle(self.image, (255,255,255), (8, 8), 8)
self.rect = self.image.get_rect(centerx=380, centery=280)
self.x = 380
self.y = 280
self.x_change = 3
self.y_change = 3
def reset(self):
self.x = 380
self.y = 280
def draw(self, screen):
self.rect.centerx = int(self.x)
self.rect.centery = int(self.y)
screen.blit(self.image, self.rect)
def update(self):
# Ball Movement and boundary checking
self.x += self.x_change
self.rect.centerx = int(self.x)
if self.rect.left <= 0:
self.x_change *= -1
elif self.rect.right >= 800:
self.x_change *= -1
self.y += self.y_change
self.rect.centery = int(self.y)
if self.rect.top <= 0:
self.y_change *= -1
elif self.rect.bottom >= 600:
self.reset()
class Paddle():
def __init__(self):
#self.image = pygame.image.load("scaledPaddle.png")
self.image = pygame.Surface((100, 30))
self.image.fill((255,0,0))
self.rect = self.image.get_rect(x=335, y=550)
self.x_change = 0
self.y_change = 0
def reset(self):
self.rect.x = 335
self.rect.y = 550
def draw(self, screen):
screen.blit(self.image, self.rect)
def update(self):
# Checking boudries of paddle
self.rect.x += self.x_change
if self.rect.left <= 0:
self.rect.left = 0
elif self.rect.right >= 800:
self.rect.right = 800
class Score():
def __init__(self):
#self.font = pygame.font.Font("Neufreit-ExtraBold.otf", 24)
self.font = pygame.font.SysFont(None, 24)
self.value = 0
self.x = 10
self.y = 10
def reset(self):
self.value = 0
def draw(self, screen):
self.image = self.font.render("Score : " + str(self.value), True, (255,255,255))
self.rect = self.image.get_rect(x=self.x, y=self.y)
screen.blit(self.image, self.rect)
# --- functions ---
# empty
# --- main ---
pygame.init()
screen = pygame.display.set_mode((800, 600))
pygame.display.set_caption("Brick Breaker")
#icon = pygame.image.load("Brick Breaker Icon.png")
#pygame.display.set_icon(icon)
# Background Image
#background_image = pygame.image.load("realBackground.png")
background_image = pygame.Surface((800,600))
for y in range(5, 600, 25):
for x in range(5, 800, 25):
color = random.choice([(255,128,128), (128,255,128), (128,128,255)])
background_image.fill(color, [x,y,15,15])
# Brick Images
#brick_images = [
# pygame.image.load("yellowBrick.png"),
# pygame.image.load("greenBrick.png"),
# pygame.image.load("blueBrick.png"),
# pygame.image.load("pinkBrick.png"),
#]
brick_images = [
pygame.Surface((100, 30)),
pygame.Surface((100, 30)),
pygame.Surface((100, 30)),
pygame.Surface((100, 30)),
pygame.Surface((100, 30)),
pygame.Surface((100, 30)),
]
brick_images[0].fill((255,0,0))
brick_images[1].fill((0,255,0))
brick_images[2].fill((0,0,255))
brick_images[3].fill((255,255,0))
brick_images[4].fill((255,0,255))
brick_images[5].fill((0,255,255))
# Objects
paddle = Paddle()
ball = Ball()
score = Score()
# bricks
rows_number = 5
cols_number = 7
all_bricks = []
y = 0
for row in range(rows_number):
x = 50
for col in range(cols_number):
color_image = random.choice(brick_images)
brick = Brick(x, y, color_image)
all_bricks.append(brick)
x += 100
y += 30
# Game Loop
clock = pygame.time.Clock()
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
# If keystroke is pressed check whether left or right
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
paddle.x_change = -5
if event.key == pygame.K_RIGHT:
paddle.x_change = 5
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT:
paddle.x_change = 0
# --- updates ---
paddle.update()
ball.update()
# Bricks Update
for brick in all_bricks:
brick.update()
# Ball and Paddle Collision
if ball.rect.colliderect(paddle):
ball.y_change *= -1
# Ball and Bricks Collision
for brick in all_bricks:
if ball.rect.colliderect(brick):
brick.x = -400
ball.y_change *= -1
score.value += 1
# --- draws ---
# To change background colour
# screen.fill((128, 128, 128)) # you don't need it if background fill all screen
# background image
screen.blit(background_image, (0, 0))
for brick in all_bricks:
brick.draw(screen)
paddle.draw(screen)
ball.draw(screen)
score.draw(screen)
pygame.display.flip()
clock.tick(60) # 60 FPS (Frames Per Second) on all computers
# --- end ---
pygame.quit()

How to make an object "jump" in pygame

I was trying to create something along the lines of mario, this is far from perfect I know. Anyways, while trying to make the "jumping" method I ran into an issue - The jumping doesn't work the way I intended it to work. Whenether I click the space bar my red square moves up and down randomly, I have to press the spacebar and hold it to complete a jump and even then its not perfect. Sometimes when I hold the space bar for too long the red square will continue to jump again. Is there any way to solve this issue? I'd be very thankful for any help, thanks.
import pygame, time, math, random, sys
from pygame.locals import *
background = pygame.image.load("assets/MarioBackground.png")
def events():
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
W, H = 640, 400
HW, HH = W / 2, H / 2
AREA = W * H
FPS = 60
bg_x = 0
isJump = False
jumpCount = 10
pygame.init()
clock = pygame.time.Clock()
screen = pygame.display.set_mode((W,H))
pygame.display.set_caption("Mario")
class Mario():
def __init__(self, x, y):
self.x = x
self.y = y
def draw(self):
pygame.draw.rect(screen, (255,0,0), (self.x, self.y, 40, 40))
def move(self):
global bg_x
if pressed_keys[K_RIGHT] and bg_x > -920:
if self.x > 490:
bg_x -= 5
else:
self.x += 5
if pressed_keys[K_LEFT] and self.x > 5:
self.x -= 5
def jump(self):
global jumpCount, isJump
if pressed_keys[K_SPACE]:
if jumpCount >= -10:
isJump = True
print(jumpCount)
neg = 1
if jumpCount < 0:
neg = -1
self.y -= (jumpCount ** 2) * 0.1 * neg
jumpCount -= 1
else:
isJump = False
jumpCount = 10
mario = Mario(50, 270)
while True:
clock.tick(FPS)
events()
pressed_keys = pygame.key.get_pressed()
screen.blit(background, (bg_x,0))
mario.move()
mario.draw()
mario.jump()
pygame.display.update()
Just check if isJump is true and then execute the jumping code in the jump method. I also recommend adding the isJump and jumpCount as attributes to Mario, so that you don't have to modify global variables.
To prevent the continuous jumping while Space is pressed, you have to handle the key press in the event queue. Then the jump action is triggered only once per key press not while the key is being held down.
import pygame, time, math, random, sys
from pygame.locals import *
background = pygame.Surface((640, 400))
background.fill((30, 90, 120))
W, H = 640, 400
HW, HH = W / 2, H / 2
AREA = W * H
FPS = 60
bg_x = 0
pygame.init()
clock = pygame.time.Clock()
screen = pygame.display.set_mode((W,H))
class Mario():
def __init__(self, x, y):
self.x = x
self.y = y
# isJump and jumpCount should be attributes of Mario.
self.isJump = False
self.jumpCount = 10
def draw(self):
pygame.draw.rect(screen, (255,0,0), (self.x, self.y, 40, 40))
def move(self):
global bg_x
if pressed_keys[K_RIGHT] and bg_x > -920:
if self.x > 490:
bg_x -= 5
else:
self.x += 5
if pressed_keys[K_LEFT] and self.x > 5:
self.x -= 5
def jump(self):
# Check if mario is jumping and then execute the
# jumping code.
if self.isJump:
if self.jumpCount >= -10:
neg = 1
if self.jumpCount < 0:
neg = -1
self.y -= self.jumpCount**2 * 0.1 * neg
self.jumpCount -= 1
else:
self.isJump = False
self.jumpCount = 10
mario = Mario(50, 270)
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
# Start to jump by setting isJump to True.
mario.isJump = True
clock.tick(FPS)
pressed_keys = pygame.key.get_pressed()
screen.blit(background, (bg_x,0))
mario.move()
mario.draw()
mario.jump()
pygame.display.update()
You can fix it by implementing the following rules:
you can only begin a jump when you touch the floor
you start a jump by pressing the space bar (set a variable) and stop it, when you touch the floor
you start a jump on keydown (pygame.KEYDOWN) not if pressed.
Some code snippets:
Begin jump
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE and self.y == 0:
isJump = True
End jump
if self.y == 0:
isJump = False
With this rules you can only jump, when you're on the floor. You don't need to hold the space bar and you won't jump a second time if you hold the space bar to long

Artificial inteligence in python and pygame for Pong clone

I'm making a program that clones pong based off a tutorial and I already have the program to where it is multiplayer with two separate people. I want to add an AI in the program instead of a player 2. I've been stuck on this for quite some time and would appreciate any help! Here is the code currently:
import sys, os, math, random, pygame
from pygame.locals import *
class paddle(pygame.sprite.Sprite):
def __init__(self, xy):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load(os.path.join('assets', 'pong_paddle.gif'))
self.rect = self.image.get_rect()
self.rect.centerx, self.rect.centery = xy
self.movementspeed = 5
self.velocity = 0
def up(self):
# increases vertical velocity
self.velocity -= self.movementspeed
def down(self):
# decreases vertical velocity
self.velocity += self.movementspeed
def move(self, dy):
# moves the paddle y, doesn't go out of top or bottom
if self.rect.bottom + dy > 400:
self.rect.bottom = 400
elif self.rect.top + dy < 0:
self.rect.top = 0
else:
self.rect.y += dy
def update(self):
# makes the paddle move every frame
self.move(self.velocity)
class aiplayer(object):
def __init__(self):
self.bias = random.random() - 0.5
self.hit_count = 0
def update(self, paddle, game,):
if (paddle.rect.centerx < game.bounds.centerx and game.ball.rect.centerx < game.bounds.centerx) or (paddle.rect.centerx > game.bounds.centerx and game.ball.rect.centerx > game.bounds.centerx):
delta = (paddle.rect.centery + self.bias * paddle.rect.height) - game.ball.rect.centery
if abs(delta) > paddle.velocity:
if delta > 0:
paddle.direction = -1
else:
paddle.direction = 1
else:
paddle.direction = 0
else:
paddle.direction = 0
def hit(self):
self.hit_count += 1
if self.hit_count > 6:
self.bias = random.random() - 0.5
self.hit_count = 0
def lost(self):
self.bias = random.random() - 0.5
def won(self):
pass
def render(self, surface):
x, y = self.location
w, h = self.image.get_size()
surface.blitz(self.image, (x-w/2, y-h/2))
class Ball(pygame.sprite.Sprite):
def __init__(self, xy):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load(os.path.join('assets', 'pong_ball.gif'))
self.rect = self.image.get_rect()
self.rect.centerx, self.rect.centery = xy
self.maxspeed = 10
self.servespeed = 5
self.velx = 0
self.vely = 0
def reset(self):
self.rect.centerx, self.rect.centery = 400, 200
self.velx = 0
self.vely = 0
def serve(self):
angle = random.randint(-45, 45)
if abs(angle) < 5 or abs(angle-180) < 5:
angle = random.randint(10, 20)
if random.random() > .5:
angle += 180
# this gets the velocity for the x and y coords
x = math.cos(math.radians(angle))
y = math.sin(math.radians(angle))
self.velx = self.servespeed * x
self.vely = self.servespeed * y
class Game(object):
def __init__(self):
pygame.init()
# creates the window
self.window = pygame.display.set_mode((800, 400))
# makes a clock
self.clock = pygame.time.Clock()
# window title
pygame.display.set_caption("Pong")
# tells pygame to watch for these certain events so we can close window
pygame.event.set_allowed([QUIT, KEYDOWN, KEYUP])
self.background = pygame.Surface((800, 400))
self.background.fill((55, 255, 85))
pygame.draw.line(self.background, (0,0,0), (400, 0), (400, 400), 2)
self.window.blit(self.background, (0,0))
#lets the background show up
pygame.display.flip()
#renders the sprites so that they actually show up
self.sprites = pygame.sprite.RenderUpdates()
# makes the paddles, adds to sprite group
self.leftpaddle = paddle((50, 200))
self.sprites.add(self.leftpaddle)
self.rightpaddle = paddle((750, 200))
self.sprites.add(self.rightpaddle)
# makes the ball
self.ball = Ball((400, 200))
self.sprites.add(self.ball)
def run(self):
# this lets the game run using a loop so its always active and never closes
running = True
while running:
self.clock.tick(60)
# pygame event, if user closes the game, then stop running
running = self.handleEvents()
pygame.display.set_caption("Pong %d fps" % self.clock.get_fps())
self.manageBall()
# updates the sprites(paddles, ball)
for sprite in self.sprites:
sprite.update()
# renders the sprites
self.sprites.clear(self.window, self.background)
dirty = self.sprites.draw(self.window)
pygame.display.update(dirty)
def handleEvents(self):
for event in pygame.event.get():
if event.type == QUIT:
return False
elif event.type == KEYDOWN:
if event.key == K_ESCAPE:
return False
# controls the right paddle
if event.key == K_w:
self.leftpaddle.up()
if event.key == K_s:
self.leftpaddle.down()
if event.key == K_UP:
self.rightpaddle.up()
if event.key == K_DOWN:
self.rightpaddle.down()
# serves the ball
if event.key == K_SPACE:
if self.ball.velx == 0 and self.ball.vely == 0:
self.ball.serve()
elif event.type == KEYUP:
if event.key == K_w:
self.leftpaddle.down()
if event.key == K_s:
self.leftpaddle.up()
if event.key == K_UP:
self.rightpaddle.down()
if event.key == K_DOWN:
self.rightpaddle.up()
elif event.type ==
return True
def manageBall(self):
# this moves the ball
self.ball.rect.x += self.ball.velx
self.ball.rect.y += self.ball.vely
if self.ball.rect.top < 0:
self.ball.rect.top = 1
# makes the ball bounce
self.ball.vely *= -1
elif self.ball.rect.bottom > 400:
self.ball.rect.bottom = 399
# makes ball bounce off bottom
self.ball.vely *= -1
# resets the ball if it hits the left or right screen
if self.ball.rect.left < 0:
self.ball.reset()
return
elif self.ball.rect.right > 800:
self.ball.reset()
return
collision = pygame.sprite.spritecollide(self.ball, [self.leftpaddle, self.rightpaddle], dokill = False)
if len(collision) > 0:
hitpaddle = collision[0]
# sends the ball back
self.ball.velx *= -1
# makes sure the ball doesn't get stuck in the paddle
self.ball.rect.x += self.ball.velx
# makes the game and runs it
if __name__ == '__main__':
game = Game()
game.run()
Make a function AI in the aiplayer and have it return up or down
int AI(self.position,ball.position):
if self.y>ball.y:
return -1
elif self.y<ball.y:
return 1
then, in the update() code for aiplayer, do something similar to this
self.y += movespeed*AI(self.position,ball.position)
Then, it either moves the paddle up or down depending on where the ball is ( you might need to switch if you add or subtract the movespeed to get the paddle to go the right direction). Also, it might be more effective to use the center of the paddle so that it won't put the top or bottom edge of the paddle at the ball.

Categories