I am making a 2D platform game using the Python module Pygame. I have made the background, the character and the movement for said player. You can move using a & d on the keyboard and jump with SPACE. However I cannot figure out how to make an idle animation for the player. I have the running animation, but I haven't made the sprites yet, so I just used the idle picture set.
Here's my code:
import pygame, time, itertools
pygame.init()
# background image
walkRight = pygame.image.load('idle1.png')
walkLeft = pygame.image.load('idle1.png')
bg = pygame.image.load("background.png")
idle = [pygame.image.load('idle1.png'), pygame.image.load('idle2.png'), pygame.image.load('idle3.png')]
standcount = True
clock = pygame.time.Clock()
# jump
isJump = False
jumpcount = 10
# window
display_width = 1000
display_height = 600
win = pygame.display.set_mode((display_width, display_height))
# title & icon
pygame.display.set_caption("Grand Theft Ewok")
icon = pygame.image.load('bear.png')
pygame.display.set_icon(icon)
# player creds
x = 50
y = 430
vel = 10
# playerIMG
playerIMG = pygame.image.load('player.png')
def player(x, y):
global standcount
global walkcount
win.blit(bg, (0, 0))
# win.blit(playerIMG, (x,y))
if walkcount + 1 >= 9:
walkcount = 0
if standcount + 1 >= 9:
standcount = 0
if left:
win.blit(idle[walkcount // 3], (x, y))
walkcount += 1
elif right:
win.blit(idle[walkcount // 3], (x, y))
walkcount += 1
elif standcount:
p = 0
for frame in idle:
win.blit(idle[p], (x, y))
p += 1
if p >= 2:
p = 0
continue
pygame.display.update()
# game loop
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
# movement
keys = pygame.key.get_pressed()
if keys[pygame.K_a] and x > (vel - 25):
x -= vel
left = True
right = False
elif keys[pygame.K_d] and x < 835:
x += vel
right = True
left = False
else:
right = False
left = False
walkcount = 0
standcount = True
if not (isJump):
if keys[pygame.K_SPACE]:
isJump = True
left = False
right = False
else:
if jumpcount >= -10:
neg = 1
if jumpcount < 0:
neg = -1
y -= (jumpcount ** 2) * 0.5 * neg
jumpcount -= 1
else:
isJump = False
jumpcount = 10
player(x, y)
pygame.display.update()
pygame.quit()
under the player function you can see where I tried to use a for loop, but it just doesn't work.
I am using Python 3.8.
Best wishes to all.
Stay indoors, Thanks.
EDIT
I have found out how to make the idle animation using this:
elif standcount:
p = 0
for frame in idle:
win.blit(idle[standcount], (x, y))
standcount += 1
#pygame.display.update()
if standcount >= 2:
standcount = 0
continue
pygame.display.update()
However, it iterates through the list extremely fast. I cant think of a way to slow it down without using time.sleep because then it will freeze the game every time I stop moving.
Thanks
You dont need a loop, just do the same thing you did for the walking:
if left:
win.blit(idle[walkcount // 3], (x, y))
walkcount += 1
elif right:
win.blit(idle[walkcount // 3], (x, y))
walkcount += 1
else:
win.blit(idle[standcount // 3], (x, y))
standcount += 1
using a loop means it will blit all the images on top of each other in the same frame meaning you will only see the top/ last one. What you did for the walking animations works perfectly.
also, you should only have one pygame.display.update(). You should only update the screen at the end of each frame, not many times in a frame. Since you call player() right before updating the screen, you can get rid of one of them, as one will do nothing
So i found the problem, you had a standcount = True which would reset it to 1, getting rid of this solved the problem
Here is the full code edited:
import pygame, time, itertools
pygame.init()
# background image
walkRight = pygame.image.load('idle1.png')
walkLeft = pygame.image.load('idle1.png')
bg = pygame.image.load("background.png")
idle = [pygame.image.load('idle1.png'), pygame.image.load('idle2.png'), pygame.image.load('idle3.png')]
standcount = 0 # change it to an int, not a bool
clock = pygame.time.Clock()
# jump
isJump = False
jumpcount = 10
# window
display_width = 1000
display_height = 600
win = pygame.display.set_mode((display_width, display_height))
# title & icon
pygame.display.set_caption("Grand Theft Ewok")
icon = pygame.image.load('bear.png')
pygame.display.set_icon(icon)
# player creds
x = 50
y = 430
vel = 10
# playerIMG
playerIMG = pygame.image.load('player.png')
def player(x, y):
global standcount
global walkcount
win.blit(bg, (0, 0))
# win.blit(playerIMG, (x,y))
if walkcount + 1 >= 9:
walkcount = 0
if standcount + 1 >= 9:
standcount = 0
if left:
win.blit(idle[walkcount // 3], (x, y))
walkcount += 1
elif right:
win.blit(idle[walkcount // 3], (x, y))
walkcount += 1
else:
win.blit(idle[standcount // 3], (x, y))
standcount += 1
pygame.display.update()
# game loop
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
# movement
keys = pygame.key.get_pressed()
if keys[pygame.K_a] and x > (vel - 25):
x -= vel
left = True
right = False
elif keys[pygame.K_d] and x < 835:
x += vel
right = True
left = False
#you could put standcount = 0 here to reset animation after walking
else:
right = False
left = False
walkcount = 0
#got rid of standcount = True
if not (isJump):
if keys[pygame.K_SPACE]:
isJump = True
left = False
right = False
else:
if jumpcount >= -10:
neg = 1
if jumpcount < 0:
neg = -1
y -= (jumpcount ** 2) * 0.5 * neg
jumpcount -= 1
else:
isJump = False
jumpcount = 10
player(x, y)
pygame.display.update()
pygame.quit()
As for speed:
There are 2 options,
A) wait a certain amount time (i recommend)
B) wait a certain amount of frames (don't recommend)
Its best to do time as then performance doesn't affect the speed
So you already have time imported you can do this:
idle_frame_start = time.time() # get the current time - very accurate
walk_frame_start = time.time()
def player(x, y):
global standcount, idle_frame_start
global walkcount, walk_frame_start
# win.blit(playerIMG, (x,y))
if walkcount + 1 >= 4: #if the count is more than amount of images
walkcount = 0
if standcount + 1 >= 4:
standcount = 0
if left:
win.blit(idle[walkcount], (x, y))
if time.time() - walk_frame_start > 0.8:
walkcount += 1
walk_frame_start = time.time()
elif right:
win.blit(idle[walkcount], (x, y))
if time.time() - walk_frame_start > 0.8:
walkcount += 1
walk_frame_start = time.time()
else:
win.blit(idle[standcount], (x, y))
if time.time() - idle_frame_start > 0.8: # if the time difference is bigger than 0.8s
standcount += 1
idle_frame_start = time.time() # reset the start time
pygame.display.update()
Related
import pygame
pygame.init()
win = pygame.display.set_mode((1280,800))
pygame.display.set_caption("Fight")
appwallpaper = pygame.image.load('/Users/arnav/Downloads/AppWallpaper.jpeg') #setting
the apps wallpaper storing it in a variable
pygame.display.set_icon(appwallpaper) #setting the apps wallpaper as the poster
walkLeft = [pygame.image.load('/Users/arnav/Downloads/Jokerattack1.png'),
pygame.image.load('/Users/arnav/Downloads/Jokerattack2.png'),
pygame.image.load('/Users/arnav/Downloads/Jokerattack3.png')]
walkRight = [pygame.image.load('/Users/arnav/Downloads/Jokerattack1Right.png'),
pygame.image.load('/Users/arnav/Downloads/Jokerattack2Right.png'),
pygame.image.load('/Users/arnav/Downloads/Jokerattack3Right.png')]
walkLeft2 = [pygame.image.load('/Users/arnav/Downloads/Jokerattack1.png'),
pygame.image.load('/Users/arnav/Downloads/Jokerattack2.png'),
pygame.image.load('/Users/arnav/Downloads/Jokerattack3.png'),
pygame.image.load('/Users/arnav/Downloads/Jokerattack4.png')]
walkRight2 = [pygame.image.load('/Users/arnav/Downloads/Jokerattack1Right.png'),
pygame.image.load('/Users/arnav/Downloads/Jokerattack2Right.png'),
pygame.image.load('/Users/arnav/Downloads/Jokerattack3Right.png'),
pygame.image.load('/Users/arnav/Downloads/Jokerattack4Right.png')]
Joker1 = pygame.image.load('/Users/arnav/Downloads/Joker.png')
char = pygame.transform.scale(Joker1, (100, 165))
bg1 = pygame.image.load('/Users/arnav/Downloads/fighterbackground.png')
bg = pygame.transform.scale(bg1, (1280, 800))
x = 50
y = 550
width = 40
height = 60
vel = 5
clock = pygame.time.Clock()
isJump = False
jumpCount = 10
left = False
right = False
space = False
walkCount = 0
currentWalk = walkLeft
def redrawGameWindow():
global walkCount
win.blit(bg, (0,0))
if walkCount + 1 >= 9:
walkCount = 0
if left:
currentWalk = walkLeft
win.blit(currentWalk[walkCount//3], (x,y))
walkCount += 1
elif right:
currentWalk = walkRight
win.blit(currentWalk[walkCount//3], (x,y))
walkCount += 1
elif space:
win.blit(bg, (0,0))
if walkCount + 1 >= 12:
walkCount = 0
currentWalk = walkLeft2
win.blit(currentWalk[walkCount//3], (x,y))
walkCount += 1
else:
win.blit(char, (x, y))
walkCount = 0
pygame.display.update()
run = True
while run:
clock.tick(27)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT] or keys[ord('a')] and x > vel:
x -= vel
left = True
right = False
space = False
currentWalk = walkLeft
elif keys[pygame.K_RIGHT] or keys[ord('d')] and x < 1000 - vel - width:
x += vel
left = False
right = True
space = False
currentwalk = walkRight
else:
left = False
right = False
space = False
walkCount = 0
if not(isJump):
if keys[pygame.K_UP] or keys[ord('w')]:
isJump = True
left = False
right = False
space = False
walkCount = 0
else:
if jumpCount >= -10:
y -= (jumpCount * abs(jumpCount)) * 0.5
jumpCount -= 1
else:
jumpCount = 10
isJump = False
if keys[ord('n')]:
x -= vel
left = False
right = False
space = True
currentWalk = walkLeft2
if keys[ord('z')]:
x -= vel
left = False
right = False
space = True
currentWalk = walkLeft2
if x <= 0:
x = 0
elif x >= 1100:
x = 1100
redrawGameWindow()
def redrawgamewindow2():
currentWalk = walkLeft2
win.blit(bg, (0,0))
if walkCount + 1 >= 12:
walkCount = 0
if left:
win.blit(currentWalk[walkCount//3], (x,y))
walkCount += 1
elif right:
win.blit(walkRight[walkCount//3], (x,y))
walkCount += 1
else:
win.blit(char, (x, y))
walkCount = 0
keys = pygame.key.get_pressed()
if keys[pygame.K_SPACE]:
currentWalk = True
pygame.display.update()
pygame.quit()
In this program, I have 2 animations and I am using currentWalk to differentiate and use both animations. I have used walkCount to animate and most parts of the program are working and it is running fine, problem is that when I press Z or N to animate walkLeft2, it doesnt animate and instead dissapears. When I let go it reeapears and you can see that it moved left but the actual movement isnt visible.
It is a matter of Indentation:
def redrawGameWindow():
# [...]
elif space:
win.blit(bg, (0,0))
if walkCount + 1 >= 12:
walkCount = 0
# INDENTATION
#<--|
currentWalk = walkLeft2
win.blit(currentWalk[walkCount//3], (x,y))
walkCount += 1
Hello I am new to stack overflow and python and I need some help with this coding error I get. I followed Tech with Tim's tutorial on creating sprite movement and I'm coming across an error message when I move my sprite around.
Here's a link to the video I followed:
https://www.youtube.com/watch?v=UdsNBIzsmlI
The jump movement seems to be working but I get an error message when I move my character/sprite more than 3 steps to the left/right.
Here's the error message I get:
Traceback (most recent call last):
File "C:\Users\Desktop\PYGAME Folder\Game Code.py", line 90, in <module>
redrawGameWindow()
File "C:\Users\Desktop\PYGAME Folder\Game Code.py", line 40, in redrawGameWindow
win.blit(walkRight[walkCount//3], (x,y))
TypeError: argument 1 must be pygame.Surface, not str
Here's the code using Tech with Tim's example:
import pygame
pygame.init()
win = pygame.display.set_mode((500,480))
pygame.display.set_caption("First Game")
walkRight = [pygame.image.load('R1.png'), ('R2.png'), ('R3.png'), ('R4.png'), ('R5.png'), ('R6.png'), ('R7.png'), ('R8.png'), ('R9.png')]
walkLeft = [pygame.image.load('L1.png'), ('L2.png'), ('L3.png'), ('L4.png'), ('L5.png'), ('L6.png'), ('L7.png'), ('L8.png'), ('L9.png')]
bg = pygame.image.load('bg.jpg')
char = pygame.image.load('standing.png')
x = 50
y = 400
width = 40
height = 60
vel = 5
clock = pygame.time.Clock()
isJump = False
jumpCount = 10
left = False
right = False
walkCount = 0
def redrawGameWindow():
global walkCount
win.blit(bg, (0,0))
if walkCount + 1 >= 27:
walkCount = 0
if left:
win.blit(walkLeft[walkCount//3], (x,y))
walkCount += 1
elif right:
win.blit(walkRight[walkCount//3], (x,y))
walkCount += 1
else:
win.blit(char, (x, y))
walkCount = 0
pygame.display.update()
run = True
while run:
clock.tick(27)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT] and x > vel:
x -= vel
left = True
right = False
elif keys[pygame.K_RIGHT] and x < 500 - width - vel:
x += vel
left = False
right = True
else:
left = False
right = False
walkCount = 0
if not(isJump):
if keys[pygame.K_SPACE]:
isJump = True
left = False
right = False
walkCount = 0
else:
if jumpCount >= -10:
y -= (jumpCount * abs(jumpCount)) * 0.5
jumpCount -= 1
else:
jumpCount = 10
isJump = False
redrawGameWindow()
pygame.quit()
In walkRight, only the first image is actually loaded. The others are just the filenames. There is the same issue with walkLeft.
See if this resolves the problem:
walkRight = [pygame.image.load(i) for i in ['R1.png', 'R2.png', 'R3.png', 'R4.png', 'R5.png', 'R6.png', 'R7.png', 'R8.png', 'R9.png']]
For more concise code try this:
walkRight = [pygame.image.load("R%d.png"%i) for i in range(1,10)]
What I am trying to do here is make my collision detect allow me to jump on a square but it doesn't seem to work. Its a the very bottom of the main loop.
# --- COLLISION is at the bottom of main loop
# ------
# this is a pygame module that I imported
import pygame
pygame.init()
# this is just my screen I created win defines it
win = pygame.display.set_mode((500,500))
# this is my caption for my game
pygame.display.set_caption("Just Tryna learn Something")
# these are my coordinates for my enemy where it will spawn
cordx = 300
cordy = 300
heights = 70
widths = 70
# my Player Coordinate and its speed and and its Jump
x = 200
y = 200
height = 40
width = 40
speed = 5
isJump = False
jumpCount = 10
# main loop
# main loop for my game
running = True
while running:
pygame.time.delay(100)
win.fill((0,0,0))
#-----------------------------------------------------------------------------------------
# this here draws my player in my window
Player = pygame.draw.rect(win, (140, 0,150), (x, y, height, width))
#-----------------------------------------------------------------------------------------
# this here draws my enemy
Enemy = pygame.draw.rect(win, (90,90,90), (cordx, cordy, heights, widths))
#=-------------------------------------------------------------------------------------
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
#-------------------------------------------------------------------
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
x -= speed
if keys[pygame.K_RIGHT]:
x += speed
# this here is my functions for movement and Jumping
if not(isJump):
if keys[pygame.K_UP]:
y -= speed
if keys[pygame.K_DOWN]:
y += speed
if keys[pygame.K_SPACE]:
isJump = True
else:
if jumpCount >= -10:
y -= (jumpCount * abs(jumpCount)) * 0.5
jumpCount -= 1
else:
jumpCount = 10
isJump = False
# COLLISION here is my collision detect and collision
its suppose to make me stand on the square with my little box when I jump on it
but it doesnt seem to work (Enemy) is the big box and (Player) is the little box
if Player.colliderect(Enemy):
pygame.draw.rect(win, (150,0,140), (50, 50, 20, 70))
if Player.top >= 375 and Player.top <= 370:
x = 375
# ---------------------------------------------------------
pygame.display.update()
pygame.quit()
Continuously let the player fall down. Add a variable fall = 0 and the variable to y and increment fall in every frame, if the player is not jumping. A jump ends, if the player reaches the maximum jump height (jumpCount == 0):
if not isJump:
y += fall
fall += 1
# [...]
else:
if jumpCount > 0:
y -= (jumpCount * abs(jumpCount)) * 0.5
jumpCount -= 1
else:
jumpCount = 10
isJump = False
Limit the player to the bottom of the window (500), and the top of the block by setting the y coordinate of the player:
Player.topleft = (x, y)
collide = False
if Player.colliderect(Enemy):
y = Enemy.top - Player.height
collide = True
if Player.bottom >= 500:
y = 500 - Player.height
collide = True
It is only allowed to jump, if the player stands on the ground or on the block:
if collide:
if keys[pygame.K_SPACE]:
isJump = True
fall = 0
Furthermore use pygame.time.Clock() and tick(), instead of pygame.time.delay() for a smooth movement. Control the speed by the flops per second (FPS):
FPS = 60
clock = pygame.time.Clock()
running = True
while running:
clock.tick(FPS)
#pygame.time.delay(100)
See the example:
# --- COLLISION is at the bottom of main loop
# ------
# this is a pygame module that I imported
import pygame
pygame.init()
# this is just my screen I created win defines it
win = pygame.display.set_mode((500,500))
# this is my caption for my game
pygame.display.set_caption("Just Tryna learn Something")
# these are my coordinates for my enemy where it will spawn
cordx = 300
cordy = 350
heights = 70
widths = 70
# my Player Coordinate and its speed and and its Jump
x = 200
y = 200
height = 40
width = 40
speed = 5
isJump = False
jumpCount = 10
fall = 0
FPS = 60
clock = pygame.time.Clock()
# main loop
# main loop for my game
running = True
while running:
clock.tick(FPS)
#pygame.time.delay(100)
win.fill((0,0,0))
#-----------------------------------------------------------------------------------------
# this here draws my player in my window
Player = pygame.draw.rect(win, (140, 0,150), (x, y, height, width))
#-----------------------------------------------------------------------------------------
# this here draws my enemy
Enemy = pygame.draw.rect(win, (90,90,90), (cordx, cordy, heights, widths))
#=-------------------------------------------------------------------------------------
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
#-------------------------------------------------------------------
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
x -= speed
if keys[pygame.K_RIGHT]:
x += speed
# this here is my functions for movement and Jumping
if not isJump:
y += fall
fall += 1
Player.topleft = (x, y)
collide = False
if Player.colliderect(Enemy):
collide = True
y = Enemy.top - Player.height
if Player.right > Enemy.left and Player.left < Enemy.left:
x = Enemy.left - Player.width
if Player.left < Enemy.right and Player.right > Enemy.right:
x = Enemy.right
if Player.bottom >= 500:
collide = True
y = 500 - Player.height
if collide:
if keys[pygame.K_SPACE]:
isJump = True
fall = 0
else:
if jumpCount > 0:
y -= (jumpCount * abs(jumpCount)) * 0.5
jumpCount -= 1
else:
jumpCount = 10
isJump = False
pygame.display.update()
pygame.quit()
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
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!