StreetFighterLan123
StreetFighterLan123

Reputation: 13

How to fix unwanted character acceleration in a Pygame game?

I made a game where a character has to get coins on a 2D map (when you get a coin, it respawns on a random place), while running away form a spongebob-type character who moves randomly. If you touch the spongebob, you die.

The problem I am having is that my character sometimes goes slow, but then sometimes randomly goes fast when I am controlling it with my arrow keys. My changing in the values in the code is constant, so can someone explain to me this doesn't work? Github Link

Here is the code if you don't want to open the link:

import pygame
import random
import math
import time

pygame.init()
screen = pygame.display.set_mode((800,600))
pygame.display.set_caption("Survive the Spongey Boi")

#Sounds
game_over_sound = pygame.mixer.Sound("Game_Over.wav")
pygame.mixer.music.load("background.wav")
pygame.mixer.music.play(-1)

#Score
coins_collected = 0
font = pygame.font.Font('freesansbold.ttf', 32)
#coinfont = pygame.font.Font('freesansbold.ttf', 16)
#Positions of the text.
coin_textX = 10
coin_textY = 10

def show_coin_score(x,y):
    coins_text = font.render("Coins: " + str(coins_collected), True, (0,0,0))
    screen.blit(coins_text, (x,y))

#Player
playerImg = pygame.image.load('monster.png')
playerX = 370
playerY = 480
playerX_change = 0
playerY_change = 0

#Spongebob
enemyImg = pygame.image.load('sponge.png')
enemyX = random.randint(0,735)
enemyY = random.randint(10,400)
enemyX_change = 0
enemyY_change = 0

#Coin
coinImg = pygame.image.load('coin.png')
coinX = random.randint(0,735)
coinY = random.randint(0,535)

#Font for Game Over
over_font = pygame.font.Font('freesansbold.ttf', 64)

def player(x,y):
    screen.blit(playerImg, (x,y))

def enemy(x,y):
    screen.blit(enemyImg, (x,y))

def coin(x,y):
    screen.blit(coinImg, (x,y))

def isCollision(enemyX, enemyY, playerX, playerY):
    #Distance formula in Python
    distance = math.sqrt((math.pow(enemyX - playerX,2)) + (math.pow(enemyY - playerY,2))) 
    if distance < 27:
        return True
    else: 
        return False

def coin_collision(coinX, coinY, playerX, playerY):
    distance = math.sqrt((math.pow(coinX - playerX,2)) + (math.pow(coinY - playerY,2))) 
    if distance < 29:
        return True
    else: 
        return False

def game_over_text():
    over_text = over_font.render("GAME OVER", True, (0, 0, 0))
    screen.blit(over_text, (200,250))

#Game loop
running = True

while running:
    screen.fill((255,255,206))
    #Do the for loop here.
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        #Do the keydown
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_LEFT:
                playerX_change = -2
            if event.key == pygame.K_RIGHT:
                playerX_change = 2
            if event.key == pygame.K_UP:
                playerY_change = -2
            if event.key == pygame.K_DOWN:
                playerY_change = 2
        if event.type == pygame.KEYUP:
            if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT:
                playerX_change = 0
            if event.key == pygame.K_UP or event.key == pygame.K_DOWN:
                playerY_change = 0

    playerX += playerX_change
    playerY += playerY_change

    enemyX += enemyX_change
    enemyY += enemyY_change
    #Boundaries
    if playerX <= 0:
        playerX = 0
    elif playerX > 736:
        playerX = 736
    if playerY <= 0:
        playerY = 0
    elif playerY > 536:
        playerY = 536

    if enemyX <= 0:
        enemyX = 0
    elif enemyX > 736:
        enemyX = 736
    if enemyY <= 0:
        enemyY = 0
    elif enemyY > 536:
        enemyY = 536

    if isCollision(enemyX, enemyY, playerX, playerY):
        game_over_text()
        playerX = 10000
        enemyX = 10000
        pygame.mixer.Sound.play(game_over_sound)
        time.sleep(3.5)
        break
    if coin_collision(coinX, coinY, playerX, playerY):
        coins_collected += 1
        #time.sleep(0.00001)
        coinX = random.randint(0,735)
        coinY = random.randint(0,535)
    #CHANGE THIS LATER
    enemyX_change = random.randint(-15,15)
    enemyY_change = random.randint(-15,15)

    #score_value = score_value//1

    show_coin_score(coin_textX, coin_textY)
    coin(coinX, coinY)
    enemy(enemyX, enemyY)
    player(playerX, playerY)
    pygame.display.update()

Upvotes: 1

Views: 104

Answers (1)

Rabbid76
Rabbid76

Reputation: 210909

Nice game! The issue seems to be cause, because you use the KEYDOW and KEYUP event. That may lead to ans issue when you change the direction between left and right respectively up and down, because the movement is canceled in on KEYUP.

I recommend to use the pygame.key.get_pressed to get the current states of the key. Set playerX_change respectively playerY_change dependent on the state of the keys:

while running:
    # [...]    

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False

    keys = pygame.key.get_pressed()
    playerX_change, playerY_change = 0, 0
    if keys[pygame.K_LEFT]:
        playerX_change -= 2
    if keys[pygame.K_RIGHT]:
        playerX_change += 2
    if keys[pygame.K_UP]:
        playerY_change -= 2
    if keys[pygame.K_DOWN]:
        playerY_change += 2

Side note, use min and max to simplify the limitation to the bounderys:

while running:
    # [...]

    #Boundaries
    playerX = max(0, min(736, playerX))
    playerY = max(0, min(536, playerY))
    enemyX  = max(0, min(736, enemyX))
    enemyY  = max(0, min(536, enemyY))

Upvotes: 1

Related Questions