Pygame sprite double jump - python

So I'm relatively new to pygame, and have started to branch off from a basic tutorial. I want the sprite to be able to double jump and have attempted to add in a variable etc so I can change it to a triple jump if they eventually gain a power up or some sort, and I can change it easily, but I'm struggling. P.S: Some of the comments might not make sense as some code has been removed, but are still useful to me.
x = 200
y = 450
width = 64
height = 66
vel = 5
screenwidth = 500
isjump = True #whether our character is jumping or not
jumpcount = 10
maxjump = 2 #double jump
maxjumpcount = 0
#we must keep track of direction, are they moving and how many steps for frames
left = False
right = False
walkcount = 0
def redrawGameWindow():
global walkcount
window.blit(background,(0,0)) #loads bg at 0,0
if walkcount +1 >= 15: #15 as we have 5 sprites, which will be displayed 3 times per second
walkcount = 0
if left:
window.blit(walkleft[walkcount//3],(x,y))#excludes remainders
walkcount+=1
elif right:
window.blit(walkright[walkcount//3],(x,y))
walkcount+=1
elif isjump:
window.blit(jumpp,(x,y))
walkcount+=1
else:
window.blit(char,(x,y))
pygame.display.update()
#now to write main loop which checks for collisions, mouse events etc
run = True
while run: #as soon as we exit this, the game ends
#main loop, gonna check for collision
clock.tick(15) #frame rate, how many pics per second, games r just a ton of pictures running very quickly
#now we check for events
for event in pygame.event.get(): #gets a list of all events that happened
print(event)
#can go through these events& check if they've happened
if event.type == pygame.QUIT: #if we try to exit the window
run = False
through the use of events. If a key has been pressed, we change the x & y of our shape
#if we want it to continuely move, we need to get a list
keys = pygame.key.get_pressed() #if these are pressed or held down, execute whatever is under these.
if keys[pygame.K_LEFT] and x > vel-vel: #if pressed we move our character by the velocity in whatever direction via grid which works from the TOP LEFT of screen
#0,0 is top left #vel-vel to equal 0, makes border better
x -= vel
left = True
right = False
elif keys[pygame.K_RIGHT] and x < screenwidth - width: #as the square co ord is top left of it
x+= vel
right = True
left = False
else:
right = False
left = False
walkcount = 0
#JUMP CODE
if not(isjump): # still lets them move left and right
if keys[pygame.K_SPACE]:
isjump = True #quadratic function for jump
right = False
left = False
walkcount = 0
maxjumpcount+=1
if maxjumpcount > 2:
isjump = False
else:
while jumpcount >= -10 and maxjumpcount < 2: #moving slower, then faster, hang, then go down
pygame.time.delay(12)
y -= (jumpcount*abs(jumpcount)) / 2#1.35? #squared, 10 ^2, /2, jumpcount = jump height
jumpcount -= 1
else: #jump has concluded if it reaches here
isjump = False
jumpcount = 10
maxjumpcount = 0 #double jump resets once jump ends
redrawGameWindow()
Apologies for quite a pathetic attempt. Any other suggestions would be greatly appreciated as I still have so much to learn. Thanks.

You have a game loop, use it. You don't need an extra loop for the jump. Use a selection (if) instead of the inner while loop, to solve the issue:
run = True
while run: #as soon as we exit this, the game ends
# [...]
if not(isjump): # still lets them move left and right
if keys[pygame.K_SPACE]:
# [...]
else:
# instead of: while jumpcount >= -10 and maxjumpcount < 2:
if jumpcount >= -10 and maxjumpcount < 2: # <---------------
y -= (jumpcount*abs(jumpcount)) / 2
jumpcount -= 1
Note, this block of code is continuously called in the main application loop.

Related

Why I can't move my character with a joystick in Python?

I'm trying to make my game be able to be played with a xbox one controller, I can make it shoot and exit the game but I'm having trouble with the axis (I've tried with the D-pad but it was the same)
EDIT: Now i can make it move but It's like a frame, and I need to move the axis multiple times to make it move, I want to hold the axis 1 and that the player moves smoothly and it always moves left for some reason.
This is the Player class:
class Player(pygame.sprite.Sprite):
def update(self):
self.speed_x = 0
for event in pygame.event.get():
if event.type == JOYAXISMOTION:
if event.axis <= -1 >= -0.2:
self.speed_x = PLAYER_SPEED
if event.axis <= 1 >= 0.2:
self.speed_x = -PLAYER_SPEED
self.rect.x += self.speed_x
The Joystick only gives you notice of changes to position. So if it's previously sent an event to say that the joystick's left-right axis is at 0.5, then joystick axis is still at 0.5.
So you probably need something like:
PLAYER_SPEED = 7
...
for event in pygame.event.get():
if event.type == JOYAXISMOTION:
if event.axis == 1: # possibly left-right
player.speed_x = PLAYER_SPEED * event.value
elif event.axis == 2: # possibly up-down
player.speed_y = PLAYER_SPEED * event.value
...
# In main loop
movePlayer( player.speed_x, player.speed_y )
How the axes map to up/down and left/right is dependent on the joystick type. So maybe you will need to reverse the mapping.

Collision with enemy in pygame making player lose multiple lives

I'm trying to make it so then when an enemy collides with the player, a single life is lost and the player is positioned at the center of the screen. It works about half of the time, but the other half of the time two or three lives are lost from one collision.
def collide(self):
for enemy in enemies:
if ((robot.hitbox[0] < enemy.x + 16 < robot.hitbox[0] + robot.hitbox[2]) or (robot.hitbox[0] < enemy.x - 16 < robot.hitbox[0] + robot.hitbox[2])) and ((robot.hitbox[1] < enemy.y + 16 < robot.hitbox[1] + robot.hitbox[3]) or (robot.hitbox[1] < enemy.y - 16 < robot.hitbox[1] + robot.hitbox[3])):
robot.alive = False
robot.x = 400
robot.y = 300
for enemy in enemies:
enemies.remove(enemy)
robot.lives -= 1
robot.alive = True
This is a function under the class Enemy which is called inside of the Enemy's draw function, which is called in the while loop.
while running:
## add if robot.alive == True into loop
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
userInput = pygame.key.get_pressed()
if len(enemies) <= 3:
randSpawnX = random.randint(32, 768)
randSpawnY = random.randint(77, 568)
if (robot.x - 100 <= randSpawnX <= robot.x + 100) or (robot.y - 100 <= randSpawnY <= robot.y + 100):
randSpawnX = random.randint(32, 768)
randSpawnY = random.randint(77, 568)
else:
enemy = Enemy(randSpawnX, randSpawnY)
enemies.append(enemy)
if robot.alive == True:
for enemy in enemies:
enemy.move()
robot.shoot()
robot.movePlayer(userInput)
drawGame()
Could anyone help me figure out why this is occurring? I believe it's because multiple collisions are registering but since I move the robot to the middle of the screen as soon as the first hit is registered and before the lives are lost, why is this happening?
Read How do I detect collision in pygame? and use pygame.Rect / colliderect() for the collision detection.
Read How to remove items from a list while iterating? and iterate through a copy of the list.
If you encounter a collision, it is not enough to change the player's x and y attributes. You also need to change the hitbox. Additionally break the loop when a collision is detected:
def collide(self):
robot_rect = pygame.Rect(*robot.hitbox)
for enemy in enemies[:]:
enemy_rect = pygame.Rect(enemy.x, enemy.y, 16, 16)
if robot_rect.colliderrect(enemy_rect):
enemies.remove(enemy)
robot.x, robot.y = 400, 300
robot.hitbox[0] = robot.x
robot.hitbox[1] = robot.y
robot.lives -= 1
break

Pygame sprites behaving incorrectly when moving left

Alright so following up to my previous question I've made some progress, game has the addition of left and right movement and a simple jump script, evolution woo :D
My latest addition was an Idle animation and now the dude can't move left :D
I hope its not too silly I checked everything but can't point out the issue >.> ..
regardless here's the code, Thanks in advance, truly appreciative! (origination is awful srry >.<):
import pygame
pygame.init()
path = "C:/Users/user/Documents/Le game/"
win = pygame.display.set_mode((800, 700))
pygame.display.set_caption("Potato ultra")
bg = pygame.image.load(path + "BG.jpg")
walk_right = [pygame.image.load("C:/Users/user/Documents/Le game/R2.png"), pygame.image.load("C:/Users/user/Documents/Le game/R3.png"), pygame.image.load("C:/Users/user/Documents/Le game/R4.png"), pygame.image.load("C:/Users/user/Documents/Le game/R5.png"), pygame.image.load("C:/Users/user/Documents/Le game/R6.png"), pygame.image.load("C:/Users/user/Documents/Le game/R7.png"), pygame.image.load("C:/Users/user/Documents/Le game/R8.png"), pygame.image.load("C:/Users/user/Documents/Le game/R9.png")]
walk_left = [pygame.image.load("C:/Users/user/Documents/Le game/L2.png"), pygame.image.load("C:/Users/user/Documents/Le game/L3.png"), pygame.image.load("C:/Users/user/Documents/Le game/L4.png"), pygame.image.load("C:/Users/user/Documents/Le game/L5.png"), pygame.image.load("C:/Users/user/Documents/Le game/L6.png"), pygame.image.load("C:/Users/user/Documents/Le game/L7.png"), pygame.image.load("C:/Users/user/Documents/Le game/L8.png"), pygame.image.load("C:/Users/user/Documents/Le game/L9.png")]
Static = pygame.image.load("C:/Users/user/Documents/Le game/Idle.png")
SW = 800
SH = 700
x = 0
y = 480
width = 64
height = 64
vel = 20
isJump = False
MoveLeft = False
MoveRight = False
Idle = False
JumpCount = 10
walkCount = 0
def redrawGameWindow():
win.blit(bg, (0,0))
global walkCount
if not Idle:
if MoveRight:
if walkCount <= 7:
win.blit(walk_right[walkCount], (x, y))
elif walkCount > 7:
walkCount = 0
win.blit(walk_right[walkCount], (x, y))
if MoveLeft:
if walkCount <= 7:
win.blit(walk_left[walkCount], (x, y))
elif walkCount > 7:
walkCount = 0
win.blit(walk_left[walkCount], (x, y))
else:
win.blit(Static, (x, y))
pygame.display.update()
run = True
while run:
pygame.time.delay(50)
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 > 0:
Idle = False
MoveRight = False
MoveLeft = True
x -= vel
walkCount += 1
if keys[pygame.K_RIGHT] and x < SW - width:
Idle = False
MoveRight = True
MoveLeft = False
x += vel
walkCount += 1
else:
Idle = True
if not isJump:
if keys[pygame.K_UP] and y > 0:
y -= vel
if y < 0:
y = 0
if keys[pygame.K_DOWN] and y < SH - height:
y += vel
if y > 636:
y = 636
if keys[pygame.K_SPACE]:
isJump = True
else:
if JumpCount >= -10:
y -= (JumpCount * 4)
if y < 0:
y = 0
JumpCount -= 2
else:
isJump = False
JumpCount = 10
redrawGameWindow()
pygame.quit()
Well, the first thing I would do would be to add the following code (before the final line below, which you already have):
print("DEBUG1 keyl =", keys[pygame.K_LEFT], "x =", x)
print("DEBUG2 keyr =", keys[pygame.K_RIGHT], "SW =", Sw, "wid =", width)
print("DEBUG3 mover =", MoveRight, "movel =", MoveLeft)
print("DEBUG4 vel =", vel, "walkc =", walkCount)
print("DEBUG5 ==========")
if keys[pygame.K_LEFT] and x > 0:
That way, you'll see all the variables that take part in deciding left and right moves, and it will hopefully become obvious what is preventing the left move from functioning.
Based on a slightly deeper look at your code, it appears to be this bit:
if keys[pygame.K_LEFT] and x > 0:
Idle = False
MoveRight = False
MoveLeft = True
x -= vel
walkCount += 1
if keys[pygame.K_RIGHT] and x < SW - width:
Idle = False
MoveRight = True
MoveLeft = False
x += vel
walkCount += 1
else:
Idle = True
Since that else belongs only to the second if statement, it will fire whenever the right key is not being pressed, regardless of whether you're pressing the left key.
I suspect you can fix this simply by changing it from an if, if, else sequence to an if, elif, else sequence, so that the else fires only if neither of the keys are pressed.
A couple of possible improvements to your code:
you can get rid of all that walkCount checking and adjusting in the redraw function by simply using walkCount = (walkCount + 1) % 8 in the event loop - this will ensure it wraps from seven to zero without further effort.
you don't appear to have limiters on the x value. For example, if x == 5 and vel == 10, it's possible that a left move will set x = -5 which may not be desirable. You have more knowledge of the game play than me so I could be wrong, but it's worth checking.
you may not need both MoveLeft and MoveRight. The Idle flag decides whether you're moving or not so, if you are moving, it's either left or right. So a Idle/MoveRight combo should be enough for the code to figure out what to do. Again, this is a gameplay issue, something to look at but I may be incorrect.
not sure how your sprites look when they jump but you may be better off using constant acceleration formulae for calculating y position. I've answered similar questions before so you can have a look at this answer for guidance.

How to reflect the ball off paddle

Im trying out pygame for the first time, now ive gotten very comfortable with python as a language, and ive been trying to recreate Pong, like the old school game with 2 paddles and a ball. I cant seem to figure out how to get the ball to reflect off the paddle. Im not looking for angles and stuff yet, cos ill be able to figure that out on my own.
Buttt what ive thought of is to get a range of coordinates, which are the X & Y of the paddle and the x & y + the width and height, and if the ball enters these, it simply reflects as it does at a boundary. Ive tried doing multiple if statements, as you can see in the code below, but ive also tried doing it as a single statement, but that doesnt work. None of the debug prints ive put in actually print, but when i test the coord ranges with print they look fine :D
Ill paste my code here so you guys can run my game as is.
Id really appreciate your guys help!
import pygame
pygame.init()
win = pygame.display.set_mode((500,500))
pygame.display.set_caption("First Game")
x = 50
y = 50
width = 10 #sets variables for the main paddle
height = 60
vel = 5
ballx = 250
bally = 250
radius = 5
direction = True #True is left, False is right
bvel = 4 #sets variables for the ball
angle = 0
coordxGT = 0
coordxLT = 0 #sets variables for the coordinate ranges of the first paddle for collision
coordyGT = 0
coordyLT = 0
def setCoords():
coordxGT = x
coordxLT = x + width
coordyGT = y #This function updates the coords throughout the main loop
coordyLT = y + height
coordxLT += radius
coordyLT += radius
run = True
while run == True:
pygame.time.delay(20)
for event in pygame.event.get(): #on quit, quit the game and dont throw up an error :)
if event.type == pygame.QUIT:
run = False
setCoords()
if direction == True: #Ball movement
ballx -= bvel
else:
ballx += bvel
if ballx<0:
ballx += bvel
direction = False
elif bally<0:
bally += bvel
elif ballx>495: #if the ball hits an edge
ballx -= bvel
direction = True
elif bally>495:
bally -= bvel
if ballx<coordxLT and ballx>coordxGT:
print("S1")
if bally<coordyLT and bally>coordyGT: #THE PART I CANT FIGURE OUT. If the ball lands within these ranges of coordinates, reflect it and change its direction
print("S2")
if direction == True:
print("YES")
ballx += bvel
direction = False
keys = pygame.key.get_pressed() #gets the keys pressed at that current time
if keys[pygame.K_DOWN]:
bally += bvel #Ball control (For debugging)
if keys[pygame.K_UP]:
bally -= bvel
if keys[pygame.K_w]:
y -= vel
if keys[pygame.K_a]:
x -= vel
if keys[pygame.K_s]: #Paddle controls
y += vel
if keys[pygame.K_d]:
x += vel
if x<0:
x += vel
if y<0:
y += vel
if x>80:
x -= vel #Stops the paddle from moving if it hits a boundary
if y>440:
#440 because window height - height of cube
y -= vel
win.fill((0,0,0))
pygame.draw.circle(win, (255, 255, 255), (ballx, bally), radius) #refreshes the screen
pygame.draw.rect(win,(255,255,255),(x, y, width, height))
pygame.display.update()
pygame.quit()
You are close, but you missed to declare the variables coordxGT, coordxLT, coordxLT, coordyLT to be global.
def setCoords():
global coordxGT, coordxLT, coordxLT, coordyLT
coordxGT = x
coordxLT = x + width
coordyGT = y
coordyLT = y + height
coordxLT += radius
coordyLT += radius
Note, if you want to write to a variable in global namespace in a function, then the varible has be interpreted as global. Otherwise an new variable in the scope of the function will be created and set. See global statement.

Blit function not working, is loop going to fast?

Hey I'm working on a gravity function for my Super Mario bross. I would like a smooth movement of gravity.But my player is like teleporting from top to the ground.
I though it was the loop that was going too fast and pygame couldn't blit the image but i've tried to slow the loop with time.sleep() or pygame.time.wait()
It is not working.
At the start it's like this :
Image : Before
Image : One sec later
Thanks for helping !
def moove(self,keys):
if(self.gravity()):
if keys[pygame.K_LEFT]:
self.orientation = "Left"
if not(self.x - vel<0) and not self.collision_with_walls():
map.draw()
self.rect.x -= vel
camera.update(player)
self.draw_player()
def gravity(self):
refresh = 0
self.collision_with_ground = False
while not self.collision_with_ground:
self.rect.y += 1
blocks_hit_list = pygame.sprite.spritecollide(self,sol_sprites,False)
if not(blocks_hit_list == []):
self.collision_with_ground = True
self.rect.y -= 1
map.draw()
player.draw_player()
return True
else:
map.draw()
player.draw_player()
pygame.time.wait(10)
In your line: while not self.collision_with_ground: you are ensuring that you will not leave this loop until your player has reached the ground. You will never blit (which is outside this loop) until this loop has been left. Try if instead of while and move your other functions outside that loop (you should probably take them out of this function):
def gravity(self):
refresh = 0
self.collision_with_ground = False
if not self.collision_with_ground:
self.rect.y += 1
blocks_hit_list = pygame.sprite.spritecollide(self,sol_sprites,False)
if not(blocks_hit_list == []):
self.collision_with_ground = True
self.rect.y -= 1
map.draw()
player.draw_player()
return True
map.draw()
player.draw_player()
pygame.time.wait(10)

Categories