pygame strange behavior on key pressings - python

I am kind of new to pygame module.
I am keeping track of the key pressings from the terminal via PyCharm IDE.
To clearness, I am adding screenshot of the workspace of mine below.
Now, the problem is, I found out that, If I am pressing and holding DOWN and UP keys at the same time, the system can detect RIGHT key pressings, however ignorant to LEFT key pressings.
Same thing is valid for holding W and S keys together and sensing T key but not sensing E or Q keys.
RIGHT & LEFT being hold, senses DOWN does not sense UP
I am adding a fully ready to run code(except you need pygame module installed) for ones who might want to try on their computer.
import pygame
#import time
pygame.init()
display_width = 800
display_height = 600
white = (255, 255, 255)
black = (0, 0, 0)
red = (255, 0, 0)
green = (0, 255, 0)
blue = (0, 0, 255)
#carImg = pygame.image.load('raceCar.png')
# def drawCar(x, y):
# gameDisplay.blit(carImg, (x, y))
x = display_width * 0.45
y = display_height * 0.6
dx = 0
dy = 0
gameDisplay = pygame.display.set_mode((display_width, display_height))
pygame.display.set_caption("MY GAME")
clock = pygame.time.Clock()
crashed = False
Quit = False
i = 0
while not crashed and not Quit:
for event in pygame.event.get():
# if event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE:
# Quit = True
#
# elif event.type == pygame.KEYDOWN:
#
# if event.key == pygame.K_DOWN:
# dy += 5
# elif event.key == pygame.K_UP:
# dy += -5
# elif event.key == pygame.K_RIGHT:
# dx += 5
# elif event.key == pygame.K_LEFT:
# dx += -5
#
# elif event.type == pygame.KEYUP:
#
# if event.key == pygame.K_DOWN:
# dy += -5
# elif event.key == pygame.K_UP:
# dy += 5
# elif event.key == pygame.K_RIGHT:
# dx += -5
# elif event.key == pygame.K_LEFT:
# dx += 5
#
# elif event.type == pygame.QUIT:
# Quit = True
i += 1
print(i, event)
# x = (x + 1) % display_width
# y = (y - 1) % display_height
x += dx
y += dy
gameDisplay.fill(white)
x = x if x <= display_width else -163
x = x if x+163 >= 0 else display_width
y = y if y <= display_height else -244
y = y if y + 244 >= 0 else display_height
# drawCar(x, y)
pygame.display.update()
clock.tick(60)
pygame.quit()
quit()
Note that, I have commented out unnecessary parts in order to make it ready to run for anyone easily.

I suspect it's the way your code is handling key-presses. It's better to use the pygame.key.get_pressed(), which returns a dictionary of the current state of all keys pressed at that instant. But the presented code (the commented out section) does not seem to have any issues that would cause this.
Below is some example code that demonstrates handling multiple key-presses. You can also use it to ensure your keyboard handles multiple presses correctly. I would expect every keyboard can handle a minimum of 3 simultaneous key-presses, since otherwise Ctrl-Alt-Del would be impossible.
import pygame
# Window size
WINDOW_WIDTH = 400
WINDOW_HEIGHT = 50
WINDOW_SURFACE = pygame.HWSURFACE|pygame.DOUBLEBUF|pygame.RESIZABLE
DARK_BLUE = ( 3, 5, 54)
WHIPPED_CREAM = ( 251, 252, 214 )
### initialisation
pygame.init()
window = pygame.display.set_mode( ( WINDOW_WIDTH, WINDOW_HEIGHT ), WINDOW_SURFACE )
pygame.display.set_caption("Multi Keys Test")
# We need to write some stuff
default_font = pygame.font.SysFont(None, 40)
### Main Loop
clock = pygame.time.Clock()
done = False
while not done:
# Handle user-input
for event in pygame.event.get():
if ( event.type == pygame.QUIT ):
done = True
# Make a string of which arrow-keys are pressed
# EDIT: Removing the loop, as it seems to be causing some minor confusion
currently_pressed = ""
keys = pygame.key.get_pressed()
if ( keys[ pygame.K_UP ] ):
currently_pressed += "up "
if ( keys[ pygame.K_DOWN ] ):
currently_pressed += "down "
if ( keys[ pygame.K_LEFT ] ):
currently_pressed += "left "
if ( keys[ pygame.K_RIGHT ] ):
currently_pressed += "right "
keys_text = default_font.render( currently_pressed, True, WHIPPED_CREAM )
# Update the window, but not more than 60fps
window.fill( DARK_BLUE )
window.blit( keys_text, ( 10, 10 ) )
pygame.display.flip()
# Clamp FPS
clock.tick_busy_loop(60)
pygame.quit()
For what it's worth, I can get it to show "left right up down" all together.

This is most likely the result of hardware limitations. It's called keyboard ghosting and happens to most cheap commercial keyboards

Related

how to randomly generate spikes in pygame which are constantly moving down

im building a game in pygame in which a hot air balloon is constantly going up and spikes are coming down and hot air balloon has to dodge them. However i dont know how to randomly generate nicely spaced spikes which constantly moving downwards im having issue with randomly generating downward moving spikes.
here is the code:
import pygame
import random
import math
pygame.init()
clock = pygame.time.Clock()
screenwid = 400
screenhigh = 500
screen = pygame.display.set_mode((screenwid, screenhigh))
grey = (240,240,240)
black = (0,0,0)
initvel = 3
player_x = 100
player_y = 250
spikex= -100
spikey = -100
xchange = 0
ychange = 0
baloon = pygame.image.load('C:/Users/aliab/Downloads/hotair balloom.png')
baloon = pygame.transform.scale(baloon,(300, 300))
spike = pygame.image.load('C:/Users/aliab/Downloads/spikes.png')
spike = pygame.transform.scale(spike,(300, 300))
bg = pygame.image.load('E:/bgparacute.jpg')
def balloon(x,y):
screen.blit(baloon,(x,y ))
def spikee(x,y):
screen.blit(spike,(x,y ))
y = 0
run = True
while run:
rel_y = y % bg.get_rect().height
screen.blit(bg,(0,rel_y - bg.get_rect().height))
if rel_y < screenhigh:
screen.blit(bg, (0, rel_y))
y +=1
for event in pygame.event.get():
if event.type == pygame.QUIT:
quit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
xchange = -initvel
ychange = 0
if event.key == pygame.K_RIGHT:
xchange = initvel
ychange = 0
if event.key == pygame.K_UP:
ychange = -initvel
xchange = 0
if event.key == pygame.K_DOWN:
ychange = initvel
xchange = 0
if spikey == 100:
print('hihiohug')
spikex = random.randint(0, 400)
spikey = random.randint(-20, 10)
spikey += 2
player_x += xchange
player_y += ychange
balloon(player_x,player_y)
spikee(spikex, spikey)
clock.tick(60)
pygame.display.update()
pygame.quit()
I tried out your program. If you are looking to only have a few spikes on your screen, theoretically, you could just individually define the spikes and then randomly generate their starting position as in your code with some simple tweaks.
import pygame
import random
import math
pygame.init()
clock = pygame.time.Clock()
screenwid = 400
screenhigh = 500
screen = pygame.display.set_mode((screenwid, screenhigh))
grey = (240,240,240)
black = (0,0,0)
initvel = 2
player_x = 100
player_y = 250
spikex1 = -100
spikey1 = -100
spikex2 = -40
spikey2 = -100
xchange = 0
ychange = 0
baloon = pygame.image.load('Balloon.png')
baloon = pygame.transform.scale(baloon,(240, 240))
spike1 = pygame.image.load('Mine.png') # Multiple spike definitions (very simplistic)
spike1 = pygame.transform.scale(spike1,(30, 30))
spike2 = pygame.image.load('Mine.png')
spike2 = pygame.transform.scale(spike2,(30, 30))
bg = pygame.image.load('background-day.png')
def balloon(x,y):
screen.blit(baloon,(x,y ))
def spikee(x,y):
screen.blit(spike1,(x,y ))
screen.blit(spike2,(x,y ))
y = 0
run = True
while run:
rel_y = y % bg.get_rect().height
screen.blit(bg,(0,rel_y - bg.get_rect().height))
if rel_y < screenhigh:
screen.blit(bg, (0, rel_y))
y +=1
for event in pygame.event.get():
if event.type == pygame.QUIT:
quit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
xchange = -initvel
ychange = 0
if event.key == pygame.K_RIGHT:
xchange = initvel
ychange = 0
if event.key == pygame.K_UP:
ychange = -initvel
xchange = 0
if event.key == pygame.K_DOWN:
ychange = initvel
xchange = 0
if event.type == pygame.KEYUP: # Allow for a little more control of the balloon
xchange = 0
ychange = 0
if spikey1 == 280:
print('hihiohug')
spikex1 = random.randint(0, 300)
spikey1 = random.randint(-100, 10) # Adjust the random start above the screen for the spike
if spikey2 == 280:
print('hihiohug')
spikex2 = random.randint(0, 300)
spikey2 = random.randint(-100, 10) # Adjust the random start above the screen for the spike
spikey1 += 1
spikey2 += 1
player_x += xchange
player_y += ychange
balloon(player_x,player_y)
spikee(spikex1, spikey1)
spikee(spikex2, spikey2)
clock.tick(60)
pygame.display.update()
pygame.quit()
This produced randomly generated spikes (mines in my test).
However, you might want to define an array of spikes that are randomly placed just off of the display. As an example of that, I am including a link to GitHub for you to pull down a simple game I call "Submarine".
Submarine Game
It is an arcade like game where the submarine tries to avoid hitting underwater mines. It effectively is running in a horizontal fashion as opposed to your vertical action, but the underlying premises are alike. It has an array set up for storing underwater mine images that then appear on the screen.
Give that a try and see if that moves you forward in your game.

Can someone help implement gravity and running animation into my pygame code? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 2 years ago.
Improve this question
I'm making Mario with pygame for my class assessment this school term and am sorta new to pygame, i can't find anywhere how to properly implement gravity into my game, so when mario jumps, he comes back down. My second problem is trying to make a running animation, i want Mario to flick through pictures as he moves left and right in the order; 1, 2, 3, 2 (and over and over). If someone could help it would be great!
import pygame
import time
import random
pygame.init()
display_width = 800
display_height = 600
mario_width = 55
blue = (77, 240, 255)
green = (0, 186, 43)
ground_colour = (186, 150, 97)
gameDisplay = pygame.display.set_mode((display_width,display_height))
pygame.display.set_caption("Super Italiano Bros")
direction = 'right'
clock = pygame.time.Clock()
cloudImg = pygame.image.load('Cloud.png')
rightMarioImg = pygame.image.load('MarioRight.png')
rightMarioImg2 = pygame.image.load("MarioRight2.png")
rightMarioImg3 = pygame.image.load("MarioRight3.png")
leftMarioImg = pygame.image.load('MarioLeft.png')
leftMarioImg2 = pygame.image.load('MarioLeft2.png')
leftMarioImg3 = pygame.image.load('MarioLeft3.png')
def marioRight(x,y):
gameDisplay.blit(rightMarioImg, (x,y))
def marioLeft(x,y):
gameDisplay.blit(leftMarioImg, (x,y))
def cloud(x_cloud,y_cloud):
gameDisplay.blit(cloudImg, (x_cloud,y_cloud))
def cloud_two(x_cloud_two,y_cloud_two):
gameDisplay.blit(cloudImg, (x_cloud_two,y_cloud_two))
def game_loop():
global direction
x = (320)
y = (360)
x_cloud = (-200)
y_cloud = (-220)
x_cloud_two = (200)
y_cloud_two = (-170)
x_change = (0)
y_change = (0)
gameExit = False
while not gameExit:
for event in pygame.event.get():
if event.type == pygame.QUIT:
gameExit = True
print(event)
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
x_change = -5
direction = 'left'
if event.key == pygame.K_RIGHT:
x_change = 5
direction = 'right'
if event.key == pygame.K_UP:
y_change = -60
if event.key == pygame.K_ESCAPE:
gameExit = True
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT or event.key == pygame.K_UP:
x_change = 0
y_change = 60
x += x_change
y += y_change
if x <= 0:
x = 0
if y <= 300:
y = 300
if y >= 360:
y = 360
gameDisplay.fill(blue)
pygame.draw.rect(gameDisplay, ground_colour, (0,500,800,500))
pygame.draw.rect(gameDisplay, green, (0, 470, 800, 30))
cloud(x_cloud,y_cloud)
cloud_two(x_cloud_two,y_cloud_two)
if direction == 'right':
marioRight(x,y)
else:
marioLeft(x,y)
pygame.display.update()
clock.tick(60)
game_loop()
pygame.quit()
quit()
Fixed some issues and did a lot of code styling. When you press the up key he jumps a fixed amount and when you release it he goes back to the ground level. Now it animates itself. The image is changed every loop, which is probably super fast, so you will probably only want to increase the state every a certain amount of frames.
Summary of what I changed:
Imports are usually grouped in three different blocks (divided by a single blank line) and ordered alphabetically:
The first block contains all standard library imports
The second block contains third party libraries
The third block contains local imports to other files in this project
A file should have 0 not used imports
Function and variable names in python follow snake case notation: my_variable and my_function. "Constants" are written in snake upper case: MY_CONSTANT. Classes use camel case: MyClass.
dicts and lists allow you to store data in a more organized way. For example, we can have a MARIO_IMGS dict of lists that store all the mario images so they can be accessed like MARIO_IMGS['right'][0] (the first image is index 0 as lists start counting by 0).
Try to avoid global variables, I moved the variables that were only needed inside the loop to the game_loop function and the remaining top level statements that were not definitions isnide a if __name__ == '__main__': block that runs whenever this script is launched but not when this scrip is imported.
Functions are meant to be reused, having cloudand cloud_two functions that do exactly the same makes no sense. Call cloud(x_cloud, y_cloud) and then cloud(x_cloud_two, y_cloud_two).
Do not use unneeded brackets if they do not provide clarity, for example: x = (320) should be x = 320
You had a indentation error where you process events outside the event loop, so only the last event would be processed (except for exiting, that part was inside the loop so every event would be checked against pygame.QUIT)
Lines should be 80 chars or lower.
quit() at the end of a python file is not needed. quit() is mostly used to close the python interpreter from a terminal window.
import pygame
# Window width and height in px
DISPLAY_SIZE = (800, 600)
# Window title
TITLE = "Super Italiano Bros"
# Predefined colors
BLUE = (77, 240, 255)
GREEN = (0, 186, 43)
GROUND_COLOR = (186, 150, 97)
# Images
MARIO_IMGS = {
'right': [
pygame.image.load('MarioRight.png'),
pygame.image.load("MarioRight2.png"),
pygame.image.load("MarioRight3.png"),
pygame.image.load("MarioRight2.png"),
],
'left': [
pygame.image.load('MarioLeft.png'),
pygame.image.load('MarioLeft2.png'),
pygame.image.load('MarioLeft3.png'),
pygame.image.load('MarioLeft2.png'),
]
}
CLOUD_IMG = pygame.image.load('Cloud.png')
MAX_STATES = min(map(len, MARIO_IMGS.values())) # 3
def draw_mario(x, y, direction='right', state=0):
screen.blit(MARIO_IMGS[direction][state], (x, y))
def draw_cloud(x_cloud, y_cloud):
screen.blit(CLOUD_IMG, (x_cloud, y_cloud))
def game_loop():
# Mario position
x = 320
y = 360
x_change = 0
state = 0
direction = 'right'
# Cloud positions
x_cloud = -200
y_cloud = -220
x_cloud_two = 200
y_cloud_two = -170
# Clock used to limit the FPS
clock = pygame.time.Clock()
game_exit = False
while not game_exit:
for event in pygame.event.get():
if event.type == pygame.QUIT:
game_exit = True
print(event)
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
x_change = -5
direction = 'left'
if event.key == pygame.K_RIGHT:
x_change = 5
direction = 'right'
if event.key == pygame.K_UP:
y = 300
if event.key == pygame.K_ESCAPE:
game_exit = True
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT:
x_change = 0
elif event.key == pygame.K_UP:
y = 360
x += x_change
if x < 0:
x = 0
elif x > DISPLAY_SIZE[0]:
x = DISPLAY_SIZE[0]
screen.fill(BLUE)
pygame.draw.rect(screen, GROUND_COLOR, (0, 500, 800, 500))
pygame.draw.rect(screen, GREEN, (0, 470, 800, 30))
draw_cloud(x_cloud, y_cloud)
draw_cloud(x_cloud_two, y_cloud_two)
draw_mario(x, y, direction, state)
# Increase the state to animate Mario
state += 1
state %= MAX_STATES # Start back from 0 if we have reached the end
pygame.display.update()
clock.tick(60)
if __name__ == '__main__':
pygame.init()
screen = pygame.display.set_mode(DISPLAY_SIZE)
pygame.display.set_caption(TITLE)
game_loop()
pygame.quit()
You should probably change your mario and cloud to Sprites. An Sprite is a class that has a rect and an image attributes that define how they are drawn, and then instead of using screen.blit(IMAGE, POSITION) you just tell pygame to draw the sprite and he will use those two attributes to draw the desired image at the position of the rect.

How do I continuously loop KEYDOWN in pygame?

I'm new to python/pygame and I can't figure this out. Whenever I press and hold a key it won't loop the KEYDOWN. Also, if I hold the key on my keyboard down and move the mouse at the same time, it seems to move continuously.
Can someone tell me what I'm doing wrong?
import pygame
import random
pygame.init()
#Colors
white = 255, 255, 255
black = 0, 0, 0
back_color = 48, 255, 124
light_color = 34, 155, 78
#Display W/H
display_width = 800
display_height = 600
#X/Y
x_axis = 400
y_axis = 580
Block_size = 20
x_int = 0
y_int = 0
ON = True
Window = pygame.display.set_mode((display_width, display_height))
pygame.display.set_caption('Game')
#On Loop
while ON == True:
#Screen Event
for Screen in pygame.event.get():
#Quit Screen
if Screen.type == pygame.QUIT:
pygame.quit()
exit()
#Quit Full Screen
if Screen.type == pygame.KEYDOWN:
if Screen.key == pygame.K_q:
pygame.quit()
exit()
#Full Screen !!!!!!!! EDIT THIS !!!!!!!!
if Screen.type == pygame.KEYDOWN:
if Screen.key == pygame.K_1:
pygame.display.set_mode((display_width, display_height),pygame.FULLSCREEN)
if Screen.key == pygame.K_2:
pygame.display.set_mode((display_width, display_height))
#Player Movement K DOWN
if Screen.type == pygame.KEYDOWN:
if Screen.key == pygame.K_d:
x_int = 20
if Screen.key == pygame.K_a:
x_int = -20
#Player Movement K UP
if Screen.type == pygame.KEYUP:
if Screen.key == pygame.K_d or Screen.key == pygame.K_a:
x_int = 0
x_axis += x_int
Window.fill((back_color))
Player = pygame.draw.rect(Window, light_color, [x_axis, y_axis, Block_size, Block_size])
pygame.display.update()
quit()
I have improved your code. You have placed the screen update (drawing the screen) portion in the events loop whereas it should be in the while loop. The code I have mode is a bit complex but works as expected. Why it is complex? When the key is held down, then the events list is empty (you can print the events). I have also made the block not to go out of the screen. The speed of the block was high so I decreased it to 10.
import pygame
import random
pygame.init()
#Colors
white = 255, 255, 255
black = 0, 0, 0
back_color = 48, 255, 124
light_color = 34, 155, 78
#Display W/H
display_width = 800
display_height = 600
#X/Y
x_axis = 400
y_axis = 580
global x_int
Block_size = 20
x_int = 0
y_int = 0
ON = True
Window = pygame.display.set_mode((display_width, display_height))
pygame.display.set_caption('Game')
global topass_a,topass_d
x_int,topass_a,topass_d = 0,0,0
#On Loop
while ON:
#Screen Event
events = pygame.event.get()
def on_a_press():
global topass_a,x_int
x_int = -10
topass_a = 1
def on_d_press():
global topass_d,x_int
x_int = 10
topass_d = 1
if len(events) == 0:
if topass_a == 1:on_a_press()
if topass_d == 1:on_d_press()
for Screen in events:
if Screen.type == pygame.QUIT:
pygame.quit()
exit()
if Screen.type == pygame.KEYDOWN:
if Screen.key == pygame.K_q:
pygame.quit()
exit()
if Screen.key == pygame.K_1:
pygame.display.set_mode((display_width, display_height),pygame.FULLSCREEN)
if Screen.key == pygame.K_2:
pygame.display.set_mode((display_width, display_height))
if Screen.key == pygame.K_d or topass_d == 1:
on_d_press()
if Screen.key == pygame.K_a or topass_a == 1:
on_a_press()
if Screen.type == pygame.KEYUP:
if Screen.key == pygame.K_d or Screen.key == pygame.K_a:
x_int = 0
topass_a = 0
topass_d = 0
x_axis += x_int
x_int = 0
if x_axis < 0:x_axis=0
elif x_axis >= display_width-Block_size:x_axis = display_width-Block_size
Window.fill((back_color))
Player = pygame.draw.rect(Window, light_color, [x_axis, y_axis, Block_size, Block_size])
pygame.display.update()
You can further improve the code as you need.
Edit:
Why complex? Easy things come first. I have realized that there is no need to track the keys. pygame.key.get_pressed() returns the pressed key. Here is a smaller , better and improved code. I have also implemented the w and s (y_axis) keys.
import pygame
import random
pygame.init()
#Colors
white = 255, 255, 255
black = 0, 0, 0
back_color = 48, 255, 124
light_color = 34, 155, 78
#Display W/H
display_width = 800
display_height = 600
#X/Y
x_axis = 400
y_axis = 580
Block_size = 20
x_int = 0
y_int = 0
ON = True
Window = pygame.display.set_mode((display_width, display_height))
pygame.display.set_caption('Game')
while ON:
events = pygame.event.get()
for Screen in events:
if Screen.type == pygame.QUIT:
pygame.quit()
exit()
if Screen.type == pygame.KEYDOWN:
if Screen.key == pygame.K_q:
pygame.quit()
exit()
if Screen.key == pygame.K_1:
pygame.display.set_mode((display_width, display_height),pygame.FULLSCREEN)
if Screen.key == pygame.K_2:
pygame.display.set_mode((display_width, display_height))
keys = pygame.key.get_pressed()
if keys[pygame.K_a]:
x_int = -10
if keys[pygame.K_d]:
x_int = 10
# keys controlling y axis, you can remove these lines
if keys[pygame.K_w]:
y_int = -10
if keys[pygame.K_s]:
y_int = 10
#x_axis......
x_axis += x_int
x_int = 0
if x_axis < 0:x_axis=0
elif x_axis >= display_width-Block_size:x_axis = display_width-Block_size
#y axis
y_axis += y_int
y_int = 0
if y_axis < 0:y_axis=0
elif y_axis >= display_height-Block_size:y_axis = display_height-Block_size
#updaing screen
Window.fill((back_color))
Player = pygame.draw.rect(Window, light_color, [x_axis, y_axis, Block_size, Block_size])
pygame.display.update()
You only receive pygame.KEYDOWN when the key is first pressed - not while it is held down. The simple solution is to only draw while the key is down (ie. when x_int != 0)
#On Loop
while ON == True:
#Screen Event
for Screen in pygame.event.get():
# <Removed not relevant code for brevity>
#Player Movement K DOWN
if Screen.type == pygame.KEYDOWN:
if Screen.key == pygame.K_d:
x_int = 20
if Screen.key == pygame.K_a:
x_int = -20
#Player Movement K UP
if Screen.type == pygame.KEYUP:
if Screen.key == pygame.K_d or Screen.key == pygame.K_a:
x_int = 0
# Render only happens if x_int is not zero
# (Need to add code to force render first time)
if x_int:
x_axis += x_int
Window.fill((back_color))
Player = pygame.draw.rect(Window, light_color, [x_axis, y_axis, Block_size, Block_size])
pygame.display.update()
As the program grows and gets more complex, you'll need better logic for when to render, but this will get you started.

How would I make a car move the direction it's pointing (After use of pygame.translation.rotate)

Okay so I'm making a test for making a racing game...
And I want the car to move in the direction it's pointing.
Here is my code.
import pygame, sys
from pygame.locals import *
pygame.init()
mainClock = pygame.time.Clock()
degree = 0
WHITE = 250,250,250
rect2 = pygame.rect = (100,100,50,50)
WINDOWWIDTH = 1200
WINDOWHEIGHT = 750
thing = pygame.image.load('car.png')
screen = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT), 0, 32)
pygame.display.set_caption('Teh test')
left = False
right = False
while True:
rect2 = pygame.rect = (100,100,50,50)
if right == True:
degree -= 2
if left == True:
degree += 2
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
if event.type == KEYDOWN:
if event.key == ord('a'):
left = True
if event.key == ord('d'):
right = True
if event.type == KEYUP:
if event.key == ord('a'):
left = False
if event.key == ord('d'):
right = False
pygame.draw.rect(screen,WHITE,rect2)
screen.fill((40, 40, 40))
thing2 = pygame.transform.rotate(thing,degree)
screen.blit(thing2,(100,100))
pygame.display.update()
mainClock.tick(60)
So like I said I want to know how to move the car in the direction it's pointing.
I tried to think of a way but I couldn't think of anything. So there isn't really anything to correct.
(If there are any questions I'll edit my question to answer it.) Please make sure you know pygame before answering.
You'll want to use trigonometry to calculate how much you want to move in the x and y directions, so that the car ends up moving in the correct direction. To calculate this, you can do this:
dx = math.cos(math.radians(degree))
dy = math.sin(math.radians(degree))
position = (position[0] + dx * SPEED, position[1] - dy * SPEED)
Note that you'll also need to initialize a position variable somewhere at the start of your code like this:
position = (100, 100)
Then, you have to change the blit line of code so you draw at the position variable, instead of at (100, 100) all of the time:
screen.blit(thing2, position)
Edit: Working example
import pygame, sys
from pygame.locals import *
import math
pygame.init()
mainClock = pygame.time.Clock()
degree = 0
WHITE = 250,250,250
rect2 = pygame.rect = (100,100,50,50)
WINDOWWIDTH = 1200
WINDOWHEIGHT = 750
thing = pygame.image.load('car.png')
screen = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT), 0, 32)
pygame.display.set_caption('Teh test')
left = False
right = False
position = (100, 100)
while True:
rect2 = pygame.rect = (100,100,50,50)
if right == True:
degree -= 2
if left == True:
degree += 2
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
if event.type == KEYDOWN:
if event.key == ord('a'):
left = True
if event.key == ord('d'):
right = True
if event.type == KEYUP:
if event.key == ord('a'):
left = False
if event.key == ord('d'):
right = False
pygame.draw.rect(screen,WHITE,rect2)
screen.fill((40, 40, 40))
thing2 = pygame.transform.rotate(thing,degree)
dx = math.cos(math.radians(degree))
dy = math.sin(math.radians(degree))
position = (position[0] + dx, position[1] - dy)
screen.blit(thing2, position)
pygame.display.update()
mainClock.tick(60)
Working example to kabb answer
import pygame, sys
from pygame.locals import *
import math # math library
pygame.init()
mainClock = pygame.time.Clock()
degree = 0
WHITE = 250,250,250
rect2 = pygame.rect = (100,100,50,50)
WINDOWWIDTH = 1200
WINDOWHEIGHT = 750
thing = pygame.image.load('car.png')
screen = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT), 0, 32)
pygame.display.set_caption('Teh test')
left = False
right = False
forward = False
backward = False
thing2_x = 100
thing2_y = 100
speed = 20
while True:
rect2 = pygame.rect = (100,100,50,50)
if right: # don't need == True
degree -= 2
while degree < 0:
degree += 360
elif left: # don't need == True
degree += 2
while degree > 359:
degree -= 360
dx = math.cos(math.radians(degree))
dy = math.sin(math.radians(degree))
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
if event.type == KEYDOWN:
if event.key == K_ESCAPE:
pygame.quit()
sys.exit()
elif event.key == K_a: # use constants K_a
left = True
elif event.key == K_d: # use constants K_d
right = True
elif event.key == K_w: # use constants K_w
forward = True
elif event.key == K_s: # use constants K_s
backward = True
if event.type == KEYUP:
if event.key == K_a: # use constants K_a
left = False
elif event.key == K_d: # use constants K_d
right = False
elif event.key == K_w: # use constants K_w
forward = False
elif event.key == K_s: # use constants K_s
backward = False
if forward:
thing2_y -= int(speed * dx)
thing2_x -= int(speed * dy)
elif backward:
thing2_y += int(speed * dx)
thing2_x += int(speed * dy)
pygame.draw.rect(screen,WHITE,rect2)
screen.fill((40, 40, 40))
thing2 = pygame.transform.rotate(thing,degree)
screen.blit(thing2,(thing2_x,thing2_y))
pygame.display.update()
mainClock.tick(60)

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 ()
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.
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.
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)

Categories

Resources