This question already has an answer here:
How to make a character jump in Pygame?
(1 answer)
Closed last year.
hello i am currently trying to make a jumping game in pygame a lot like the chrome dino game. i have made some simple code to draw a square and make it jump. i will my code dow n bellow. my problem is with the jumping part. whenever i press w wichis the the jump button the square jumps multiple times(usauly 2 times). good people of stack overflow please help a man in need.
here is my code
import pygame
pygame.init()
screen_width = 500
screen_height = 400
isJump = False
y = 350
x = 50
BLUE=(0,0,255)
run = True
screen = pygame.display.set_mode((screen_width, screen_height))
screen.fill((0,0,0))
pygame.display.set_caption("syoma n9ot intelent")
pygame.draw.rect(screen,BLUE,(x,y,50,50))
while run:
pygame.display.flip()
for event in pygame.event.get():
keys = pygame.key.get_pressed()
if keys[pygame.K_w]:
for a in range (1,250):
y -= .5
screen.fill((0,0,0))
pygame.draw.rect(screen,BLUE,(x,y,50,50))
pygame.display.flip()
for a in range (1,250):
y += .5
screen.fill((0,0,0))
pygame.draw.rect(screen,BLUE,(x,y,50,50))
pygame.display.flip()
if event.type == pygame.QUIT:
run = False
pygame.quit()
Use the KEYDOWN event instead of pygame.key.get_pressed().
pygame.key.get_pressed() returns a sequence with the state of each key. If a key is held down, the state for the key is True, otherwise False. Use pygame.key.get_pressed() to evaluate the current state of a button and get continuous movement.
The keyboard events (see pygame.event module) occur only once when the state of a key changes. The KEYDOWN event occurs once every time a key is pressed. KEYUP occurs once every time a key is released. Use the keyboard events for a single action or a step-by-step movement.
Use pygame.time.Clock to control the frames per second and thus the game speed.
The method tick() of a pygame.time.Clock object, delays the game in that way, that every iteration of the loop consumes the same period of time. See pygame.time.Clock.tick():
This method should be called once per frame.
That means that the loop:
clock = pygame.time.Clock()
run = True
while run:
clock.tick(100)
runs 100 times per second.
Do not control the game with an extra loop in the application or event loop. Use the application loop. Use the variables isJump and jumpCount to control the jump. Set the variable isJump = True and jumpCount = 20 when w is started pressed. Decrement jumpCount in the application loop and change the y position of the player. Set isJump = False if jumpCount == -20:
Complete example:
import pygame
pygame.init()
screen_width = 500
screen_height = 400
isJump = False
jumpCount = 0
y = 350
x = 50
BLUE=(0,0,255)
run = True
screen = pygame.display.set_mode((screen_width, screen_height))
clock = pygame.time.Clock()
pygame.display.set_caption("syoma n9ot intelent")
pygame.draw.rect(screen,BLUE,(x,y,50,50))
while run:
clock.tick(100)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_w:
isJump = True
jumpCount = 20
if isJump:
if jumpCount > 0:
y -= 5
elif jumpCount <= 0:
y += 5
jumpCount -= 1
if jumpCount == -20:
isJump = False
screen.fill((0,0,0))
pygame.draw.rect(screen,BLUE,(x,y,50,50))
pygame.display.flip()
Related
I cant seem to understand the clock function in pygame as much i search and code it if it is possible can you help me with this code that is trying to simply make the square move with the up down left and right arrows and if possible and if you have time simply help me understand the clock system.
import pygame
import sys
pygame.init()
fps = 30
fpsclock=pygame.time.Clock()
window = pygame.display.set_mode((600, 600))
# main application loop
run = True
while run:
# limit frames per second
# event loop
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
# clear the display
window.fill(0)
# draw the scene
color = (255,0,0)
x = 275
y = 275
key_input = pygame.key.get_pressed() #key imputs
pygame.draw.rect(window, color, pygame.Rect(x,y,60,60))
pygame.display.flip()
if key_input[pygame.K_LEFT]:
x - 1
if key_input[pygame.K_RIGHT]:
x + 1
if key_input[pygame.K_DOWN]:
y + 1
if key_input[pygame.K_UP]:
y - 1
pygame.display.update()
fpsclock.tick(fps)
# update the display
pygame.display.flip()
pygame.quit()
exit()
x -= 1 instead of x - 1 and x += 1 instead of x + 1. Do the same for y. x and y needs to be initialized before the application instead of in the loop. So you have to do x = 275 and y = 275 before the application loop:
import pygame
import sys
pygame.init()
fps = 30
fpsclock=pygame.time.Clock()
window = pygame.display.set_mode((600, 600))
x = 275
y = 275
color = (255,0,0)
# main application loop
run = True
while run:
# limit frames per second
fpsclock.tick(fps)
# event loop
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
key_input = pygame.key.get_pressed() #key imputs
if key_input[pygame.K_LEFT]:
x -= 1
if key_input[pygame.K_RIGHT]:
x += 1
if key_input[pygame.K_DOWN]:
y += 1
if key_input[pygame.K_UP]:
y -= 1
# clear the display
window.fill(0)
# draw the scene
pygame.draw.rect(window, color, pygame.Rect(x,y,60,60))
# update the display
pygame.display.flip()
pygame.quit()
exit()
if you have time simply help me understand the clock system.
Use pygame.time.Clock to control the frames per second and thus the game speed. The method tick() of a pygame.time.Clock object, delays the game in that way, that every iteration of the loop consumes the same period of time. See pygame.time.Clock.tick():
This method should be called once per frame.
That means that the loop:
fps = 30
fpsclock=pygame.time.Clock()
while run:
fpsclock.tick(fps)
runs 30 times per second.
There are some problems about it:
Change x - 1 to x -= 1
And put x = 275 and y = 275 after defining window
Finally:
import pygame
import sys
pygame.init()
fps = 30
fpsclock=pygame.time.Clock()
window = pygame.display.set_mode((600, 600))
x = 275
y = 275
# main application loop
run = True
while run:
# limit frames per second
# event loop
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
# clear the display
window.fill(0)
# draw the scene
color = (255,0,0)
key_input = pygame.key.get_pressed() #key imputs
pygame.draw.rect(window, color, pygame.Rect(x,y,60,60))
pygame.display.flip()
if key_input[pygame.K_LEFT]:
x -= 1
if key_input[pygame.K_RIGHT]:
x += 1
if key_input[pygame.K_DOWN]:
y += 1
if key_input[pygame.K_UP]:
y -= 1
pygame.display.update()
fpsclock.tick(fps)
# update the display
pygame.display.flip()
pygame.quit()
exit()
I am currently making a fighting game and was wondering how command inputs could be added. I understand it is kind of irrelevant and many substitutes are possible, but it would be nice to use familiar fighting game inputs.
I currently have something like this:
keys = pygame.key.get_pressed()
if keys[pygame.K_DOWN]:
commandcount +=1
if commandcount > 0 and commandcount < 30 and keys[pygame.K_RIGHT] and keys[pygame.K_z]:
player1.projectile = True
The "commandcount" helps keep the window of action available until a certain amount of time.
The main problem with this is that you could still press the inputs in whatever order and the projectile would still come out.
Thanks
Try using the pygame.KEYDOWN events instead of pygame.key.get_pressed() so the order can be observed. Use a list to keep track of the order of these KEYDOWN events. When the order matches a specific combo then execute the move and reset the list. The list also gets reset after a certain amount of time with a combo. I made an example program with the combo down, right, z activating a fireball.
import pygame
# pygame setup
pygame.init()
# Open a window on the screen
width, height = 600, 600
screen = pygame.display.set_mode((width, height))
def main():
clock = pygame.time.Clock()
black = (0, 0, 0)
move_combo = []
frames_without_combo = 0
while True:
clock.tick(30) # number of loops per second
frames_without_combo += 1
if frames_without_combo > 30 or len(move_combo) > 2:
print("COMBO RESET")
frames_without_combo = 0
move_combo = []
screen.fill(black)
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
if event.type == pygame.KEYDOWN:
move_combo.append(event.key) # Only keys for combos should be added
if move_combo == [pygame.K_DOWN, pygame.K_RIGHT, pygame.K_z]:
print("FIRE BALL")
frames_without_combo = 0
print(move_combo)
pygame.display.update()
main()
I am trying to make a python window for my game from my laptop in pygame... however when I try to close the window I get an error message saying "not responding" im not sure why that if I thought i had done everything right.... the code is below any help is needed.
Thanks!
import pygame
from sys import exit
pygame.init()
screen = pygame.display.set_mode((800,400))
clock = pygame.time.Clock()
sky_surface = pygame.image.load("bg_desert.png").convert()
snail_surface = pygame.image.load("snailWalk1.png").convert_alpha()
player_surf = pygame.image.load("p1_walk01.png")
snail_x_pos = 600
while True:
pygame.time.set_timer(snail_x_pos, 100)
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
print("hello")
snail_x_pos -=4
if snail_x_pos < -100: snail_x_pos = 800
screen.blit(sky_surface,(0,0))
screen.blit(snail_surface,(snail_x_pos,350))
screen.blit(player_surf,(80, 200))
pygame.display.update()
clock.tick(60)
All problem makes
pygame.time.set_timer(snail_x_pos, 100)
which you run inside loop.
If I remove it then it closes without problem.
Every set_timer creates new timer which sends event every 100ms (again and again). If you run it in loop then you create hundreds timers.
You should run it only once - before loop - and it will repeatly send event which you can get in for-loop.
Problem is also that you use it in wrong way - you use snail position but it should user_id and time in milliseconds.
my_event_id = pygame.USEREVENT + 1
pygame.time.set_timer(my_event_id, 500) # 500ms = 0.5s
and later you can use it to move snail
elif event.type == my_event_id:
print('0.5 second')
snail_x_pos -= 4
Here my version with other changes.
I use Surfaces instead images so everyone can simply copy and run it.
I also use pygame.Rect to keep position and size - it has useful values (ie. .center to get/set center position) and functions (ie. to detect colisions). I use .left and .right to move snake to right side of window when it leaves window on left side.
import pygame
pygame.init()
screen = pygame.display.set_mode((800,400))
sky_surface = pygame.Surface((800, 100))
sky_surface.fill((0,0,255))
sky_surface_rect = sky_surface.get_rect()
snail_surface = pygame.Surface((100, 10))
snail_surface.fill((0,255,0))
snail_surface_rect = snail_surface.get_rect()
snail_surface_rect.x = 600
snail_surface_rect.y = 350
player_surf = pygame.Surface((10, 50))
player_surf.fill((255,0,0))
player_surf_rect = player_surf.get_rect()
player_surf_rect.x = 80
player_surf_rect.y = 200
clock = pygame.time.Clock()
my_event_id = pygame.USEREVENT + 1
pygame.time.set_timer(my_event_id, 500) # 500ms = 0.1s
while True:
# - events -
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
exit()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
print("hello")
elif event.type == my_event_id:
print('0.5 second')
# move snake
snail_surface_rect.x -= 4
# use this event to slow down player
pressed = pygame.key.get_pressed()
if pressed[pygame.K_LEFT]:
player_surf_rect.x -= 4
elif pressed[pygame.K_RIGHT]:
player_surf_rect.x += 4
# - updates -
if snail_surface_rect.right < 0:
snail_surface_rect.left = 800
# - draw -
screen.fill((0,0,0)) # clear screen
screen.blit(sky_surface, sky_surface_rect)
screen.blit(snail_surface, snail_surface_rect)
screen.blit(player_surf, player_surf_rect)
pygame.display.update()
clock.tick(60)
I'm making a game where a moving cube at the top of the screen will fire a cube down the screen at certain intervals. How would I do this. For example, I want it so that every 1 second the moving cube will fire a projectile down the screen towards the player icon and when it reaches past the screen, it will respawn where the moving cube is and be able to fire again.
This is what I have so far.
import pygame
pygame.init()
screen = pygame.display.set_mode((280, 800))
pygame.display.set_caption("Cube Run")
icon = pygame.image.load("cube.png")
pygame.display.set_icon(icon)
player_icon = pygame.image.load("cursor.png")
player_x = 128
player_y = 750
player_x_change = 0
cube_1 = pygame.image.load("rectangle.png")
cube1_x = 128
cube1_y = 0
cube1_x_change = 0.8
cube_fire = pygame.image.load("rectangle.png")
cube_fire_x = 0
cube_fire_y = 0
cube_y_change = 1.5
cube_fire_state = "ready"
def player(player_x, player_y):
screen.blit(player_icon, (player_x, player_y))
def cube(cube1_x, cube1_y):
screen.blit(cube_1, (cube1_x, cube1_y))
def cube_enemy(cube_fire_x, cube_fire_y):
screen.blit(cube_fire, (cube_fire_x, cube_fire_y))
running = True
while running:
screen.fill((255, 255, 255))
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_RIGHT:
player_x_change += 0.7
if event.key == pygame.K_LEFT:
player_x_change -= 0.7
if event.type == pygame.KEYUP:
if event.key == pygame.K_RIGHT or pygame.K_LEFT:
player_x_change = 0
player_x += player_x_change
if player_x < 0:
player_x = 0
elif player_x > 280-32:
player_x = 280-32
cube1_x += cube1_x_change
if cube1_x > 248:
cube1_x_change = -1
cube1_x += cube1_x_change
elif cube1_x < 0:
cube1_x_change = 1
cube1_x += cube1_x_change
cube_fire_x += cube1_x
cube_enemy(cube_fire_x, cube_fire_y)
player(player_x, player_y)
cube(cube1_x, cube1_y)
pygame.display.update()
You can register events with pygame.time.set_timer. Create a new event and set how many milliseconds should pass before it's fired. This event will then appear at the set intervall.
FIRE_EVENT = pygame.USEREVENT + 1 # This is just a integer.
OTHER_EVENT = pygame.USEREVENT + 2 # This is how you define more events.
pygame.time.set_timer(FIRE_EVENT, 1000) # 1000 milliseconds is 1 seconds.
Then in your event loop, you check for this event and do whatever you want.
for event in pygame.event.get():
if event.type == pygame.QUIT:
quit()
elif event.type == FIRE_EVENT: # Will appear once every second.
make_square_fire()
When you want to disable the event, just set the interval to 0.
pygame.time.set_timer(FIRE_EVENT, 0)
In your code, you don't include a time manager of any kind – which means your code will run as fast as possible, an you can't really control how fast that will be, it will really depend on the machine it is working and on the CPU load, among other things.
Basically, you want to purposely wait within your program just the right amount of time so you can dynamically adapt to the execution speed. You could implement this by yourself (it isn't that hard, and there are plenty of tutorials out there), but to take a first glance of it, you could use pygame.Clock:
first, create a clock with clock = pygame.Clock().
Then, within your main loop, call eta = clock.tick(FPS), where FPS represents the target frame rate you want your application to run (you can simply fix it to 60 at the start of your program if don't really know what value you want it to be), and the eta variable measures the time elapsed (in milliseconds) since last tick call.
Next, to have something happen, say, every second, just keep a counter:
counter = 1000 # in ms
clock = pygame.Clock()
while True:
# do what you want
eta = clock.tick(FPS)
counter -= eta
if counter < 0:
# trigger the event
counter += 1000
# don't set it directly like
# counter = 1000
# to keep track of margin
Currently, I am stuck on trying to get my tank to move when the user presses "a" and "d". The lines involving pressing a key to move the tank seem correct and I believe should work. This is also my first time using one of these forums. Please provide feedback so I can improve. Thank you for your help.
I have asked my teacher and friends for help, but they are all wondering why the tank will not move. I also have searched over the internet and youtube for answers. A weird thing is that my friend and I directly copied a youtube video on user movement where the user can move a rectangle around. My friend can hold down "w","a","s",or "d" to move the rectangle, but I can not hold down "w","a","s",or "d" to move it but need to spam the button. What is weird is that when you move your mouse around, I can then hold down "w","a","s",or "d".
import pygame
from pygame.locals import *
import math
import random
width = 640
height = 480
screen = pygame.display.set_mode((width, height))
pygame.display.set_caption("2 Player Tanks")
def gameloop():
pygame.init()
time = pygame.time.get_ticks()
screen.fill(white)
tankx = 100
tanky = 100
tankwidth = 40
tankheight = 20
turretwidth = 5
wheelwidth = 5
tankmove = 5
def tank(x,y):
x = int(x)
y = int(y)
pygame.draw.circle(screen,black,(x,y),10)
pygame.draw.rect(screen,black,(x-tankheight,y,tankwidth,tankheight))
pygame.draw.line(screen,black,(x,y),(x-20,y-20), turretwidth)
startx = 15
for i in range(7):
pygame.draw.circle(screen,black,(x-startx,y+20),wheelwidth)
startx -= 5
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
keys= pygame.key.get_pressed()
if keys[pygame.K_a]:
tankx -= tankmove
if keys[pygame.K_d]:
tankx += tankmove
if keys[pygame.K_w]:
tanky -= tankmove
if keys[pygame.K_s]:
tanky += tankmove
tank(tankx,tanky)
pygame.display.update()
gameloop()
I want the player to be able to use "a" and "d" to move the tank horizontally.
The event loop is executed only when an event occurs. This means it is executed when a key is pressed or a key is released — however, when a key is held down, no event occurs and the event loop is not executed.
You've got to evaluate the key presses in the main loop (in scope of gameloop) rather than in the event loop:
e.g.
def gameloop():
# [...]
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
# <--
keys= pygame.key.get_pressed()
if keys[pygame.K_a]:
tankx -= tankmove
if keys[pygame.K_d]:
tankx += tankmove
if keys[pygame.K_w]:
tanky -= tankmove
if keys[pygame.K_s]:
tanky += tankmove
tank(tankx,tanky)
pygame.display.update()
Note: pygame.key.get_pressed() returns the current states of the keys and the states are evaluated and updated when pygame.event.get() is called.
The position of the tank is reset at the begin of the frame, because the variables tankx and tanky are set at the begin of gameloop:
def gameloop():
#[...]
tankx = 100
tanky = 100
Define the variables in global scope, and use the global statement to access them.
Decrease the speed of the tank, because it would move very rapidly (tankmove = 1).
The pygame.init() should be called once only, at the begin of application.
e.g.
def gameloop():
global tankx, tanky, tankmove
tankwidth = 40
tankheight = 20
turretwidth = 5
wheelwidth = 5
time = pygame.time.get_ticks()
screen.fill(white)
# [...]
pygame.init()
tankx = 100
tanky = 100
tankmove = 1
run = True
while run:
gameloop()
I can move the tank with a randomized background, but the program keeps on drawing a new tank. To fix this, I added a screen.fill(white). That fixes the drawing problem, but now I have no background.
Don't draw the random background to the window. Create a pygame.Surface and draw the random background to the surface.
.blit the background surface to the screen in every frame:
background_surface = pygame.Surface((widht, height))
# draw background to "background_surface" rather then "screen"
# [...]
def gameloop():
# [...]
# blit background instead of screen.fill(white)
screen.blit(background_surface, (0, 0))
# [...]