This question already has answers here:
How to do a variable jump height based on how long key is held in Pygame
(1 answer)
How to make a character jump in Pygame?
(1 answer)
Closed last year.
I'm trying to make a jumping method for my player in pygame. It goes up but I can just hold the space bar key down and it will go up for as long as I want and I don't know how to prevent it. Here's the code for my player class:
import pygame
class Player(pygame.sprite.Sprite):
def __init__(self, pos):
super().__init__()
self.image = pygame.Surface((32, 64))
self.image.fill('blue')
self.rect = self.image.get_rect(topleft = pos)
self.direction = pygame.math.Vector2(0, 0)
self.speed = 8
self.jump_speed = -16
self.gravity = 0.8
def get_input(self):
keys = pygame.key.get_pressed()
if keys[pygame.K_RIGHT] or keys[pygame.K_d]:
self.direction.x = 1
elif keys[pygame.K_LEFT] or keys[pygame.K_a]:
self.direction.x = -1
else:
self.direction.x = 0
if keys[pygame.K_SPACE] or keys[pygame.K_w] or keys[pygame.K_UP]:
self.jump()
def apply_gravity(self):
self.direction.y += self.gravity
self.rect.y += self.direction.y
def jump(self):
self.direction.y = self.jump_speed
def update(self):
self.get_input()
The jump event changes the way the player is moving. When a key is released, then that speed is not reverted. Use the pygame keydown event, and then the keyup event.
import pygame
from pygame.locals import *
#Your code
while True:
#Your event loop code
for event in pygame.event.get():
if event.type == KEYDOWN:
if event.key == K_SPACE:
player.jump()
if event.type == KEYUP:
if event.key == K_SPACE:
player.revert_jump()
if event.type == QUIT:
pygame.quit()
exit()
Related
This question already has answers here:
Pygame doesn't let me use float for rect.move, but I need it
(2 answers)
Closed 2 years ago.
I tried adding gravity to my player in pygame, but I can move the player with key controls but gravity is not working, Here I used sprite class for making this. I got the rect of the image then add the x momentum and y momentum. X momentum worked while moving the player but y momentum didn't work while adding the gravity. Please help!
# Platformer
import pygame
# Basic Setup
pygame.init()
clock = pygame.time.Clock()
# Game Colors
white = (255, 255, 255)
light_blue = (105, 142, 255)
# Game Settings
game_title = "Platformer!"
screen_width = 1280
screen_height = 750
fps = 120
player_speed = 4
player_gravity = 0.2
# Main Window
screen = pygame.display.set_mode((screen_width, screen_height))
pygame.display.set_caption(game_title)
class Player(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.image = pygame.image.load("IMGs/player.png")
self.image.set_colorkey(white)
self.rect = self.image.get_rect(center=(screen_width / 2, screen_height / 2))
self.x_momentum = 0
self.y_momentum = 0
self.moving_right = False
self.moving_left = False
def move(self):
# Set the movement to zero at first
self.x_momentum = 0
self.y_momentum = 0
# Move the player on key press
if self.moving_right:
self.x_momentum += player_speed
elif self.moving_left:
self.x_momentum -= player_speed
# Add Gravity
self.y_momentum += player_gravity
# Move the player
self.rect.x += self.x_momentum
self.rect.y += self.y_momentum
def update(self):
self.move()
class Main:
def __init__(self):
# Sprites
self.all_sprites = pygame.sprite.Group()
# Player Sprite
self.player = Player()
self.all_sprites.add(self.player)
def draw(self, surface):
self.all_sprites.draw(surface)
def update(self):
self.all_sprites.update()
main_game = Main()
def main_game_loop():
while True:
# Handling Inputs
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
exit(0)
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_RIGHT or event.key == pygame.K_d:
main_game.player.moving_right = True
elif event.key == pygame.K_LEFT or event.key == pygame.K_a:
main_game.player.moving_left = True
if event.type == pygame.KEYUP:
if event.key == pygame.K_RIGHT or event.key == pygame.K_d:
main_game.player.moving_right = False
elif event.key == pygame.K_LEFT or event.key == pygame.K_a:
main_game.player.moving_left = False
# Draw / Render
screen.fill(light_blue)
main_game.draw(screen)
main_game.update()
pygame.display.update()
# Manage Speed
clock.tick(fps)
main_game_loop()
The gravity doesn't work because self.y_momentum is set 0 at the begin of Player.move:
class Player(pygame.sprite.Sprite):
# [...]
def move(self):
# Set the movement to zero at first
self.x_momentum = 0
self.y_momentum = 0
# [...]
Since pygame.Rect is supposed to represent an area on the screen, a pygame.Rect object can only store integral data.
The coordinates for Rect objects are all integers. [...]
The fraction part of the coordinates gets lost when the position stored in the Rect object is decremented:
# Move the player
self.rect.x += self.x_momentum
self.rect.y += self.y_momentum
If you want to store object positions with floating point accuracy, you have to store the location of the object in separate variables respectively attributes and to synchronize the pygame.Rect object. round the coordinates and assign it to the location (e.g. .topleft) of the rectangle:
class Player(pygame.sprite.Sprite):
def __init__(self):
# [...]
self.x = screen_width // 2
self.y = screen_height // 2
self.rect = self.image.get_rect(center = (self.x, self.y))
# [...]
def move(self):
# [...]
# Move the player
self.x += self.x_momentum
self.y += self.y_momentum
self.rect.topleft = round(self.x), round(self.y)
This question already has answers here:
How can i shoot a bullet with space bar?
(1 answer)
How do I stop more than 1 bullet firing at once?
(1 answer)
Closed 2 years ago.
so I was doing the exercise of python crash course 12-6. which places a ship on the left side of the screen and allows the player to move the ship up and down. Make the ship fire the bullet that travels right across the screen when the player presses the space-bar.
I've tried to print the length of the bullets, the animation runs which means it is recognizing that the button is being pressed and the bullets appear but don't move. The bullet appears but stays frozen. It seems the for loop has something to do with it.
I've tried to compare the Alian Invasion code three times which is explained in the chapter for this exercise, which sound stupid but i don't see anything obviously wrong to me.
I'm new to python and pygame and even to stackoverflow, any help will be highly appreciated.
The below is the main code to run the game.
import pygame
import sys
from sideways_shooter import SidewaysShooter
from stone import Stone
from settings import Settings
class SidewaysShooterGame:
def __init__(self):
pygame.init()
self.settings = Settings()
self.screen = pygame.display.set_mode(
(self.settings.screen_width, self.settings.screen_height))
pygame.display.set_caption("Sideways Shooter Game")
self.sideways_shooter = SidewaysShooter(self)
self.stones = pygame.sprite.Group()
def run_game(self):
while True:
self._check_events()
self.sideways_shooter.update()
self._stones_update()
self._update_screen()
def _stones_update(self):
self.stones.update()
for stone in self.stones.copy():
if stone.rect.left >= self.sideways_shooter.screen_rect.right:
self.stones.remove(stone)
def _check_events(self):
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == pygame.KEYDOWN:
self._check_keydown_events(event)
elif event.type == pygame.KEYUP:
self._check_keyup_events(event)
def _check_keydown_events(self, event):
if event.key == pygame.K_UP:
self.sideways_shooter.moving_up = True
elif event.key == pygame.K_DOWN:
self.sideways_shooter.moving_down = True
elif event.key == pygame.K_q:
sys.exit()
elif event.key == pygame.K_SPACE:
self._throw_stones()
def _check_keyup_events(self,event):
if event.key == pygame.K_UP:
self.sideways_shooter.moving_up = False
elif event.key == pygame.K_DOWN:
self.sideways_shooter.moving_down = False
def _throw_stones(self):
if len(self.stones) < self.settings.stones_allowed:
new_stone = Stone(self)
self.stones.add(new_stone)
def _update_screen(self):
self.screen.fill(self.settings.bg_color)
self.sideways_shooter.blitme()
for stone in self.stones:
stone.draw_stone()
pygame.display.flip()
if __name__ == '__main__':
ss_game = SidewaysShooterGame()
ss_game.run_game()
The below are the classes and methods that contains assets and attributes for the main code project.
sideway_shooter file
import pygame
class SidewaysShooter:
def __init__(self, ss_game):
self.screen = ss_game.screen
self.settings = ss_game.settings
self.screen_rect = ss_game.screen.get_rect()
self.image = pygame.image.load('images/resized_shooter_bmp_file.bmp')
self.rect = self.image.get_rect()
self.rect.midleft = self.screen_rect.midleft
self.y = float(self.rect.y)
self.moving_up = False
self.moving_down = False
def update(self):
if self.moving_up and self.rect.top > 0:
self.y -= self.settings.speed
if self.moving_down and self.rect.bottom < self.screen_rect.bottom:
self.y += self.settings.speed
self.rect.y = self.y
def blitme(self):
self.screen.blit(self.image, self.rect)
stone file
import pygame
from pygame.sprite import Sprite
class Stone(Sprite):
def __init__(self, ss_game):
super().__init__()
self.screen = ss_game.screen
self.settings = ss_game.settings
self.color = self.settings.stone_color
self.rect = pygame.Rect(0, 0, self.settings.stone_width,
self.settings.stone_height)
self.rect.midright = ss_game.sideways_shooter.rect.midright
self.x = float(self.rect.x)
def upate(self):
self.x += self.settings.stone_speed
self.rect.x = self.x
def draw_stone(self):
pygame.draw.rect(self.screen, self.color, self.rect)
settings file
class Settings:
def __init__(self):
self.screen_width = 1400
self.screen_height = 700
self.bg_color = (255, 255, 255)
self.speed = 1.5
self.stone_color = (60, 60, 60)
self.stone_width = 15
self.stone_height = 3
self.stone_speed = 1.0
self.stones_allowed = 3
Just starting out in pygame and trying to get a simple dot to move around the screen when you hold down the arrow keys. Currently, it only moves when you press the key, but you'd have to repeatedly press it.
import random
import pygame
import keyboard
import time
from pygame.locals import *
class Player:
def __init__(self):
self.x = 150
self.y = 150
pygame.init()
screen = pygame.display.set_mode((400, 300))
pygame.display.set_caption("Smile, you're beautiful!")
player = Player()
while True:
pygame.time.Clock().tick(60)
for event in pygame.event.get():
if event.type == QUIT:
exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_RIGHT:
player.x += 5
if event.key == pygame.K_DOWN:
player.y += 5
if event.key == pygame.K_LEFT:
player.x -= 5
if event.key == pygame.K_UP:
player.y -= 5
pygame.event.pump()
pygame.display.flip()
pygame.display.update()
screen.fill((0,0,0))
pygame.draw.circle(screen, (180, 180, 180), (player.x, player.y), 5)
Also, I'd appreciate any tips you might have regarding my current code that may be improved upon or changed to make more efficient.
You need to use pygame.key.get_pressed rather than the key down events. This way you know which keys are currently being pressed on every tick
while True:
pressed = pygame.key.get_pressed()
if pressed[pygame.K_RIGHT]:
player.x += 5
if pressed[pygame.K_DOWN]:
player.y += 5
if pressed[pygame.K_LEFT]:
player.x -= 5
if pressed[pygame.K_UP]:
player.y -= 5
Previously in my projectiles module, I had a class that handled each direction of fire seperately (a class for firing up, down, left and right) and this did it's job. However, now that I'm trying to incorporate shot speed and other things into the class, having 4 seperate classes is just too messy and so I tried to trim it down so that I only have one class for all projectiles fired.
However, now that I have done this, when I fire a projectile, it will only move so long as I am holding the fire button ('a' key if firing left) down. Also, if I fire left, then fire right, the projectile that was previously travelling left will begin to travel right instead.
My question is; How do I handle the projectiles so that when I fire one, it no longer accepts updates and travels in a straight line?
This is my working code;
Main game module
import pygame
from constants import *
from player import Player
from Projectile import Projectiles
pygame.init()
screen = pygame.display.set_mode([500, 500])
pygame.display.set_caption('Labyrinth')
# Spawn player
player = Player(50, 50)
all_sprites_list = pygame.sprite.Group()
all_sprites_list.add(player)
projectile_list = pygame.sprite.Group()
clock = pygame.time.Clock()
done = False
# ----- Event Loop
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
elif event.type == pygame.KEYDOWN:
if event.key == ord('a'):
player.changespeed(-3, 0)
elif event.key == ord('d'):
player.changespeed(3, 0)
elif event.key == ord('w'):
player.changespeed(0, -3)
elif event.key == ord('s'):
player.changespeed(0, 3)
elif event.key == pygame.K_LEFT:
projectile = Projectiles(0, 0)
projectile.rect.x = player.rect.x
projectile.rect.y = player.rect.y
elif event.key == pygame.K_RIGHT:
projectile = Projectiles(0, 0)
projectile.rect.x = player.rect.x
projectile.rect.y = player.rect.y
elif event.key == pygame.K_UP:
projectile = Projectiles(0, 0)
projectile.rect.x = player.rect.x
projectile.rect.y = player.rect.y
elif event.key == pygame.K_DOWN:
projectile = Projectiles(0, 0)
projectile.rect.x = player.rect.x
projectile.rect.y = player.rect.y
try:
if projectile:
projectile_list.add(projectile)
except:
pass
elif event.type == pygame.KEYUP:
if event.key == ord('a'):
player.changespeed(3, 0)
elif event.key == ord('d'):
player.changespeed(-3, 0)
elif event.key == ord('w'):
player.changespeed(0, 3)
elif event.key == ord('s'):
player.changespeed(0, -3)
# ----- Game Logic
all_sprites_list.update()
projectile_list.update()
screen.fill(GREEN)
all_sprites_list.draw(screen)
projectile_list.draw(screen)
pygame.display.flip()
clock.tick(60)
pygame.quit()
Player module
from constants import *
import pygame
import time
from datetime import datetime, timedelta
class Player(pygame.sprite.Sprite):
def __init__(self, x, y):
super().__init__()
self.image = pygame.Surface([15, 15])
self.image.fill(BLACK)
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
self.change_x = 0
self.change_y = 0
def changespeed(self, x, y):
self.change_x += x
self.change_y += y
def update(self):
self.rect.x += self.change_x
self.rect.y += self.change_y
Projectile module
import pygame
from constants import *
class Projectiles(object):
def __init__(self, x, y):
super().__init__()
self.image = pygame.Surface([4, 4])
self.image.fill(RED)
self.rect = self.image.get_rect()
def update(self):
key = pygame.key.get_pressed()
if key[pygame.K_UP]:
self.rect.y -= 5
if key[pygame.K_DOWN]:
self.rect.y += 5
if key[pygame.K_LEFT]:
self.rect.x -= 5
if key[pygame.K_RIGHT]:
self.rect.x += 5
As always any help would be much appreciated!
The first problem is that you only create ONE projectile. Your class is called Projectiles which is misleading because it's only one object not multiple. This causes the projectile to be controlled even after firing.
Also, the reason why the projectile only moves while you press a key is that in the update() method, you only add to the projectiles x or y coordinate when e.g. key[pygame.K_UP]: is true.
So, to fix this issues you will have to change the way your game handles projectiles.
If I understand your question right, you want to have multiple projectiles at once.
The way to implement this is to use a collection of projectiles.
Game
//nothing changed till here
elif event.key == pygame.K_LEFT:
p = Projectile(player.rect.x, player.rect.y, -5, 0)
projectile_list.add(p)
elif event.key == pygame.K_RIGHT:
p = Projectile(player.rect.x, player.rect.y, 5, 0)
projectile_list.add(p)
elif event.key == pygame.K_UP:
p = Projectile(player.rect.x, player.rect.y, 0, -5)
projectile_list.add(p))
elif event.key == pygame.K_DOWN:
p = Projectile(player.rect.x, player.rect.y, 0, 5)
projectile_list.add(p)
// moved the part where you append the projectile to in the if statement
# ----- Game Logic
all_sprites_list.update()
projectile_list.update()
screen.fill(GREEN)
all_sprites_list.draw(screen)
projectile_list.draw(screen)
pygame.display.flip()
clock.tick(60)
pygame.quit()
Projectile:
import pygame
from constants import *
// projectile needs to extend Sprite
class Projectile(pygame.sprite.Sprite):
def __init__(self, x, y, x_speed, y_speed):
super().__init__()
self.image = pygame.Surface([4, 4])
self.image.fill(RED)
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
self.x_speed = x_speed
self.y_speed = y_speed
def update(self):
self.rect.x += self.x_speed
self.rect.y += self.y_speed
Im not so familiar with Pygame but I hope this will help you at least somehow.
I have never used PyGame but one can see that your update() method in the Projectiles class depends on key press while it should depend on elapsed time instead.
Your projectile moves 5 units per key press, not 5 units per game tick once launched.
I am currently working on a pong clone in Python using Pygame. I am no where near an expert at the subject of programming, and have run into an error. Whenever I run the code I currently have, which will be listed below separated by Blockquotes, the program will freeze up, and not respond. I cannot tell what the issue may be with the little knowledge I have. I was hoping that someone would be able to assist me on this issue. I am currently using a tutorial to help instruct me through the making of this game, and the code looks pretty identical at this point. I will include a hyperink to the tutorial here. I appreciate any and all feedback.
3000X_runner.py
import GameObj
if __name__ == '__main__':
game = GameObj.Game()
game.run()
PongPaddle.py
import os, pygame
class Paddle(pygame.sprite.Sprite):
def __init__(self, user, xy):
pygame.sprite.Sprite.__init__(self)
if user == 1:
self.image = pygame.image.load(os.path.join("images", "playerPaddle.png"))
else:
self.image = pygame.image.load(os.path.join("images", "opponentPaddle.png"))
self.rect = self.image.get_rect()
self.rect.centerx, self.rect.centery = xy
self.movement_speed = 5
self.velocity = 0
def up(self):
self.velocity -= self.movement_speed
def down(self):
self.velocity += self.movement_speed
def move(self, dy):
if self.rect.bottom + dy > 720:
self.rect.bottom = 720
elif self.rect.top + dy < 0:
self.rect.bottom = 0
else: self.rect.y += dy
def update(self):
self.move(self.velocity)
GameObj.py
import os, pygame, PongPaddle
class Game(object):
def __init__(self):
pygame.init()
#setup screen width/height
self.screen = pygame.display.set_mode((1080, 720))
self.clock = pygame.time.Clock() #setups internal pygame clock
#Mandatory silly name featuring extra numbers for game name
pygame.display.set_caption("Hyper Pong 3000-X")
#create background.
self.background = pygame.Surface((1080, 720))
self.background.fill((0,0,0)) #black background
#draws a white line down the middle of screen
#line(Surface, color, start_pos, end_pos, width=1) -> Rect
pygame.draw.line(self.background, (255, 255, 255), (540, 0), (540, 720), 5)
self.screen.blit(self.background, (0, 0)) #blits to screen
#I shall render all the sprites here:
self.sprites = pygame.sprite.OrderedUpdates()
#setting up the paddles and adding them to my sprite group
self.player_paddle = PongPaddle.Paddle(1, (50, 200))
self.sprites.add(self.player_paddle)
self.opponent_paddle = PongPaddle.Paddle(2, (1030, 200))
self.sprites.add(self.opponent_paddle)
def run(self):
stillPlaying= True
while stillPlaying:
self.clock.tick(30)
#handles our pygame events, giving us a easy to view, clutter free game loop
stillPlaying = self.handleEvents
#updates all of our sprites
for sprite in self.sprites:
sprite.update()
self.sprites.clear(self.screen, self.background)
dirty = self.sprites.draw(self.screen)
pygame.display.update(dirty)
def handleEvents(self):
#here we handle all of our events, such as when either player will
#press a key to move, quit the game, etc etc.
for event in pygame.event.get():
if event.type == pygame.QUIT:
return False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
return False
#player1 keydown events
if event.key == pygame.K_w:
self.player_paddle.up()
if event.key == pygame.K_s:
self.player_paddle.down()
#player2 keydown events
if event.key == pygame.K_UP:
self.opponent_paddle.up()
if event.key == pygame.K_DOWN:
self.opponent_paddle.down()
elif event.type == pygame.KEYUP:
#player1 keyup events
if event.key == pygame.K_w:
self.player_paddle.down()
if event.key == pygame.K_s:
self.player_paddle.up()
#player2 keyup events
if event.key == pygame.K_UP:
self.opponent_paddle.down()
if event.key == pygame.K_DOWN:
self.opponent_paddle.up()
return True
Simply forgot to add () in GameObj.py after
stillPlaying = self.handleEvents
It should look like: stillPlaying = self.handleEvents()