user2214288
user2214288

Reputation: 35

Pygame Arrow Control

I am wondering why is it that when I execute the file,
the arrow control and movement of the left rectangle will not continuously move up or down, even though I am holding down on the arrow keys for a long time.

import pygame

black    = (   0,   0,   0)
white    = ( 255, 255, 255)
green    = (   0, 255,   0)
red      = ( 255,   0,   0)

pygame.init()

size = [700,500]
screen = pygame.display.set_mode(size)

fonto = pygame.font.SysFont("algerian", 100)
font = pygame.font.SysFont("algerian", 12)
text = fonto.render("Game Over", True, (0, 128, 10))

pygame.display.set_caption("Vasanths First Legit Game")

done = False
pygame.mouse.set_visible(0)

clock = pygame.time.Clock()
score = 1

rect_x = 50
rect_y = 50
rect_xp = 10
rect_yp = 10

rect_change_x = 10
rect_change_y = 10
rect_change_xp = 10
rect_change_yp = 3

while done == False:
    for event in pygame.event.get(): 
        if event.type == pygame.QUIT: 
            done=True 

        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_DOWN:
                rect_yp = rect_change_yp+rect_yp
        if event.type == pygame.KEYUP:
            if event.key == pygame.K_DOWN:
                rect_yp = 0+rect_yp

        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_LEFT:
                rect_yp=-3+rect_yp
            if event.key == pygame.K_RIGHT:
                rect_yp=3+rect_yp
            if event.key == pygame.K_UP:
                rect_yp=-3+rect_yp
            if event.key == pygame.K_DOWN:
                rect_yp=3+rect_yp

        if event.type == pygame.KEYUP:
            if event.key == pygame.K_LEFT:
                rect_yp=0+rect_yp
            if event.key == pygame.K_RIGHT:
                rect_yp=0+rect_yp
            if event.key == pygame.K_UP:
                rect_yp=0+rect_yp
            if event.key == pygame.K_DOWN:
                rect_yp=0+rect_yp

    pos = pygame.mouse.get_pos()

    x = pos[0] 
    y = pos[1] 

    screen.fill(black)

    pygame.draw.rect(screen,white,[rect_x,rect_y,10,10])
    pygame.draw.rect(screen,green,[x,490,50,10])
    pygame.draw.rect(screen,green,[10,rect_yp,10,50])
    # Move the rectangle starting point
    rect_x += rect_change_x
    rect_y += rect_change_y

    if rect_y == 0:
        rect_change_x=rect_change_x*1
        rect_change_y=rect_change_y*-1
    if rect_y == 490:
       if rect_x < x + 50 :
            scoref = font.render(score, True, (0, 128, 0))
            screen.blit(scoref,
                (20 - scoref.get_width() // 10, 20 - scoref.get_height() // 10))
            rect_change_x=rect_change_x*1
            rect_change_y=rect_change_y*-1

        if rect_x < x:
            rect_change_y = 0
            rect_change_x = 0

            #dont do this , it will go bizzonkes
            score = str(score)
            score = int(score)

    if rect_y == 490:
        if rect_x < x + 50 :
            if rect_change_x !=0:
                if rect_change_y !=0:
                    score=int(score)
                    score = score + 1
                    score=str(score)
    if rect_change_x == 0:
        if rect_change_y == 0:
                    screen.blit(text,
                        (320 - text.get_width() // 2, 240 - text.get_height() // 2))

    if rect_x == 700:
        rect_change_x = rect_change_x*-1
        rect_change_y = rect_change_y*1

    if rect_x == 0:
        rect_change_x = rect_change_x*0
        rect_change_y = rect_change_y*0

    if rect_y == 500:
        rect_change_y = 0
        rect_change_x = 0
        screen.blit(text,
            (320 - text.get_width() // 2, 240 - text.get_height() // 2))
        score=str(score)


    print(score)
    score = str(score)

    scoref = font.render(score, True, (0, 128, 0))
    screen.blit(scoref,
                (20 - scoref.get_width() // 10, 20 - scoref.get_height() // 10))

    clock.tick(30)

    pygame.display.flip()

pygame.quit ()

Upvotes: 2

Views: 11264

Answers (3)

user2741371
user2741371

Reputation: 115

I would use pygame.key.get_pressed(), but you are also forgetting pygame.key.set_repeat(). The first argument is the # of milliseconds it takes to start repeating, and the second is the interval at which the key repeats.

This is an example which uses both:

x = 400
y = 300

import pygame, sys

bkg = (255, 211, 0)
clr = (0, 0, 0)
squ = (8, 11, 134)

pygame.init()
size = (800, 600)
screen = pygame.display.set_mode(size)
pygame.display.set_caption("Bloxy")
pygame.key.set_repeat(1, 1)
font = pygame.font.SysFont("Stencil", 20)
clock = pygame.time.Clock()

while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            sys.exit()

    keys_pressed = pygame.key.get_pressed()

    if keys_pressed[pygame.K_LEFT]:
        x -= 5
    if keys_pressed[pygame.K_RIGHT]:
        x += 5
    if keys_pressed[pygame.K_UP]:
        y -= 5
    if keys_pressed[pygame.K_DOWN]:
        y += 5

    if x > 800:
        x = 0
    if x < 0:
        x = 800
    if y > 600:
        y = 0
    if y < 0:
        y = 600

    screen.fill(bkg)
    text = font.render('(' + str(x) + ',' + str(y) + ')', True, clr)
    screen.blit(text, [10, 10])
    pygame.draw.rect(screen, squ, [x - 10, y - 10, 20, 20])

    pygame.display.flip()
    clock.tick(60)

Upvotes: 1

Haz
Haz

Reputation: 2679

This is how I handle it in one of my own Pygame projects:

class Inputs:

def __init__(self):
    self.bindings = {"up": pygame.K_UP,
                     "down":  pygame.K_DOWN,
                     "left":  pygame.K_LEFT,
                     "right":   pygame.K_RIGHT,
                     "lp":  pygame.K_a,
                     "mp":  pygame.K_s,
                     "hp":  pygame.K_d,
                     "lk":  pygame.K_z,
                     "mk":  pygame.K_x,
                     "hk":  pygame.K_c,
                     "pause":   pygame.K_RETURN}

    self.inputState = {"up": False,
                   "down": False,
                   "right": False,
                   "left": False,
                   "lp": False,
                   "mp": False,
                   "hp": False,
                   "lk": False,
                   "mk": False,
                   "hk": False,
                   "pause": False}

    self.buffer = InputBuffer()

def lookupBinding(self, keyEntered):
    for binding, keyBound in self.bindings.items():
        if keyEntered == keyBound:
            return binding

    return "not found"

def getInputState(self, events):
    for event in events:

        if event.type == pygame.KEYDOWN:
            binding = self.lookupBinding(event.key)
            if binding != "not found":
                newInput = Input()
                newInput.inputName = binding
                newInput.timeSinceInput = 0
                self.buffer.push(newInput)
                self.inputState[binding] = True

        if event.type == pygame.KEYUP:
            binding = self.lookupBinding(event.key)
            if binding != "not found":
                self.inputState[binding] = False

    return self.inputState

I keep two dictionaries, one of in-game "commands", such as directions, to the pygame key, then another of those commands to a boolean representing the command's on/off state. By watching for KEYDOWN and KEYUP events, I can determine which mapped inputs are on and which are off.

EDIT: A benefit of this way method that I should mention is that it makes it very easy to change the key mapping later on, or even allow custom key-mappings. Your game logic only needs to rely on the basic inputs, such as a jump or move input, and won't need to change if the key-mappings change.

Upvotes: 1

Bartlomiej Lewandowski
Bartlomiej Lewandowski

Reputation: 11170

In pygame the input is handled in a event loop. There is a event queue, the system sends input from the keyboard, and by calling pygame.event.get() you get the first event in the queue. There are many types of events, the most popular being KEYUP and KEYDOWN. The mistake that most beginner people make, is that they believe that when a button is pressed, a KEYDOWN event is sent the whole time. That is not needed, since if you press a button, it is pressed until you release it. So you need to have certain flags to see if a button is pressed.

The most popular way of doing this is by using a d = v*t equation. Since the speed is constant, we need to introduce a direction. So our equation would look like this:

distance_changed = direction * speed * time_change

In your event loop, you then change the direction:

1 if KEYDOWN-RIGHT

-1 if KEYDOWN-LEFT

0 if KEYUP-LEFTorRIGHT.

Now the question might pop up, why use time_change? Since, we cannot predict on which machines the program will work, the amount of times the loop will repeat will not be known. If you take an old machine, the game will work much slower. So we measure the time taken from the last movement, so that it will not changed on different machines.

I have see that you use pygame.tick(30), which waits so that the time it took for the loop to finish was constant. The problem arises, when you run this at an older machine. The loop cannot speed up.

As a suggestion, you should divide you game into functions. It's much more readable, and you can use you code in different places. Also, your event loop, has to many ifs. Use elif since there is no point to check if RIGTH key was pressed if LEFT was already pressed.

Upvotes: 4

Related Questions