import pygame
pygame.init()
win = pygame.display.set_mode((1280,800))
pygame.display.set_caption("First Game")
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')]
Joker1 = pygame.image.load('/Users/arnav/Downloads/Joker.png')
char = pygame.transform.scale(Joker1, (80, 132))
bg1 = pygame.image.load('/Users/arnav/Downloads/GothamCity.jpg')
bg = pygame.transform.scale(bg1, (1280, 800))
x = 0
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 >= 9:
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(12)
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
elif keys[pygame.K_RIGHT] or keys[ord('d')] and x < 900 - vel - width:
x += vel
left = False
right = True
else:
left = False
right = False
walkCount = 0
if not(isJump):
if keys[pygame.K_UP] or keys[ord('w')]:
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
def redrawGameWindow2():
global walkCount
if keys[pygame.K_SPACE]:
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'),
pygame.image.load('/Users/arnav/Downloads/Jokerattack4.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'),
pygame.image.load('/Users/arnav/Downloads/Jokerattack3Right.png')]
win.blit(bg, (0,0))
if walkCount + 1 >= 12:
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()
redrawGameWindow2()
pygame.quit()
In this program, I am trying to make it so that when you press arrow keys, the character walks, and when you press space, the animation extends to attack. I tried to do this by redrawing the game window for a second time and the arrow keys work but when I press space it gives me a builtins.IndexError: list index out of range pygame animation.
You're using the // floor division operator to clamp the animation index instead of modulo %.
So when you press space on the 12th frame you get an out of range error 12 // 3 = 4
Instead you need to use walkLeft[walkCount % len(walkLeft)]
0 % 4 = 0
1 % 4 = 1
[..]
4 % 4 = 0
5 % 4 = 1
Before using the index to get an item from the list, compare the index to the length of the list:
def redrawGameWindow():
global walkCount
win.blit(bg, (0,0))
if left:
if walkCount // 3 >= len(walkLeft):
walkCount = 0
win.blit(walkLeft[walkCount//3], (x,y))
walkCount += 1
elif right:
if walkCount // 3 >= len(walkRight):
walkCount = 0
win.blit(walkRight[walkCount//3], (x,y))
walkCount += 1
else:
win.blit(char, (x, y))
walkCount = 0
pygame.display.update()
Or use the % (modulo) operator. The modulo operator calculates the remainder of a division.
def redrawGameWindow():
global walkCount
win.blit(bg, (0,0))
if left:
win.blit(walkLeft[(walkCount//3) % len(walkLeft)], (x,y))
walkCount += 1
elif right:
win.blit(walkRight[(walkCount//3) % len(walkRight)], (x,y))
walkCount += 1
else:
win.blit(char, (x, y))
walkCount = 0
pygame.display.update()
Do the same for redrawGameWindow2:
def redrawGameWindow2():
# [...]
if left:
win.blit(walkLeft[(walkCount//3) % len(walkLeft)], (x,y))
walkCount += 1
elif right:
win.blit(walkRight[(walkCount//3) % len(walkRight)], (x,y))
walkCount += 1
else:
win.blit(char, (x, y))
walkCount = 0
# [...]
This question already has answers here:
Animated sprite from few images
(4 answers)
how to make image/images disappear in pygame?
(1 answer)
Closed 2 years ago.
I'm making a pygame game where a player is moving around on a screen and can buy items from a shop(bombs). I'm able to drop the bombs, now I need to replace the bomb image with an explosion image after 3 secs and check for collision with the enemy. I'm attaching my whole code along with some screenshots for reference. Any help is appreciated, thank you
import pygame
import random
pygame.font.init()
width = 900
height = 600
screen = pygame.display.set_mode([width, height])
walkRight = [pygame.image.load('R1.png'), pygame.image.load('R2.png'), pygame.image.load('R3.png'),
pygame.image.load('R4.png'), pygame.image.load('R5.png'), pygame.image.load('R6.png'),
pygame.image.load('R7.png'), pygame.image.load('R8.png'), pygame.image.load('R9.png')]
walkLeft = [pygame.image.load('L1.png'), pygame.image.load('L2.png'), pygame.image.load('L3.png'),
pygame.image.load('L4.png'), pygame.image.load('L5.png'), pygame.image.load('L6.png'),
pygame.image.load('L7.png'), pygame.image.load('L8.png'), pygame.image.load('L9.png')]
char = pygame.image.load('standing.png')
bomb_pic = pygame.transform.scale(pygame.image.load('bomb.png'), (20,20))
bomb_explosion = pygame.transform.scale(pygame.image.load('explosion1.png'), (40,40))
# char_rect = char.get_rect()
enemy_Left = [pygame.image.load('L1E.png'), pygame.image.load('L2E.png'), pygame.image.load('L3E.png'),
pygame.image.load('L4E.png'), pygame.image.load('L5E.png'), pygame.image.load('L6E.png'),
pygame.image.load('L7E.png'), pygame.image.load('L8E.png'), pygame.image.load('L9E.png')]
x = 50
y = 50
width = 40
height = 60
vel = 5
isJump = False
jumpCount = 10
left = False
right = False
down = False
up = False
walkCount = 0
enemy_vel = 2
enemy_list = []
shop = pygame.transform.scale(pygame.image.load("shop.png"), (60, 60))
clock = pygame.time.Clock()
FPS = 60
font = pygame.font.Font('freesansbold.ttf', 32)
items_font = pygame.font.Font('freesansbold.ttf', 16)
bombs =[]
bag = {'bomb': 0}
print(bag["bomb"])
class Button():
def __init__(self, color, x, y, width, height, text=''):
self.color = color
self.x = x
self.y = y
self.width = width
self.height = height
self.text = text
def draw(self, win, outline=None):
# Call this method to draw the button on the screen
if outline:
pygame.draw.rect(win, outline, (self.x - 2, self.y - 2, self.width + 4, self.height + 4), 0)
pygame.draw.rect(win, self.color, (self.x, self.y, self.width, self.height), 0)
if self.text != '':
font = pygame.font.SysFont('comicsans', 20)
text = font.render(self.text, 1, (0, 0, 0))
win.blit(text, (
self.x + (self.width / 2 - text.get_width() / 2), self.y + (self.height / 2 - text.get_height() / 2)))
def shop_run():
shop_bomb = Button((0, 200, 0), 820, 150, 60, 20, text="Bomb_b")
bright_green = (0, 255, 0)
green = (0, 200, 0)
shop_bomb.draw(screen)
def redrawGameWindow():
global walkCount
global font
global bag
global items_font
global enemy_list
screen.fill([166, 166, 166])
for five_enemies in range(6):
random_enemy_location_y = random.randrange(100, 400)
random_enemy_location_x = random.randrange(800, 840)
enemy_list.append([random_enemy_location_x, random_enemy_location_y])
for enemies in range(6):
screen.blit(enemy_Left[enemies], enemy_list[enemies])
enemy_list[enemies][0] -= 0.3
pygame.draw.rect(screen, (0, 0, 0), (800, 0, 100, 600))
if x + char.get_width() < 60 and y + char.get_height() < 60:
shop_run()
screen.blit(shop, (0, 0))
screen.blit(font.render("Menu", True, (255,255,255)),(805, 10))
screen.blit(items_font.render("Bombs: "+ str(bag["bomb"]), True, (255, 255, 255)), (805, 550))
# screen.blit(bomb_explosion, (450, 300))
if walkCount + 1 >= 27:
walkCount = 0
if left:
screen.blit(walkLeft[walkCount // 3], (x, y))
walkCount += 1
elif right:
screen.blit(walkRight[walkCount // 3], (x, y))
walkCount += 1
elif down:
screen.blit(char, (x, y))
walkcount = 0
elif up:
screen.blit(char, (x, y))
walkcount = 0
else:
screen.blit(char, (x, y))
walkCount = 0
for pos in bombs:
screen.blit(bomb_pic, pos)
pygame.display.update()
def main():
run = True
# shopper()
pygame.display.set_caption("bomb-mania")
global x
global y
global width
global height
global vel
global isJump
global jumpCount
global left
global right
global down
global up
global walkCount
global bomb_pic
global font
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if x + char.get_width() < 60 and y + char.get_height() < 60:
buy = pygame.key.get_pressed()
if buy[pygame.K_b]:
bag["bomb"] += 1
print(bag["bomb"])
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE and bag["bomb"] >= 1:
bombs.append(((x + (char.get_width()/2)),( y + (char.get_height() - 20))))
bag["bomb"] -= 1
redrawGameWindow()
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT] and x > vel - 15:
x -= vel
left = True
right = False
down = False
up = False
elif keys[pygame.K_RIGHT] and x < 800 - vel - width:
x += vel
left = False
right = True
down = False
up = False
elif keys[pygame.K_DOWN] and y < 600 - height:
y += vel
left = False
right = False
down = True
up = False
elif keys[pygame.K_UP] and y > vel - 15:
y -= vel
left = False
right = False
down = False
up = True
else:
left = False
right = False
down = False
up = False
walkCount = 0
clock.tick(FPS)
pygame.display.flip()
main()
enemies are moving towards the left
able to drop bombs
able to buy bombs from the shop
I'm adding a code below please help me troubleshoot and debug this
import pygame
import random
pygame.font.init()
width = 900
height = 600
screen = pygame.display.set_mode([width, height])
walkRight = [pygame.image.load('R1.png'), pygame.image.load('R2.png'), pygame.image.load('R3.png'),
pygame.image.load('R4.png'), pygame.image.load('R5.png'), pygame.image.load('R6.png'),
pygame.image.load('R7.png'), pygame.image.load('R8.png'), pygame.image.load('R9.png')]
walkLeft = [pygame.image.load('L1.png'), pygame.image.load('L2.png'), pygame.image.load('L3.png'),
pygame.image.load('L4.png'), pygame.image.load('L5.png'), pygame.image.load('L6.png'),
pygame.image.load('L7.png'), pygame.image.load('L8.png'), pygame.image.load('L9.png')]
char = pygame.image.load('standing.png')
bomb_pic = pygame.transform.scale(pygame.image.load('bomb.png'), (20,20))
bomb_explosion = pygame.transform.scale(pygame.image.load('explosion1.png'), (40,40))
# char_rect = char.get_rect()
enemy_Left = [pygame.image.load('L1E.png'), pygame.image.load('L2E.png'), pygame.image.load('L3E.png'),
pygame.image.load('L4E.png'), pygame.image.load('L5E.png'), pygame.image.load('L6E.png'),
pygame.image.load('L7E.png'), pygame.image.load('L8E.png'), pygame.image.load('L9E.png')]
x = 50
y = 50
width = 40
height = 60
vel = 5
isJump = False
jumpCount = 10
left = False
right = False
down = False
up = False
walkCount = 0
enemy_vel = 2
enemy_list = []
shop = pygame.transform.scale(pygame.image.load("shop.png"), (60, 60))
clock = pygame.time.Clock()
FPS = 60
font = pygame.font.Font('freesansbold.ttf', 32)
items_font = pygame.font.Font('freesansbold.ttf', 16)
bombs =[]
bag = {'bomb': 0}
bomb_timer = {"bomb0":0}
bomb_placed = False
bombCount = 1
bombs_dict = {"bomb0": False}
bombTimers = []
explosion_dict = {"explosion0": False}
print(bag["bomb"])
class Button():
def __init__(self, color, x, y, width, height, text=''):
self.color = color
self.x = x
self.y = y
self.width = width
self.height = height
self.text = text
def draw(self, win, outline=None):
# Call this method to draw the button on the screen
if outline:
pygame.draw.rect(win, outline, (self.x - 2, self.y - 2, self.width + 4, self.height + 4), 0)
pygame.draw.rect(win, self.color, (self.x, self.y, self.width, self.height), 0)
if self.text != '':
font = pygame.font.SysFont('comicsans', 20)
text = font.render(self.text, 1, (0, 0, 0))
win.blit(text, (
self.x + (self.width / 2 - text.get_width() / 2), self.y + (self.height / 2 - text.get_height() / 2)))
def shop_run():
shop_bomb = Button((0, 200, 0), 820, 150, 60, 20, text="Bomb_b")
bright_green = (0, 255, 0)
green = (0, 200, 0)
shop_bomb.draw(screen)
def redrawGameWindow():
global walkCount
global font
global bag
global items_font
global enemy_list
global bomb_timer
global bomb_placed
global explosion_dict
screen.fill([166, 166, 166])
for five_enemies in range(6):
random_enemy_location_y = random.randrange(100, 400)
random_enemy_location_x = random.randrange(800, 840)
enemy_list.append([random_enemy_location_x, random_enemy_location_y])
for enemies in range(6):
screen.blit(enemy_Left[enemies], enemy_list[enemies])
enemy_list[enemies][0] -= 0.3
pygame.draw.rect(screen, (0, 0, 0), (800, 0, 100, 600))
if x + char.get_width() < 60 and y + char.get_height() < 60:
shop_run()
screen.blit(shop, (0, 0))
screen.blit(font.render("Menu", True, (255,255,255)),(805, 10))
screen.blit(items_font.render("Bombs: "+ str(bag["bomb"]), True, (255, 255, 255)), (805, 550))
# screen.blit(bomb_explosion, (450, 300))
if walkCount + 1 >= 27:
walkCount = 0
if left:
screen.blit(walkLeft[walkCount // 3], (x, y))
walkCount += 1
elif right:
screen.blit(walkRight[walkCount // 3], (x, y))
walkCount += 1
elif down:
screen.blit(char, (x, y))
walkcount = 0
elif up:
screen.blit(char, (x, y))
walkcount = 0
else:
screen.blit(char, (x, y))
walkCount = 0
for pos in bombs:
for i in bombs_dict:
if bombs_dict["bomb"+str(bag["bomb"])]:
screen.blit(bomb_pic, pos)
bomb_timer["bomb"+str(bag["bomb"])] += clock.get_time()
if bomb_timer["bomb"+str(bag["bomb"])] >= 3000:
bombs_dict["bomb"+str(bag["bomb"])] = False
explosion_dict["explosion" + str(bag["bomb"])] = True
del bombs_dict["bomb"+str(bag["bomb"])]
else:
if explosion_dict["explosion" + str(bag["bomb"])]:
screen.blit(bomb_explosion, (pos))
if bomb_timer["bomb"+str(bag["bomb"])] >= 5000:
explosion_dict["explosion" + str(bag["bomb"])] = False
del explosion_dict["explosion" + str(bag["bomb"])]
pygame.display.update()
def main():
run = True
pygame.display.set_caption("bomb-mania")
global x
global y
global width
global height
global vel
global isJump
global jumpCount
global left
global right
global down
global up
global walkCount
global bomb_pic
global font
global bombs_dict
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if x + char.get_width() < 60 and y + char.get_height() < 60:
buy = pygame.key.get_pressed()
if buy[pygame.K_b]:
bag["bomb"] += 1
bombs_dict["bomb"+str(bag["bomb"])] = False
print(bag["bomb"])
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE and bag["bomb"] >= 1:
bombs.append(((x + (char.get_width()/2)),( y + (char.get_height() - 20))))
bombs_dict["bomb"+str(bag["bomb"])] = True
bag["bomb"] -= 1
redrawGameWindow()
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT] and x > vel - 15:
x -= vel
left = True
right = False
down = False
up = False
elif keys[pygame.K_RIGHT] and x < 800 - vel - width:
x += vel
left = False
right = True
down = False
up = False
elif keys[pygame.K_DOWN] and y < 600 - height:
y += vel
left = False
right = False
down = True
up = False
elif keys[pygame.K_UP] and y > vel - 15:
y -= vel
left = False
right = False
down = False
up = True
else:
left = False
right = False
down = False
up = False
walkCount = 0
clock.tick(FPS)
pygame.display.flip()
main()
Look at pygame.time.Clock(). If you set an FPS rate (say 20), All you have to do is:
myClock = pg.time.Clock()
FPS = 20
bomb_placed = True
bomb_timer = 0
main_loop():
myClock.tick(FPS) # This will keep your FPS at 20 or below so you can estimate time
if bomb_placed:
bomb_timer += myClock.get_time()
if bomb_timer >= 3000:
# Draw the bomb explosion to the screen
if bomb_timer >= 5000:
bomb_timer = 0
bomb_placed = False # Stops displaying the bomb explosion
Hope that helped. Feel free to check out the pygame docs on the subject:
https://www.pygame.org/docs/ref/time.html#pygame.time.Clock.get_time
Example for multiple bombs:
myClock = pg.time.Clock()
FPS = 20
bombA, bombB, bombC = False, False, False
bombA_timer, bombB_timer, bombC_timer = 0, 0, 0
bombs = [bombA, bombB, bombC]
bomb_timers = [bombA_timer, bombB_timer, bombC_timer]
main_loop():
myClock.tick(FPS)
for i in len(bombs):
if bombs[i]:
bomb_timers[i] += myClock.get_time()
if bomb_timers[i] >= 3000:
draw_explosion()
if bomb_timer >= 5000:
bomb_timers[i] = 0
bomb_placed[i] = False
This example simply loops through each of the bomb variables that represent the possible bombs on the screen- in this case a max of 3.
For lots of bombs, first create two dictionaries to hold the values of the bombs (active or not active) and their respective timers. Then loop through each of the bombs and, if the bomb is active, update the timer accordingly:
bombs = {"bomb0": False} # Create dictionaries for the bombs and their timers, with 0-1 entries. (I did one to show you what it looks like).
bombTimers = {bombTimer0: 0}
main_loop():
myClock.tick(FPS)
for i in len(bombs): # For each bomb you have created
bombName = "bomb" + str(i) # get the name of the bomb and corresponding timer
timerName = "bombTimer" + str(i)
if bombs[bombName]: # If the bomg has a value of True:
bombTimers[timerName] += myClock.get_time() # Update the timer
if bombTimers[timerName] >= 3000: # Check if you need to draw the explosion
draw_explosion()
if bomb_timer >= 5000: # Check if the bomb animation is over, and reset the bomb so that it can be used again in the future
bombTimers[timerName] = 0
bombs[bombName] = False
This code works exactly the same as the previous example, but it is much easier to work with. You can easily add more bombs while not starting with an unnecessary amount, like so:
bombCount = 1
bombs = {"bomb0": False}
bombTimers = {"bombTimer0": 0}
main_loop():
if player_placed_bomb(): # When the player drops a bomb in your game:
placed = False # Make a variable saying that you have not activaded the bomb and timer yet
for key, val in bombs: # For each bomb in the bombs dictionary:
if not val: # If the value of that bomb is False (Not being used):
val = True # Activates the bomb that was already created
placed = True # Updates the placed variable indicating that you set a bomb to active
break
if not placed: # After looping through the dictionary, if there were no inactive bomb variables:
bombs["bomb" + str(bombCounter)] = True # Create a new bomb in your dictionary, with a unique name.
bombTimers["bombTimer" + str(bombCounter)] = 0 # Created a new corresponding timer
bombCounter += 1 # Add 1 to the bombCounter, which is used to create the unique name of the next bomb you create.
# Rest of main_loop()
This code ensures that you are working with the smallest dictionaries possible to reduce unneeded computation power. When a bomb explodes, it will become false and it's matching timer reset. The first if loop in the code above ensures that all existing bombs are active, and if not reuses the old bomb and timer. If all bombs are being used, It creates new entries in the dictionaries to allow for more bombs.
I added an unnecesarry amount of comments, but I hope it makes it more understandable for you. Let me know if you have more questions on how this works. If you are unfamiliar with python dict() objects, there are lots of resources on the internet that explain them thoughroughly.
Disclaimer: I haven't actually ran the code, but it should function how it is supposed to. Let me know if it doesn't.
Here are some thoughts on the reformed code:
You use "str(bag["bombs"])" quite a bit in your code- consider defining a variable: b = str(bag["bombs"]), and using that. It would make it much simpler.
I don't know why you delete the "bombs_dict" and "explosions_dict" entries after you are finished with them. The way your loop is set up, I will result in an error. I would suggest rather than deleting the entries, you keep them and attempt to reuse them, as shown in the code snippet above.
Or, if you like deleting them, you need to figure out a way to rename certain keys in your dictionaries so that the names are in order. (if you delete bomb2 from bombs_dict, and you have bomb1 and bomb3, you need to change bomb3 to bomb2 or the loop wont work as intended). You will also need to alter your bombCount variable accordingly.
I've been trying to learn PyGame and wrote code for a simple game where you can only move left and right, how ever the animation for moving left doesn't show, however the animation for moving right does show.
I've tried going through the code my self but cant seem to find the mistake.
walkright = [pygame.image.load('R1.png'), pygame.image.load('R2.png'), pygame.image.load('R3.png'), pygame.image.load('R4.png'), pygame.image.load('R5.png'), pygame.image.load('R6.png'), pygame.image.load('R7.png'), pygame.image.load('R8.png'), pygame.image.load('R9.png')]
walkleft = [pygame.image.load('R1.png'), pygame.image.load('R2.Png'), pygame.image.load('R3.png'), pygame.image.load('R4.png'), pygame.image.load('R5.png'), pygame.image.load('R6.png'), pygame.image.load('R7.png'), pygame.image.load('R8.png'), pygame.image.load('R9.png')]
bg = pygame.image.load('bg1.jpg')
char= pygame.image.load('standing.png')
def redrawgamewindow():
global walkcount
win.blit(bg, (0,0))
if walkcount +1 >= 27 :
walkcount = 0
if right :
win.blit(walkright[walkcount//3],(x, y))
walkcount += 1
elif left:
win.blit(walkleft[walkcount//3], (x, y))
walkcount += 1
else :
win.blit(char, (x, y))
pygame.display.update()
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
if keys[pygame.K_RIGHT] and x < 852 - 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
right = False
left = False
walkcount = 0
else:
if jumpcount >= -10:
neg = 1
if jumpcount < 0 :
neg = -1
y -= (jumpcount **2 )* 0.5 * neg
jumpcount -= 1
else:
isjump = False
jumpcount = 10
redrawgamewindow()
pygame.quit()
No error messages show up when I move left.
Don't implement a game loop by a recursive function:
def redrawgamewindow():
# [...]
redrawgamewindow()
Use a while loop. The display has to be updated in the loop in every frame.
def redrawgamewindow():
run = True
while run:
# [...]
You do the update of the display only in case of "not left and not right":
def redrawgamewindow():
global walkcount
run = True
while run:
win.blit(bg, (0,0))
if walkcount +1 >= 27 :
walkcount = 0
if right :
win.blit(walkright[walkcount//3],(x, y))
walkcount += 1
elif left:
win.blit(walkleft[walkcount//3], (x, y))
walkcount += 1
else :
win.blit(char, (x, y))
pygame.display.update() # <--- DELETE
# [...]
pygame.display.update() # <--- INSERT
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
# [...]
I would like to ask your help for solving this problem of mine. I need to develop a game using only functions (NO CLASSES) in pygame.
I already manage to run the game but the animations or sprites do not update as they should. The image always stays the same when it should be changing while moving.
What am I doing wrong?
Here's the code:
import pygame
WIDTH = 800
HEIGHT= 600
pygame.display.set_caption("Nico's worst adventure")
window = pygame.display.set_mode((WIDTH, HEIGHT))
#Color #R #G #B
White = (255, 255, 255)
Black = (0, 0, 0)
Red = (255, 0, 0)
Blue = (0, 0, 255)
#Position
x = 50
y = 425
imageWidth = 64
vel = 5 #Velocity of movement
isJumping = False
jumpCount = 10
left = False
right = False
walkCount = 0
#Image port
walkRight = [pygame.image.load('Nico right(1).png'), pygame.image.load('Nico right(2).png'), pygame.image.load('Nico right(3).png'), pygame.image.load('Nico right(4).png')]
walkLeft = [pygame.image.load('Nico left(1).png'), pygame.image.load('Nico left(2).png'), pygame.image.load('Nico left(3).png'), pygame.image.load('Nico left(4).png')]
still = pygame.image.load('Nico still.png')
backgorund = pygame.image.load('Fondo.png')
def drawCharacter():
global walkCount
window.blit(backgorund, (0,0))
if walkCount + 1 >= 12:
walkCount = 0
if left:
window.blit(walkLeft[walkCount//3], (x, y))
walkCount += 1
elif right:
window.blit(walkRight[walkCount//3], (x, y))
walkCount += 1
else:
window.blit(still, (x, y))
pygame.display.update()
def draw():
global imageWidth
global WIDTH
global x
global y
global vel
global jumpCount
global isJumping
clock = pygame.time.Clock()
play = True
#Main loop
while play:
clock.tick(27)
pygame.init()
for event in pygame.event.get():
if event.type == pygame.QUIT:
play = False
key = pygame.key.get_pressed()
if key[pygame.K_LEFT] and x > vel:
x -= vel
left = True
right = False
elif key[pygame.K_RIGHT] and x < WIDTH - imageWidth - vel:
x += vel
right = True
left = False
else:
right = False
left = False
walkCount = 0
if not(isJumping):
if key[pygame.K_SPACE]:
isJumping = True
right = False
left = False
walkCount = 0
else:
if jumpCount >= -10:
neg = 1
if jumpCount < 0:
neg = -1
y -= (jumpCount ** 2) * 0.5 * neg
jumpCount -= 1
else:
isJumping = False
jumpCount = 10
drawCharacter()
pygame.display.flip()
pygame.quit()
draw()
I have already checked it and compared it to other codes but I just can't find what's the real problem.
The simple fix has already been mentioned, but I'd rather suggest getting rid of the global variables altogether and just moving them into the function with the main loop to make them local.
Also, the drawCharacter function shouldn't be responsible to update the walkCount as well as blitting the images. I'd just remove it and update the walkCount in the if key[pygame.K_LEFT]... clauses and then use it to assign the current player image to a variable (player_image) which you can blit later in the drawing section. That allows you to get rid of the left and right variables, too.
The drawCharacter function would then only consist of these two lines,
window.blit(background, (0, 0))
window.blit(player_image, (x, y))
so you could simply call them in the main loop as well instead of calling them in the function (to which you would have to pass these arguments).
By the way, call the convert or convert_alpha methods when you load the images to improve the performance.
Here's the updated code:
import pygame
pygame.init()
WIDTH = 800
HEIGHT= 600
pygame.display.set_caption("Nico's worst adventure")
window = pygame.display.set_mode((WIDTH, HEIGHT))
White = (255, 255, 255)
Black = (0, 0, 0)
Red = (255, 0, 0)
Blue = (0, 0, 255)
# Images (I assume you're using pictures with a transparent background
# so I call the `convert_alpha` method).
walkRight = [
pygame.image.load('Nico right(1).png').convert_alpha(),
pygame.image.load('Nico right(2).png').convert_alpha(),
pygame.image.load('Nico right(3).png').convert_alpha(),
pygame.image.load('Nico right(4).png').convert_alpha(),
]
walkLeft = [
pygame.image.load('Nico left(1).png').convert_alpha(),
pygame.image.load('Nico left(2).png').convert_alpha(),
pygame.image.load('Nico left(3).png').convert_alpha(),
pygame.image.load('Nico left(4).png').convert_alpha(),
]
still = pygame.image.load('Nico still.png').convert_alpha()
background = pygame.image.load('Fondo.png').convert()
def game():
clock = pygame.time.Clock()
# Player related variables.
x = 50
y = 425
imageWidth = 64
vel = 5
isJumping = False
jumpCount = 10
walkCount = 0
player_image = still # Assign the current image to a variable.
play = True
while play:
clock.tick(27)
for event in pygame.event.get():
if event.type == pygame.QUIT:
play = False
key = pygame.key.get_pressed()
if key[pygame.K_LEFT] and x > vel:
x -= vel
# Update the walkCount and image here.
walkCount += 1
player_image = walkRight[walkCount//3]
elif key[pygame.K_RIGHT] and x < WIDTH - imageWidth - vel:
x += vel
walkCount += 1
player_image = walkLeft[walkCount//3]
else:
player_image = still
walkCount = 0
if walkCount + 1 >= 12:
walkCount = 0
if not isJumping:
if key[pygame.K_SPACE]:
isJumping = True
walkCount = 0
else:
if jumpCount >= -10:
neg = 1
if jumpCount < 0:
neg = -1
y -= (jumpCount ** 2) * 0.5 * neg
jumpCount -= 1
else:
isJumping = False
jumpCount = 10
window.blit(background, (0, 0))
window.blit(player_image, (x, y)) # Just blit the current image.
pygame.display.flip() # Only one `flip()` or `update()` call per frame.
game()
pygame.quit()
It's because left and right in the draw function are local variables, not global.
A simple fix is to add
global left
global right
at the beginning of draw.
I need to develop a game using only functions (NO CLASSES) in pygame
That's a strange requirement given that pygame itself is full of classes and you use some of them already.
I am new to this website and pygame so bear with me. I am experimenting with pygame and made a simple platformer. However, whenever I 'Jump', the block jumps frame by frame, so I have to hold down the spacebar. Any help would be greatly appreciated!
here is my code:
import pygame
pygame.init()
win = pygame.display.set_mode((500, 500))
x = 0
y = 490
width = 10
height = 10
vel = 5
pygame.key.set_repeat(1)
isjump = False
jumpcount = 10
while True:
pygame.time.delay(30)
for event in pygame.event.get():
if event.type == pygame.QUIT:
break
keys = pygame.key.get_pressed()
if keys[pygame.K_a] and x>vel-5:
x -= vel
if keys[pygame.K_d] and x < 500 - width:
x += vel
if not(isjump):
if keys[pygame.K_SPACE]:
isjump = True
else:
if jumpcount >= -10:
neg = 1
if jumpcount < 0:
neg = -1
y -= (jumpcount ** 2) /2 * neg
jumpcount -= 1
else:
isjump = False
jumpcount = 10
win.fill((0, 0, 0))
pygame.draw.rect(win, (255, 255, 255), (x, y, width, height))
pygame.display.update()
pygame.quit()
You are mixing your keyboard event handling with your jump-logic. I've done two things, change the spacebar detection to trigger isjump and handle the jump logic irregardless of whether there is a key pressed or not:
import pygame
pygame.init()
win = pygame.display.set_mode((500, 500))
x = 0
y = 490
width = 10
height = 10
vel = 5
pygame.key.set_repeat(1)
isjump = False
jumpcount = 10
while True:
pygame.time.delay(30)
for event in pygame.event.get():
if event.type == pygame.QUIT:
break
keys = pygame.key.get_pressed()
if keys[pygame.K_a] and x>vel-5:
x -= vel
if keys[pygame.K_d] and x < 500 - width:
x += vel
# if we're not already jumping, check if space is pressed to start a jump
if not isjump and keys[pygame.K_SPACE]:
isjump = True
jumpcount = 10
# if we're supposed to jump, handle the jump logic
if isjump:
if jumpcount >= -10:
neg = 1
if jumpcount < 0:
neg = -1
y -= (jumpcount ** 2) /2 * neg
jumpcount -= 1
else:
isjump = False
jumpcount = 10
win.fill((0, 0, 0))
pygame.draw.rect(win, (255, 255, 255), (x, y, width, height))
pygame.display.update()
pygame.quit()
The line keys = pygame.key.get_pressed() and the whole game logic and drawing code should not be in the event loop (for event in pygame.event.get():), otherwise the code gets executed once per event in the queue, and if no events are in the queue, it won't be executed at all.
You could just dedent keys = pygame.key.get_pressed() and all lines beneath.
Alternatively, you could check in the event loop if the space key was pressed (with if event.type == pygame.KEYDOWN:) and then set isjump to True (that means the player will only jump once per keypress).
import pygame
pygame.init()
win = pygame.display.set_mode((500, 500))
clock = pygame.time.Clock()
x = 0
y = 490
width = 10
height = 10
vel = 5
isjump = False
jumpcount = 10
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
isjump = True
keys = pygame.key.get_pressed()
if keys[pygame.K_a] and x > vel - 5:
x -= vel
elif keys[pygame.K_d] and x < 500 - width:
x += vel
if isjump:
if jumpcount >= -10:
neg = 1
if jumpcount < 0:
neg = -1
y -= jumpcount**2 / 2 * neg
jumpcount -= 1
else:
isjump = False
jumpcount = 10
win.fill((0, 0, 0))
pygame.draw.rect(win, (255, 255, 255), (x, y, width, height))
pygame.display.update()
clock.tick(30)
pygame.quit()
I also recommend adding a pygame.time.Clock instance and call clock.tick(FPS) to regulate the frame rate.
And I'd rather implement the jumping in this way, with a gravity constant which gets added to the y-velocity each frame.