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)
Related
Im making a simple game where u can jump, and theres gravity.
Gravity is represented using
def updatecollision(self):
global colision
colision = self.hitbox.colliderect(suelo.rect)
if not
collision:
self.rect.y += 40
As you can see, whenever player collides with suelo.rect, it stops falling. Problem is, theres a point where the self.rect.y applies a movement that phases through the suelo.rect, phasing it.
Hitbox rect actually is a rect that covers my PNG file, whereas Rect is the entire section of the png, including transparent pixels.
I thought about using regular rect to check when theres less than 20 pixels beetween the suelo.rect and hitbox.rect, so the change of position modifier makes up and doesnt phase.
A bigger section of my code:
def controlarkeys(self):
global jump
global contadorSalto
global saltoMax
if jump:
self.rect.y -= contadorSalto
if contadorSalto > -saltoMax:
contadorSalto -= 3
else:
jump = False
def updatecolisiones(self):
global colision
colision = self.hitbox.colliderect(suelo.rect)
def dibujar(self, pantalla):
if not colision:
self.rect.y *= 1.02
while True:
for evento in pygame.event.get():
if evento.type==pygame.QUIT:
sys.exit()
if evento.type == pygame.KEYDOWN:
if not jump and colision and evento.key == pygame.K_SPACE:
jump = True
contadorSalto = saltoMax
print(evento)
migue.updatecolisiones()
migue.controlarkeys()
pantalla.fill(color)
suelo.updt(pantalla)
migue.dibujar(pantalla)
I am working on a school project with pygame and have unfortunately run into trouble with animating my sprites, or more specifically, changing the sprite from one to another, and I'm unsure on how to do it. Currently, I have a class of my spaceship sprite and background sprite:
game_folder = os.path.dirname(__file__)
img_folder = os.path.join(game_folder, 'img')
space_background = pygame.image.load('background.png').convert()
starship_1 = pygame.image.load('starship2.png').convert()
starship_2 = pygame.image.load('starship3.png').convert()
starship_3 = pygame.image.load('starship4.png').convert()
class starship(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
pygame.sprite.Sprite.__init__(self)
self.image = pygame.transform.scale(starship_1, (150,150))
self.image.set_colorkey(black)
self.rect = self.image.get_rect()
self.rect.center = (400, 400)
all_sprites = pygame.sprite.Group()
BackGround = background()
StarShip = starship()
all_sprites.add(BackGround)
all_sprites.add(StarShip)
My while loop looks like this:
run = True
while run:
pygame.time.delay(100)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT] and StarShip.rect.x > 25:
StarShip.rect.x -= vel
if keys[pygame.K_RIGHT] and StarShip.rect.x < 600:
StarShip.rect.x += vel
if keys[pygame.K_UP] and StarShip.rect.y > 25:
StarShip.rect.y -= vel
if keys[pygame.K_DOWN] and StarShip.rect.y < 600:
StarShip.rect.y += vel
win.fill((0,0,0))
all_sprites.update()
all_sprites.draw(win)
pygame.display.update()
pygame.quit()
This has basic movement of left/right/up/down. What I want to do is have my StarShip object constantly change between the variables starship_1, starship_2, starship_3 (which contain my 3 sprites of my starship), so it looks like the starship is moving.
My sprites look like this:
As you can see, it is the engine fire that is the difference between those sprites. How would I change between those 3 sprites every 1 second?
FYI: When the program is launched, this is what appears:
Thank you!
There are 2 parts to achieve this effect.
Create a function to change image of the sprite. ( Easy Task)
Call the above function periodically every x seconds. ( Intermediate Task)
Step 1.
You can achieve this by just setting/loading the self.image variable with the next image.
Step 2.
clock = pygame.time.Clock()
time_counter = 0
images = ['starship_1', 'starship_2', 'starship_3']
current_img_index = 0
while run:
# Your Code
time_counter = clock.tick()
# 1000 is milliseconds == 1 second. Change this as desired
if time_counter > 1000:
# Incrementing index to next image but reseting back to zero when it hits 3
current_img_index = (current_img_index + 1) % 3
set_img_function(current_img_index) # Function you make in step 1
# Reset the timer
time_counter = 0
A good approach will be to complete step 1 and then bind it to a button. Test if it works and then move on to step 2.
Some good read about the functions used in this code to fully understand them is here
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.
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.
This is my code so far, I can move and it places out a blip to pick up, I just need to know how to register that and move the blip to a new random spot!
I am very new to pygame and not 100% fluent in python either, but I'm decent. If there are pdf:s good for intermediate coders when it comes to python that would be wonderful!
import sys, pygame, os, math
from random import randint
pygame.init()
size = width, height = 800, 600
speed = [2, 2]
black = 1, 1, 1
screen = pygame.display.set_mode(size)
pygame.display.set_caption('Pick up the squares!')
UP='up'
DOWN='down'
LEFT='left'
RIGHT='right'
ball = pygame.image.load("ball.png")
ballrect = ball.get_rect()
ballx = 400
bally = 300
blip = pygame.image.load("blip.png")
bliprect = blip.get_rect()
blipx = randint(1,800)
blipy = randint(1,600)
background = pygame.Surface(screen.get_size())
background = background.convert()
background.fill((250, 250, 250))
clock = pygame.time.Clock()
while 1:
for event in pygame.event.get():
if event.type == pygame.QUIT: sys.exit()
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
ballx -= 5
if keys[pygame.K_RIGHT]:
ballx += 5
if keys[pygame.K_UP]:
bally -= 5
if keys[pygame.K_DOWN]:
bally +=5
screen.fill(black)
screen.blit(ball, (ballx,bally))
screen.blit(blip, (blipx, blipy))
pygame.display.update()
clock.tick(40)
Use the colliderect method of rectangles:
if ballrect.colliderect(bliprect):
print 'Do something here'
A basic collision detection works like this (assuming you are working with two rectangles):
def does_collide(rect1, rect2):
if rect1.x < rect2.x + rect2.width and rect1.x + rect1.width > rect2.x \
and rect1.y < rect2.y + rect2.height and rect1.height + rect1.y > rect2.y:
return True
return False
Fortunately Pygame is packed with such methods, so you should go with #MalikBrahimi's answer - using colliderect function call, which will do the math for you.
You can also try using pygame.sprite.spritecollide():
if pygame.sprite.spritecollide(a, b, False):
pass
#Do something
a here is your variable name for the class for one of the sprites in the collision. b here is the group that your second sprite will be. You can set the last one to True, which will remove the sprite from the group. Setting to False will keep it the way it is. Here is an example:
if pygame.sprite.spritecollide(my_ball, ballGroup, False):
Ball.speed[0] = -Ball.speed[0]
hit.play()
Ball.move()
The variable name for my sprite is my_ball. The group containing the other sprite(s) in this collision is ballGroup. I set the last one to False to keep all the sprites on the surface. If I set to True, the sprite from ballGroup will be removed from the group and screen. I hope this helps you!