PyGame is Choppy - python

im new at pygame and im watching some tutorials in how to get started with it, I wrote this basic code that it only has movement and a jump "function" but it is really choppy, I do not think its my hardware (Macbook Pro 2018). Do someone has any idea of whats happening?
HereĀ“s the code:
import pygame
pygame.init()
win_width = 500
win_height = 500
win = pygame.display.set_mode((win_width,win_height))
pygame.display.set_caption("First PyGame")
width = 40
height = 60
x = win_width/2
y = win_height/2
vel = 10
isJump = False
jumpCount = 10
run = True
while run:
pygame.time.delay(100)
for event in pygame.event.get():
if event.type == pygame.QUIT:
print("adios putito")
run = False
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT] and x > vel:
x -= vel
if keys[pygame.K_RIGHT] and x < win_width - width - vel:
x+= vel
if not (isJump):
if keys[pygame.K_UP] and y > vel:
y -= vel
if keys[pygame.K_DOWN]and y < win_height - height - vel:
y += vel
if keys[pygame.K_SPACE]:
isJump = True
else:
if jumpCount >= -10:
neg = 1
if jumpCount < 0:
neg = -1
y -= (jumpCount ** 2) * 0.5 * neg
jumpCount -= 1
else:
isJump = False
jumpCount = 10
win.fill((0,0,0))
pygame.draw.rect(win,(255,255,255), (x,y,width,height))
pygame.display.update()
pygame.quit()

The line
pygame.time.delay(100)
is delaying your script that milliseconds, remove that line and it should work just fine!
Result:
import pygame
pygame.init()
win_width = 500
win_height = 500
win = pygame.display.set_mode((win_width,win_height))
pygame.display.set_caption("First PyGame")
width = 40
height = 60
x = win_width/2
y = win_height/2
vel = 10
isJump = False
jumpCount = 10
run = True
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
print("adios putito")
run = False
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT] and x > vel:
x -= vel
if keys[pygame.K_RIGHT] and x < win_width - width - vel:
x+= vel
if not (isJump):
if keys[pygame.K_UP] and y > vel:
y -= vel
if keys[pygame.K_DOWN]and y < win_height - height - vel:
y += vel
if keys[pygame.K_SPACE]:
isJump = True
else:
if jumpCount >= -10:
neg = 1
if jumpCount < 0:
neg = -1
y -= (jumpCount ** 2) * 0.5 * neg
jumpCount -= 1
else:
isJump = False
jumpCount = 10
win.fill((0,0,0))
pygame.draw.rect(win,(255,255,255), (x,y,width,height))
pygame.display.update()
pygame.quit()

It's still a good idea to have a game clock that delays your program enough to keep a persistent framerate. You can use pygame's pygame.time.Clock object and use its tick() method to delay your game. The tick method takes an integer which represents the FPS you want your game to cap at. If your game runs slower than the FPS value you put in, no delay will happen.
import pygame
pygame.init()
win_width = 500
win_height = 500
win = pygame.display.set_mode((win_width,win_height))
pygame.display.set_caption("First PyGame")
clock = pygame.time.Clock()
width = 40
height = 60
x = win_width/2
y = win_height/2
vel = 10
isJump = False
jumpCount = 10
run = True
while run:
# Delay your game to try and keep 60 FPS.
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
print("adios putito")
run = False
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT] and x > vel:
x -= vel
if keys[pygame.K_RIGHT] and x < win_width - width - vel:
x+= vel
if not (isJump):
if keys[pygame.K_UP] and y > vel:
y -= vel
if keys[pygame.K_DOWN]and y < win_height - height - vel:
y += vel
if keys[pygame.K_SPACE]:
isJump = True
else:
if jumpCount >= -10:
neg = 1
if jumpCount < 0:
neg = -1
y -= (jumpCount ** 2) * 0.5 * neg
jumpCount -= 1
else:
isJump = False
jumpCount = 10
win.fill((0,0,0))
pygame.draw.rect(win,(255,255,255), (x,y,width,height))
pygame.display.update()
pygame.quit()

Related

How do I make a boundary so that the DVD logo does not go out of the screen?

I tried to make a boundary and it didn't work so I deleted it however now it just doesn't want to work. It is a code with an image and uses keys to move it. I am a beginner at coding so I don't know much so I would appreciate some edits or recommendations on what I should do.
This is my code:
#Imports Pygame module
import pygame
#Initializing/ Starting Pygame module
pygame.init()
#Setting the background and starting location of logo
dvdLogoSpeed = [1, 1]
backgroundColor = 0, 0, 0
#Screen size display variable
screen = pygame.display.set_mode(600, 600)
#Variable for logo and made rectangle for logo
dvdLogo = pygame.image.load("dvd-logo-white.png")
dvdLogoRect = dvdLogo.get_rect()
#Variables
x = 200
y = 200
vel = 10
width = 20
height = 20
def dvdwKeys ():
run = True
while run == True:
pygame.time.delay(10)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
screen.fill (backgroundColor)
screen.blit(dvdLogo, dvdLogoRect)
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT] and x>0:
dvdLogoRect.x -= vel
if keys[pygame.K_RIGHT] and x<600-width:
dvdLogoRect.x += vel
if keys[pygame.K_UP] and y>0:
dvdLogoRect.y -= vel
if keys[pygame.K_DOWN] and y<600-height:
dvdLogoRect.y += vel
pygame.display.flip()
dvdwKeys()
You need to test dvdLogoRect.x and dvdLogoRect.y instead of x and y:
while run == True:
# [...]
if keys[pygame.K_LEFT] and dvdLogoRect.x>0:
dvdLogoRect.x -= vel
if keys[pygame.K_RIGHT] and dvdLogoRect.right<600:
dvdLogoRect.x += vel
if keys[pygame.K_UP] and dvdLogoRect.y>0:
dvdLogoRect.y -= vel
if keys[pygame.K_DOWN] and dvdLogoRect.bottom<600:
dvdLogoRect.y += vel
However, you can simplify the code with pygame.Rect.clamp_ip:
def dvdwKeys ():
clock = pygame.time.Clock()
run = True
while run == True:
clock.tick(100)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
keys = pygame.key.get_pressed()
dvdLogoRect.x += (keys[pygame.K_RIGHT] - keys[pygame.K_LEFT]) * vel
dvdLogoRect.y += (keys[pygame.K_DOWN] - keys[pygame.K_UP]) * vel
dvdLogoRect.clamp_ip(screen.get_rect())
screen.fill(backgroundColor)
screen.blit(dvdLogo, dvdLogoRect)
pygame.display.flip()
See also Setting up an invisible boundary for my sprite and How can I make a sprite move when key is held down and

Pygame character jump speed problems

I'm currently trying to make my first game. I am trying to make my character jump, but my code doesn't have errors but when my character jump it just happens to fast. I don't know which part to change. I have not been able to figure this out on my own as I am still learning. Here is my code:
import pygame
pygame.init()
screen = pygame.display.set_mode((1200, 600))
WinHeight = 600
WinWidth = 1200
# player
player = pygame.image.load("alien.png")
x = 50
y = 450
vel = 0.3
playerSize = 32
# title
pygame.display.set_caption("First Game")
# Jump
isJump = False
jumpCount = 10
running = True
while running:
screen.fill((255, 255, 255))
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
break
keys = pygame.key.get_pressed()
if keys[pygame.K_a] and x > vel:
x -= vel
if keys[pygame.K_d] and x < WinWidth - vel - playerSize:
x += vel
if not (isJump):
if keys[pygame.K_w] and y > vel:
y -= vel
if keys[pygame.K_s] and y < WinHeight - vel - playerSize:
y += vel
if keys[pygame.K_SPACE]:
isJump = True
else:
if jumpCount >= -10:
neg = 1
if jumpCount < 0:
neg = -1
y -= (jumpCount ** 2) * 0.5 * neg
jumpCount -= 1
else:
isJump = False
jumpCount = 10
screen.blit(player, (x, y))
pygame.display.update()
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()
running = True
while running:
clock.tick(60)
# [...]

Trouble Shooting Projectiles Upward in Pygame

I'm in the process of writing a duel-player tank game, similar to one known as "Tank Trouble". Of course, I'm only in the baby steps of it right now and I'm a bit stuck on a particular little bug. At the moment, the code below enables me to display my sprite, able to move around in all the directions, and also able to shoot projectiles. The only issue, however, is that it can only shoot projectiles left or right. Does anyone have any suggestions as to how to change this so that the tank can shoot upward, when facing upward and downward, when facing downward? It can only shoot left and right, even when it is facing up or down, which is kind of odd. I am having trouble accessing the y-axis and having the projectile travel along it.
If anyone can find out how to do that and tell me what the new code is and where to place it, that would help a ton. Here is my code:
import pygame
pygame.init()
screen = pygame.display.set_mode((500,500))
pygame.display.set_caption("Game")
tankImg = pygame.image.load("tank1.png")
downTank = tankImg
leftTank = pygame.image.load("left1.png")
rightTank = pygame.image.load("right1.png")
upTank = pygame.image.load("up1.png")
bg = pygame.image.load("background.png")
screenWidth = 500
screenHeight = 500
clock = pygame.time.Clock()
class player(object):
def __init__(self, x, y, width, height):
self.x = x
self.y = y
self.width = width
self.height = height
self.vel = 5
self.left = False
self.right = False
self.up = False
self.down = False
def draw(self,screen):
screen.blit(tankImg,(self.x,self.y))
class projectile(object):
def __init__(self,x, y, radius, color, facing):
self.x = x
self.y = y
self.radius = radius
self.color = color
self.facing = facing
self.vel = 8 * facing
def draw(self,screen):
pygame.draw.circle(screen, self.color, (self.x,self.y), self.radius)
def redraw():
screen.blit(bg, (0,0))
tank.draw(screen)
for bullet in bullets:
bullet.draw(screen)
pygame.display.update()
run = True
tank = player(300, 410, 16, 16)
bullets = []
while run:
clock.tick(30)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
for bullet in bullets:
if bullet.x < screenWidth and bullet.x > 0:
bullet.x += bullet.vel
elif bullet.y > screenHeight and bullet.y > 0:
bullet.y += bullet.vel
else:
bullets.pop(bullets.index(bullet))
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT] and tank.x > tank.vel:
tank.left = True
tankImg = leftTank
tank.x -= tank.vel
facing = -1
if keys[pygame.K_RIGHT] and tank.x < 500 - tank.width:
tank.right = True
tankImg = rightTank
tank.x += tank.vel
facing = 1
if keys[pygame.K_UP] and tank.y > tank.vel:
tank.up = True
tankImg = upTank
tank.y -= tank.vel
facing = 1
if keys[pygame.K_DOWN] and tank.y < 500 - tank.height:
down = True
tankImg = downTank
tank.y += tank.vel
facing = -1
if keys[pygame.K_SPACE]:
if len(bullets) < 1:
bullets.append(projectile(round(tank.x + tank.width // 2), round(tank.y + tank.height // 2), 4, (0,0,0),facing))
redraw()
pygame.quit()
The issue is caused in that part of the code:
if bullet.x < screenWidth and bullet.x > 0:
bullet.x += bullet.vel
elif bullet.y > screenHeight and bullet.y > 0:
bullet.y += bullet.vel
else:
bullets.pop(bullets.index(bullet))
As long the bullet is in bounds of the window, the 1st condition evaluates True. That causes that the bullet can move in x-direction only.
Instead of the facing attribute add a direction attribute to the class projectile. Furthermore add a method (move) which moves the projectile. This method ignores the bounds of the window:
class projectile(object):
def __init__(self,x, y, radius, color, direction):
self.x = x
self.y = y
self.radius = radius
self.color = color
self.direction = direction
self.vel = 8
def move(self):
self.x += self.direction[0] * self.vel
self.y += self.direction[1] * self.vel
def draw(self,screen):
pygame.draw.circle(screen, self.color, (self.x,self.y), self.radius)
Move the bullets in a loop end evaluate if a bullet is in bounds of the window. This can be done with ease, by using pygame.Rect and collidepoint():
while run:
# [...]
for bullet in bullets[:]:
bullet.move()
window_rect = pygame.Rect(0, 0, screenWidth, screenHeight)
if not window_rect.collidepoint((bullet.x, bullet.y)):
bullets.pop(bullets.index(bullet))
Set the direction of the bullet dependent on the moving direction of the tank:
direction = (-1, 0)
while run:
# [...]
if keys[pygame.K_LEFT] and tank.x > tank.vel:
tank.left = True
tankImg = leftTank
tank.x -= tank.vel
direction = (-1, 0)
if keys[pygame.K_RIGHT] and tank.x < 500 - tank.width:
tank.right = True
tankImg = rightTank
tank.x += tank.vel
direction = (1, 0)
if keys[pygame.K_UP] and tank.y > tank.vel:
tank.up = True
tankImg = upTank
tank.y -= tank.vel
direction = (0, -1)
if keys[pygame.K_DOWN] and tank.y < 500 - tank.height:
down = True
tankImg = downTank
tank.y += tank.vel
direction = (0, 1)
if keys[pygame.K_SPACE]:
if len(bullets) < 1:
px, py = round(tank.x + tank.width // 2), round(tank.y + tank.height // 2)
bullets.append(projectile(px, py, 4, (0,0,0), direction))
I recommend to spawn the bullets in the pygame.KEYDOWN event instead of the evaluating the pressed keys (keys[pygame.K_SPACE]). The event occurs once when a button is pressed. So every time when SPACE is pressed a single bullet is generated (Of course that is up to you):
direction = (-1, 0)
while run:
clock.tick(30)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if event.type == pygame.KEYDOWN:
if event. key == pygame.K_SPACE:
px, py = round(tank.x + tank.width // 2), round(tank.y + tank.height // 2)
bullets.append(projectile(px, py, 4, (0,0,0), direction))
for bullet in bullets[:]:
bullet.move()
window_rect = pygame.Rect(0, 0, screenWidth, screenHeight)
if not window_rect.collidepoint((bullet.x, bullet.y)):
bullets.pop(bullets.index(bullet))
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT] and tank.x > tank.vel:
tank.left = True
tankImg = leftTank
tank.x -= tank.vel
direction = (-1, 0)
if keys[pygame.K_RIGHT] and tank.x < 500 - tank.width:
tank.right = True
tankImg = rightTank
tank.x += tank.vel
direction = (1, 0)
if keys[pygame.K_UP] and tank.y > tank.vel:
tank.up = True
tankImg = upTank
tank.y -= tank.vel
direction = (0, -1)
if keys[pygame.K_DOWN] and tank.y < 500 - tank.height:
down = True
tankImg = downTank
tank.y += tank.vel
direction = (0, 1)
redraw()
Currently, if bullet.x is between 0 and the screen width the first condition is met and the second is not checked
for bullet in bullets:
if bullet.x < screenWidth and bullet.x > 0:
# When this is True then the "elif" is not run
bullet.x += bullet.vel
elif bullet.y > screenHeight and bullet.y > 0:
bullet.y += bullet.vel
else:
bullets.pop(bullets.index(bullet))
You should just have one condition that makes sure the bullet is in both the x and y bound so that you update both x and y
for bullet in bullets:
if 0 < bullet.x < screenWidth and 0 < bullet.y < screenHeight:
bullet.x += bullet.vel
bullet.y += bullet.vel
else:
bullets.pop(bullets.index(bullet))
You can combine conditions like this that check if a value is between 2 values like so min < value < max

Control shooting frequency when the button to shoot is pressed?

The bullets shoot all at once when the button is pressed but I only want them to shoot once every 0.5 seconds if the button to shoot is pressed.
I have tried to import time and delay the bullets but it just delayed pygame itself.
Is there any way that I can regulate how frequent the character can shoot?
import pygame
pygame.init()
win = pygame.display.set_mode((700, 480))
pygame.display.set_caption("First project")
run = True
red = (255, 0, 0)
green = (0, 255, 0)
def drawbg():
pygame.display.update()
win.fill((255, 255, 255))
for bullet in bullets:
bullet.draw(win)
class person(object):
def __init__(self, x, y, width, height):
self.x = x
self.y = y
self.width = width
self.height = height
self.vel = 5
self.IsJump = False
self.jumpCount = 10
self.left = False
self.right = False
class projectile(object):
def __init__(self, x, y, radius, colour, facing):
self.x = x
self.y = y
self.radius = radius
self.colour = colour
self.facing = facing
self.vel = 7 * facing
def draw(self, win):
pygame.draw.circle(win, self.colour, (self.x, self.y), self.radius)
man = person(100, 400, 50, 60)
man2 = person(500, 400, 50, 60)
bullets = []
while run:
pygame.time.delay(25)
for bullet in bullets:
if bullet.x < 700 and bullet.x > 0:
bullet.x += bullet.vel
else:
bullets.pop(bullets.index(bullet))
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
keys = pygame.key.get_pressed()
if keys[pygame.K_g]:
if man.left:
facing = -1
else:
facing = 1
if len(bullets) < 5:
bullets.append(projectile(man.x + man.width//2, round(man.y + man.height/2), 6, (100, 100, 100), facing))
if keys[pygame.K_p]:
if man2.left:
facing = -1
else:
facing = 1
if len(bullets) < 50:
bullets.append(projectile(man2.x + man2.width//2, round(man2.y + man2.height/2), 6, (0, 0, 0), facing))
if keys[pygame.K_LEFT] and man2.x > man2.vel:
man2.x -= man2.vel
man2.left = True
man2.right = False
if keys[pygame.K_RIGHT] and man2.x < 700 - man2.width - man2.vel:
man2.x += man2.vel
man2.right = True
man2.left = False
if keys[pygame.K_a] and man.x > man.vel:
man.x -= man.vel
man.left = True
man.right = False
if keys[pygame.K_d] and man.x < 700 - man.width - man.vel:
man.x += man.vel
man.right = True
man.left = False
if not man.IsJump and keys[pygame.K_w]:
man.IsJump = True
man.JumpCount = 10
if man.IsJump:
if man.JumpCount >= -10:
neg = 1
if man.JumpCount < 0:
neg = -1
man.y -= (man.JumpCount ** 2) / 2 * neg
man.JumpCount -= 1
else:
man.IsJump = False
man.JumpCount = 10
if not man2.IsJump and keys[pygame.K_UP]:
man2.IsJump = True
man2.JumpCount = 10
if man2.IsJump:
if man2.JumpCount >= -10:
neg = 1
if man2.JumpCount < 0:
neg = -1
man2.y -= (man2.JumpCount ** 2) / 2 * neg
man2.JumpCount -= 1
else:
man2.IsJump = False
man2.JumpCount = 10
pygame.draw.rect(win, red, (man.x, man.y, man.width, man.height))
pygame.draw.rect(win, green, (man2.x, man2.y, man2.width, man2.height))
drawbg()
pygame.quit()
You can check for the time the last bullet was fired.
initiate the variable by:
import time
last_bullet = time.time()
then change your code to:
if len(bullets) < 5:
if time.time() - last_bullet > 0.5:
last_bullet = time.time()
bullets.append(projectile(man.x + man.width//2, round(man.y + man.height/2), 6, (100, 100, 100), facing))

How do I fix my 'Jump'?

I am new to this website and pygame so bear with me. I am experimenting with pygame and made a simple platformer. However, whenever I 'Jump', the block jumps frame by frame, so I have to hold down the spacebar. Any help would be greatly appreciated!
here is my code:
import pygame
pygame.init()
win = pygame.display.set_mode((500, 500))
x = 0
y = 490
width = 10
height = 10
vel = 5
pygame.key.set_repeat(1)
isjump = False
jumpcount = 10
while True:
pygame.time.delay(30)
for event in pygame.event.get():
if event.type == pygame.QUIT:
break
keys = pygame.key.get_pressed()
if keys[pygame.K_a] and x>vel-5:
x -= vel
if keys[pygame.K_d] and x < 500 - width:
x += vel
if not(isjump):
if keys[pygame.K_SPACE]:
isjump = True
else:
if jumpcount >= -10:
neg = 1
if jumpcount < 0:
neg = -1
y -= (jumpcount ** 2) /2 * neg
jumpcount -= 1
else:
isjump = False
jumpcount = 10
win.fill((0, 0, 0))
pygame.draw.rect(win, (255, 255, 255), (x, y, width, height))
pygame.display.update()
pygame.quit()
You are mixing your keyboard event handling with your jump-logic. I've done two things, change the spacebar detection to trigger isjump and handle the jump logic irregardless of whether there is a key pressed or not:
import pygame
pygame.init()
win = pygame.display.set_mode((500, 500))
x = 0
y = 490
width = 10
height = 10
vel = 5
pygame.key.set_repeat(1)
isjump = False
jumpcount = 10
while True:
pygame.time.delay(30)
for event in pygame.event.get():
if event.type == pygame.QUIT:
break
keys = pygame.key.get_pressed()
if keys[pygame.K_a] and x>vel-5:
x -= vel
if keys[pygame.K_d] and x < 500 - width:
x += vel
# if we're not already jumping, check if space is pressed to start a jump
if not isjump and keys[pygame.K_SPACE]:
isjump = True
jumpcount = 10
# if we're supposed to jump, handle the jump logic
if isjump:
if jumpcount >= -10:
neg = 1
if jumpcount < 0:
neg = -1
y -= (jumpcount ** 2) /2 * neg
jumpcount -= 1
else:
isjump = False
jumpcount = 10
win.fill((0, 0, 0))
pygame.draw.rect(win, (255, 255, 255), (x, y, width, height))
pygame.display.update()
pygame.quit()
The line keys = pygame.key.get_pressed() and the whole game logic and drawing code should not be in the event loop (for event in pygame.event.get():), otherwise the code gets executed once per event in the queue, and if no events are in the queue, it won't be executed at all.
You could just dedent keys = pygame.key.get_pressed() and all lines beneath.
Alternatively, you could check in the event loop if the space key was pressed (with if event.type == pygame.KEYDOWN:) and then set isjump to True (that means the player will only jump once per keypress).
import pygame
pygame.init()
win = pygame.display.set_mode((500, 500))
clock = pygame.time.Clock()
x = 0
y = 490
width = 10
height = 10
vel = 5
isjump = False
jumpcount = 10
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
isjump = True
keys = pygame.key.get_pressed()
if keys[pygame.K_a] and x > vel - 5:
x -= vel
elif keys[pygame.K_d] and x < 500 - width:
x += vel
if isjump:
if jumpcount >= -10:
neg = 1
if jumpcount < 0:
neg = -1
y -= jumpcount**2 / 2 * neg
jumpcount -= 1
else:
isjump = False
jumpcount = 10
win.fill((0, 0, 0))
pygame.draw.rect(win, (255, 255, 255), (x, y, width, height))
pygame.display.update()
clock.tick(30)
pygame.quit()
I also recommend adding a pygame.time.Clock instance and call clock.tick(FPS) to regulate the frame rate.
And I'd rather implement the jumping in this way, with a gravity constant which gets added to the y-velocity each frame.

Categories

Resources