The issue is when i press the left or right key while i press it, the sprite crosses the left and right boundaries of the screen. But when i tap it, it will not cross only when i hold the key continuosly
this is the class for the humanship
class Human:
y = display_height * 0.8
x = display_width * 0.45
width = 120
image = pygame.image.load('yasin/alien1.png')
def run(self):
gameDisplay.blit(Human.image, (Human.x, Human.y))
This is the main loop which iterates throughout the game
for event in pygame.event.get():
if event.type == pygame.QUIT:
gameExit = True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
if human.x > 0:
x_change = -8
else:
x_change = 0
elif event.key == pygame.K_RIGHT:
if human.x < display_width - human.width:
x_change = 8
else:
x_change = 0
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT:
x_change = 0
human.x += x_change
human.run()
Move the if human.x > 0: and if human.x < display_width - human.width: out of the event loop because they'll only be executed once per event in the event queue. Rather check in the main while loop if the player is still inside of the game area, otherwise stop it.
I've also changed a few more things: The attributes should be defined in the __init__ method to make them instance attributes instead of class attributes. Use self.x instead of Human.x in the class. The x_change and y_change variables belong to the human object, so they should be attributes as well. Then you can add an update method to the Human in which you do the bounds checking and the movement.
import pygame
display_width, display_height = 640, 480
class Human:
def __init__(self):
self.image = pygame.image.load('yasin/alien1.png')
self.y = display_height * 0.8
self.x = display_width * 0.45
self.x_change = 0
self.y_change = 0
self.width = 120
def run(self, gameDisplay):
gameDisplay.blit(self.image, (self.x, self.y))
def update(self):
self.x += self.x_change
# Check if the human is outside of the game area.
if self.x < 0:
self.x_change = 0 # Stop it.
self.x = 0 # Reset the position, so that we can move again.
elif self.x > display_width - self.width:
self.x_change = 0
self.x = display_width - self.width
def main():
pygame.init()
gameDisplay = pygame.display.set_mode((640, 480))
clock = pygame.time.Clock()
human = Human()
gameExit = False
while not gameExit:
for event in pygame.event.get():
if event.type == pygame.QUIT:
gameExit = True
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
human.x_change = -8
elif event.key == pygame.K_RIGHT:
human.x_change = 8
elif event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT:
human.x_change = 0
human.update()
gameDisplay.fill((30, 30, 30))
human.run(gameDisplay)
pygame.display.flip()
clock.tick(30)
if __name__ == '__main__':
main()
pygame.quit()
Related
My pygame is running way too slow. Without using class oop it was running perfectly but now using oop its very slow.
I have tested putting that separate class file in main file also but the result was same.
import pygame
from snake import Snake
pygame.init()
surf_width = 800
surf_height = 600
clock = pygame.time.Clock()
dis_surf = pygame.display.set_mode((surf_width, surf_height))
pygame.display.set_caption("snake game")
run = True
def game_loop():
x = 255
y = 255
x_change = 0
y_change = 0
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
dis_surf.fill((255, 255, 255))
game = Snake(dis_surf, x, y, x_change, y_change)
x = game.x
y = game.y
another file:
import pygame
class Snake():
def __init__(self, dis_surf, x, y, x_change, y_change):
self.dis_surf = dis_surf
self.x = x
self.y = y
self.width = 20
self.height = 20
self.x_change = x_change
self.y_change = y_change
self.vel = 5
self.draw()
def draw(self):
pygame.draw.rect(self.dis_surf, (0, 255, 0), (self.x, self.y, self.width, self.height))
self.run()
pygame.display.update()
def run(self):
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_RIGHT:
self.x_change = self.vel
self.y_change = 0
elif event.key == pygame.K_LEFT:
self.x_change = -self.vel
self.y_change = 0
elif event.key == pygame.K_UP:
self.y_change = -self.vel
self.x_change = 0
elif event.key == pygame.K_DOWN:
self.y_change = self.vel
self.x_change = 0
print(event)
self.x += self.x_change
self.y += self.y_change
x_change = game.x_change
y_change = game.y_change
pygame.display.update()
clock.tick(60)
game_loop()
A few things are wrong.
1) You are instantiating a new Snake class every game loop when you do game = Snake() inside of the while loop. This in combination with number 2 is your main problem. I moved this line outside of the while loop for you.
2) You are calling run() inside of __init__. This is something you should never do in a constructor, constructors generally should only be used for setting initial data. This also contributed to problem number 1 significantly because this was happening every game loop. I removed the call self.run() inside __init__ for you.
3) pygame.display.update() was being called twice. Not the cause of your problem, but still unnecessary.
Made some small corrections for you.
import pygame
pygame.init()
surf_width = 800
surf_height = 600
clock = pygame.time.Clock()
dis_surf = pygame.display.set_mode((surf_width, surf_height))
pygame.display.set_caption("snake game")
run = True
def game_loop():
x = 255
y = 255
x_change = 0
y_change = 0
game = Snake(dis_surf, x, y, x_change, y_change)
while run:
dis_surf.fill((255, 255, 255))
game.draw()
class Snake():
def __init__(self, dis_surf, x, y, x_change, y_change):
self.dis_surf = dis_surf
self.x = x
self.y = y
self.width = 20
self.height = 20
self.x_change = x_change
self.y_change = y_change
self.vel = 5
def draw(self):
pygame.draw.rect(self.dis_surf, (0, 255, 0), (self.x, self.y, self.width, self.height))
self.run()
def run(self):
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_RIGHT:
self.x_change = self.vel
self.y_change = 0
elif event.key == pygame.K_LEFT:
self.x_change = -self.vel
self.y_change = 0
elif event.key == pygame.K_UP:
self.y_change = -self.vel
self.x_change = 0
elif event.key == pygame.K_DOWN:
self.y_change = self.vel
self.x_change = 0
self.x += self.x_change
self.y += self.y_change
pygame.display.update()
clock.tick(60)
game_loop()
If you want to use OOP in pygame, use pygame's Sprite class. It's made exactly for this purpose.
Your code should look like this (I tried to change not too much):
import pygame
pygame.init()
surf_width = 800
surf_height = 600
clock = pygame.time.Clock()
screen = pygame.display.set_mode((surf_width, surf_height))
pygame.display.set_caption("snake game")
class Snake(pygame.sprite.Sprite):
def __init__(self, pos):
super().__init__()
self.image = pygame.Surface((20, 20))
self.image.fill(pygame.Color('orange'))
self.rect = self.image.get_rect(topleft=pos)
self.x_change = 0
self.y_change = 0
self.vel = 5
def update(self, events):
for event in events:
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_RIGHT:
self.x_change = self.vel
self.y_change = 0
elif event.key == pygame.K_LEFT:
self.x_change = -self.vel
self.y_change = 0
elif event.key == pygame.K_UP:
self.y_change = -self.vel
self.x_change = 0
elif event.key == pygame.K_DOWN:
self.y_change = self.vel
self.x_change = 0
self.rect.move_ip(self.x_change, self.y_change)
def main():
snake = Snake((0, 0))
snakes = pygame.sprite.Group(snake)
while True:
events = pygame.event.get()
for event in events:
if event.type == pygame.QUIT:
return
snakes.update(events)
screen.fill((30, 30, 30))
snakes.draw(screen)
pygame.display.flip()
clock.tick(60)
if __name__ == '__main__':
main()
Ensure to only call pygame.display.flip() and pygame.event.get() once every frame.
If you want to handle events in other parts of your code, just store the current frame's events in a variable and pass them around. Using a Group makes this easy.
See how we cleanly seperated the logic of the game:
The main loop does only the three things it's supposed to do. Handling events, updating the game state, and drawing to the screen. It does so without "knowing what actually happens" in the game.
The Snake sprite only reacts when told so by the main loop (when its update method is called), and it does not care where the events come from and how and where it is actually displayed.
I'm just messing around with Pygame and I can't see what I'm doing incorrectly to make the red circle move with the arrow keys. I can't tell if it's in my main loop. I also haven't been able to find very many tutorials on sprite or looping animations with Pygame. If I for example wanted to make a square oscillate for example like a moving platform how would I do that?
import pygame
import time
## event handling varibles
player_x = 0
player_y = 0
x = 250
y = 250
## screen display
display_width = 500
display_height = 500
pygame.init()
game_screen = pygame.display.set_mode((display_width,display_height))
pygame.display.set_caption("test")
# player
def player():
pygame.draw.circle(game_screen,red,(x,y),15)
# colors
white = (255,255,255)
red = (255,0,0)
black = (0,0,0)
### main loop
dead = False
while dead != True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
dead = True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
player_x = -1
elif event.key == pygame.K_RIGHT:
player_x = +1
if event.key == pygame.K_UP:
player_y = +1
elif event.key == pygame.K_DOWN:
player_y = -1
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT or pygame.K_RIGHT:
player_x = 0
if event.key == pygame.K_UP or pygame.K_DOWN:
player_y = 0
game_screen.fill(black)
player()
pygame.display.update()
x -= player_x
y -= player_y
pygame.quit()
quit()
Your indendation is all messed up.
Your code won't do anything unless the event is QUIT... which then makes it quit.
Your boolean logic is wrong.
This is not proper syntax event.key == pygame.K_UP or pygame.K_DOWN. The order of precedence here is as follows (event.key == pygame.K_UP) or (K_DOWN). Since K_DOWN is truthy, it is always true and thus this entire statement is always true.
I think you mean: event.key == pygame.K_UP or event.key == pygame.K_DOWN
Lastly, it wont' keep moving as you say you want.
It will only move when there is an event in the queue. You can make it keep moving by generating events. Perhaps with an event timer.
Here is a fixed version, hope this helps:
import pygame
import time
## event handling varibles
player_x = 0
player_y = 0
x = 250
y = 250
## screen display
display_width = 500
display_height = 500
pygame.init()
game_screen = pygame.display.set_mode((display_width,display_height))
pygame.display.set_caption("test")
# player
def player(game_screen, red, point): # Use parameters not globals
pygame.draw.circle(game_screen, red, point, 15)
# colors
white = (255,255,255)
red = (255,0,0)
black = (0,0,0)
### main loop
pygame.time.set_timer(pygame.USEREVENT, 1) # 1 per second
dead = False
while not dead:
for event in pygame.event.get():
if event.type == pygame.QUIT:
dead = True
elif event.type == pygame.USEREVENT:
pygame.time.set_timer(pygame.USEREVENT, 1) # Set another timer for another 1 second
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
player_x = +10
elif event.key == pygame.K_RIGHT:
player_x = -10
elif event.key == pygame.K_UP:
player_y = +10
elif event.key == pygame.K_DOWN:
player_y = -10
elif event.type == pygame.KEYUP:
if event.key in [pygame.K_LEFT, pygame.K_RIGHT]:
player_x = 0
elif event.key in [pygame.K_UP, pygame.K_DOWN]:
player_y = 0
game_screen.fill(black)
player(game_screen,red,(x,y))
pygame.display.update()
x -= player_x
y -= player_y
pygame.quit()
I'm a new programmer and am trying to figure out why my bullets aren't showing up. It seems that the Y coordinate changes, but for some reason the bullets are not showing up. This is my code in Python:
#Importing necessary modules
import random
import pygame
import sys
#Setting up pygame
pygame.init()
shooting = False
n = 0
keys = [False,False,False,False]
clock = pygame.time.Clock()
screen = pygame.display.set_mode([500,500])
font = pygame.font.Font(None,50)
#Creating class for player
class Player:
def __init__(self,x,y,width,height):
self.x = x
self.y = y
self.width = width
self.height = height
def draw(self):
pygame.draw.rect(screen,[0,255,0],
[int(self.x),int(self.y),int(self.width),int(self.height)],0)
def move(self):
if keys[1] == True:
self.x -= 1
elif keys[3] == True:
self.x += 1
if self.x < 0:
print(self.x)
self.x = 0
if self.x > 500 - self.width:
print(self.x)
self.x = 500 - self.width
def shoot(self):
return
class Bullet:
def __init__(self,x,y):
self.x = x
self.y = y
def update(self,y_amount = 5):
self.y += y_amount
return
def draw(self):
pygame.draw.rect(screen,[0,255,0],[int(self.x),int(self.y),10,30],0)
bullets = []
#Creating a player
player = Player(200,450,40,20)
#Main Loop
while True:
clock.tick(60)
#Background
screen.fill([0,0,0])
#Letting Player move
player.move()
#Drawing Player
player.draw()
#Updating screen
pygame.display.flip()
#Checking for events
for event in pygame.event.get():
#Checking for quit
if event.type == pygame.QUIT:
sys.exit()
if event.type == pygame.KEYDOWN:
#Checking for keys
if event.key == pygame.K_w:
keys[0] = True
elif event.key == pygame.K_a:
keys[1]=True
elif event.key == pygame.K_s:
keys[2]=True
elif event.key == pygame.K_d:
keys[3]=True
elif event.key == pygame.K_SPACE:
shooting = True
if event.type == pygame.KEYUP:
if event.key == pygame.K_w:
keys[0]=False
elif event.key == pygame.K_a:
keys[1]=False
elif event.key == pygame.K_s:
keys[2]=False
elif event.key == pygame.K_d:
keys[3]=False
elif event.key == pygame.K_SPACE:
shooting = False
if shooting == True:
bullets.append(Bullet(player.x, player.y))
for bullet in bullets:
bullet.update()
bullet.draw()
Rule 1: Check your coordinate system.
Pygame has (0,0) at the top left, your player is at (x, 450) - at the bottom. When you create a bullet, you do so at the player coordinate and then update the position to increase Y, i.e. move downwards rather than upwards.
I believe that you need to update your screen at the end of the while-loop, not at the beginning:
while True:
#fill screen
for event in pygame.event.get():
#get user input
pygame.display().flip()
I am moving a sprite on the x-axis. It is properly moving left and right. When I press both LEFT and RIGHT at the same time it stop moving properly.
I am trying to make it when a user presses both keys and then lets go of one, for it to continue moving in the direction still pressed.
Weirdly it works while I holding right and letting go of left. It continues moving right.
When I hold left and tap right it stops moving until I press right again.
I commented out some ideas I had to make this work, but they failed me.
I am sure its a simple fix or a logic failure on my part.
I have worked a couple hours on this.
Thanks for responses ahead of time.
import pygame
import time
import random
import sys
import math
pygame.init()
displayWidth = 1200
displayHeight = 800
white = (255,255,255)
black = (0,0,0)
gameDisplay = pygame.display.set_mode((displayWidth, displayHeight))
pygame.display.set_caption('Game 3')
clock = pygame.time.Clock()
class firstSquare:
def __init__(self,player_x,player_y):
self.x = player_x
self.y = player_y
self.width = 100
self.height = 100
def render(self):
pygame.draw.rect(gameDisplay, white,(self.x, self.y, self.width, self.height))
class secondSquare:
def __init__(self,cpu_x,cpu_y):
self.x = cpu_x
self.y = cpu_y
self.width = 100
self.height = 100
def render(self):
pygame.draw.rect(gameDisplay, white,(self.x, self.y, self.width, self.height))
player = firstSquare(300,300)
cpu = secondSquare(100,100)
def gameLoop():
### variables##
player_x = 100
player_y = 100
x = 100
y = 100
movement_x = 0
movement_y = 0
frame_rate = 0
frame_table = 0
inGame = True
while inGame:
for event in pygame.event.get():
if event.type == pygame.QUIT:
inGame = False
pygame.quit()
sys.exit()
keyPressed= pygame.key.get_pressed()
#### this is moving the player on x-axis##
if keyPressed[pygame.K_LEFT]:
movement_x = -5
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT:
movement_x = 0
if keyPressed[pygame.K_RIGHT]:
movement_x = 5
if event.type == pygame.KEYUP:
if event.key == pygame.K_RIGHT:
movement_x = 0
### two keys at once won't move the player###
if keyPressed[pygame.K_LEFT] and keyPressed[pygame.K_RIGHT]:
movement_x = 0
### pressing one key and letting go the other will continue movement
## if keyPressed[pygame.K_LEFT] and keyPressed[pygame.K_RIGHT]:
## if event.type == pygame.KEYUP:
## if event.key == pygame.K_LEFT:
## movement_x = 5
## print("left dropped")
## if keyPressed[pygame.K_RIGHT] and keyPressed[pygame.K_LEFT]:
## if event.type == pygame.KEYUP:
## if event.key == pygame.K_RIGHT:
## movement_x = -5
## print("Right dropped")
gameDisplay.fill(black)
player.render()
cpu.render()
player.x += movement_x
pygame.display.update()
clock.tick(60)
gameLoop()
pygame.quit()
quit()
I think what you need is this:
if keyPressed[pygame.K_LEFT]:
movement_x = -5
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT and movement_x < 0:
movement_x = 0
if keyPressed[pygame.K_RIGHT]:
movement_x = 5
if event.type == pygame.KEYUP:
if event.key == pygame.K_RIGHT and movement_x > 0:
movement_x = 0
And that would be it... Hope it helps.
Try to use the following code in your movement:
if keyPressed[pygame.K_LEFT]:
movement_x = -5
elif keyPressed[pygame.K_RIGHT]:
movement_x = +5
elif event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT:
movement_x = 0
elif event.type == pygame.KEYUP:
if event.key == pygame.K_RIGHT:
movement_x = 0
I would like to know how to create a border in Pygame to stop the user controlled object from exiting the screen. Right now, I only have it so python prints some text when the user controlled object has come near one of the 4 sides.
Here is my code so far.
import pygame
from pygame.locals import *
pygame.init()
#Display Stuff
screenx = 1000
screeny = 900
screen = pygame.display.set_mode((screenx,screeny))
pygame.display.set_caption('Block Runner')
clock = pygame.time.Clock()
image = pygame.image.load('square.png')
#Color Stuff
red = (255,0,0)
green = (0,255,0)
blue = (0,0,255)
white = (255,255,255)
black = (0,0,0)
#Variables
x_blocky = 50
y_blocky = 750
blocky_y_move = 0
blocky_x_move = 0
#Animations
def Blocky(x_blocky, y_blocky, image):
screen.blit(image,(x_blocky,y_blocky))
#Game Loop
game_over = False
while not game_over:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_UP:
blocky_y_move = -3
if event.type == pygame.KEYUP:
if event.key == pygame.K_UP:
blocky_y_move = 0
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_DOWN:
blocky_y_move = 3
if event.type == pygame.KEYUP:
if event.key == pygame.K_DOWN:
blocky_y_move = 0
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_RIGHT:
blocky_x_move = 3
if event.type == pygame.KEYUP:
if event.key == pygame.K_RIGHT:
blocky_x_move = 0
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
blocky_x_move = -3
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT:
blocky_x_move = 0
if x_blocky > 870 or x_blocky < 0:
print(' X Border')
if y_blocky > 750 or y_blocky < 2:
print(' Y Border')
y_blocky += blocky_y_move
x_blocky += blocky_x_move
screen.fill(white)
Blocky(x_blocky, y_blocky, image)
pygame.display.update()
clock.tick(60)
Don't use integers to store your position. Use a Rect.
So instead of
x_blocky = 50
y_blocky = 750
use
blocky_pos = pygame.rect.Rect(50, 750)
Now you can simply use
blocky_pos.move_ip(blocky_x_move, blocky_y_move)
to move your object.
After moving, you can simply call clamp/clamp_ip to ensure the blocky_pos Rect is always inside the screen.
blocky_pos.clamp_ip(screen.get_rect())
Also, you don't need to define basic colors yourself, you could simply use pygame.color.Color('Red') for example.
I also suggest you use pygame.key.get_pressed() to get all pressed keys to see how to move your object instead of creating 1000 lines of event handling code.
Well, simply don't increase your move variable any further, if you detect that the user object is near or at the border. Or reverse the move direction, depending on your general intent.
if x_blocky > 870 or x_blocky < 0:
print(' X Border')
blocky_x_move = 0
if y_blocky > 750 or y_blocky < 2:
print(' Y Border')
blocky_y_move = 0
Also, you have some redundant code with your keyboard movement. Instead of writing
if event.type == KEYDOWN:
over and over again, group the KEYUP if statements and KEYDOWN if statements.
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_UP:
blocky_y_move = -3
elif event.key == pygame.K_DOWN:
blocky_y_move = +3
etc, and:
if event.type == pygame.KEYUP:
if event.key == pygame.K_UP:
blocky_y_move = 0
elif event.type == pygame.K_DOWN:
blocky_y_move = 0
etc
You can set the boundaries using the min and max functions.
Here is the concept:
We have a pygame object that moves in all four directions; lets say the user holds down the LEFT arrow key, so that the object reaches the top of the screen. The y-coordinate of the top of the screen will always be 0, so we want the object to come to a stop at y-coordinate 0.
This may seem as simple as:
if char.rect.y > 0:
char.rect.y -= char.speed
But this will result in a bug ig char.speed is greater than 1. Like when the object is at y-coordinate 5,
and its speed is 10; the condition still allows for one more step for the object, resulting in the object
coming 5 pixels out of the pygame window. What we want to do is more like:
if char.rect.y > 0:
char.rect.y -= char.speed
if char.rect.y < 0:
char.rect.y = 0
to push the object back into the boundaries. The above block of code can be simplified with the max function:
self.rect.y = max([self.rect.y - self.speed, 0])
For the object moving down:
if char.rect.y < HEIGHT - char.height:
char.rect.y += char.speed
if char.rect.y > HEIGHT - char.height:
char.rect.y = HEIGHT - char.height
or, the more efficient and clean method:
self.rect.y = min([self.rect.y + self.speed, HEIGHT - self.height])
For going left and right, simply replace the ys and height (and HEIGHT) from two lines above with xs and widths (and WIDTH).
All together:
import pygame
pygame.init()
WIDTH = 600
HEIGHT = 600
wn = pygame.display.set_mode((WIDTH, HEIGHT))
class Player:
def __init__(self):
self.speed = 1
self.width = 20
self.height = 20
self.color = (255, 255, 0)
self.rect = pygame.Rect((WIDTH - self.width) / 2, (HEIGHT - self.height) / 2, 20, 20)
def up(self):
self.rect.y = max([self.rect.y - self.speed, 0])
def down(self):
self.rect.y = min([self.rect.y + self.speed, HEIGHT - self.height])
def left(self):
self.rect.x = max([self.rect.x - self.speed, 0])
def right(self):
self.rect.x = min([self.rect.x + self.speed, WIDTH - self.width])
def draw(self):
pygame.draw.rect(wn, self.color, self.rect)
char = Player()
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
keys = pygame.key.get_pressed()
if keys[pygame.K_UP]:
char.up()
if keys[pygame.K_DOWN]:
char.down()
if keys[pygame.K_LEFT]:
char.left()
if keys[pygame.K_RIGHT]:
char.right()
wn.fill((0, 0, 0))
char.draw()
pygame.display.update()
Good luck!