Character only maintains movement while mouse is moving on screen? - python

My while loops only maintains the movement for the sprite while the cursor is moving inside of the screen. I've tried reorganizing some of the screen.blits and display.update() and display.flip(). I can't seem to figure out why the character stops after a change in one pixel instead of continuing like it I intended.
background_image = 'Terrain_Grass_First.png'
import pygame, sys
from pygame.locals import *
pygame.init()
pygame.display.set_caption('Hans')
screen_width = 600
screen_height = 400
screen = pygame.display.set_mode((screen_width, screen_height),0,32)
pygame.mouse.set_visible(False)
sprite = pygame.image.load('Hans_front_still.png').convert_alpha()
x,y = (0,0)
movex, movey = (0,0)
while True:
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()
if event.key == K_w:
y = -1
elif event.key == K_a:
x = -1
elif event.key == K_s:
y = +1
elif event.key == K_d:
x = +1
elif event.type == KEYUP:
if event.key == K_w:
y = 0
elif event.key == K_a:
x = 0
elif event.key == K_s:
y = 0
elif event.key == K_d:
x = 0
movex += x
movey += y
screen.fill((0,0,0))
screen.blit(sprite,(movex,movey))
pygame.display.flip()

Your loop blocks on pygame.event.get.
You don't schedule any events of your own.
So, you do nothing until the OS has an event (mouse move, redraw, etc.) to give you.
And, even if you fixed that, you're calling movex += x once per event. So, when the OS is throwing a lot of events at you, your sprite will go zipping madly across the screen, but when the events are coming more slowly, it will crawl along. That's almost never what you want.
An easy fix for both problems is to just schedule your own events. For example, with pygame.time.set_timer(), you can make sure you get an event every, say, 250 milliseconds, and you can only move the sprite on those events. For example:
timer_event = pygame.USEREVENT + 1
pygame.time.set_timer(timer_event, 250)
while True:
for event in pygame.event.get():
# ...
elif event.type == timer_event:
movex += x
movey += y
Another alternative is to design your game with a fixed framerate.
A trivial example looks like this:
FRAME_TIME = 50 # 50ms = 20fps
next_frame_time = pygame.time.get_ticks() + FRAMES
while True:
while True:
event = pygame.event.poll()
if event.type == pygame.NOEVENT:
break
elif # ...
pygame.display.flip()
now = pygame.time.get_ticks()
if now < next_frame_time:
pygame.time.wait(next_frame_time - now)
next_frame_time += FRAMES
Now you can just move every 5th frame.
A realistic example has to deal with missed frames, too many events in the queue, choose between wait and delay appropriately, etc.
But I'd go with the event-driven version with a timer instead of a fixed-framerate version in most cases, especially if you're already going down that line.

The only problem is your Indentation!
The fifth and sixth lines from the bottom have wrong indentation, and you need to delete them.
These two lines:
movex += x
movey += y
should be:
movex += x
movey += y
And it works

Related

Continuous object creation in pygame?

Okay, so I've researched this topic a bit. I'm creating a game in Python's Pygame, a replica of the famous "Raiden 2". My game loop is fairly similar to those I've seen around. What I'm trying to do is have the constructor create a bullet object (with my Bullet class) while the space bar is being held. However, the following code only creates a single bullet per keypress. Holding the button does nothing, just creates a single bullet.
while game.play is True:
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
b = Bullet(x, y)
bullet_group.add(b)
bullet_group.draw(screen)
Not sure where to go from here. Any help is welcome and appreciated.
This should work as you expect it:
addBullets = False
while game.play is True:
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
addBullets = True
if event.type == pygame.KEYUP:
if event.key == pygame.K_SPACE:
addBullets = False
if addBullets:
b = Bullet(x, y)
bullet_group.add(b)
bullet_group.draw(screen)
You move the creation of bullets out of the handling of events and set there only a "flag" which is taken back if the key is released stopping creation of bullets.
And ... as mentioned in the comment by jsbueno this will work too:
while game.play is True:
for event in pygame.event.get():
pass # do something with events
if pygame.key.get_pressed()[pygame.K_SPACE]:
b = Bullet(x, y)
bullet_group.add(b)
I think the other answer is lacking an important detail. You most likely don't want to fire a bullet every frame, so you need to have some kind of timer. The simplest way is to count the frames, but then the game would be frame rate bound (better don't do it in this way).
firing = False
bullet_timer = 0
while game.play:
for event in pygame.event.get():
if event.type == pygame.QUIT:
game.play = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
firing = True
elif event.type == pygame.KEYUP:
if event.key == pygame.K_SPACE:
firing = False
if bullet_timer > 0:
bullet_timer -= 1
elif firing: # Timer is less than 0 and we're firing.
bullet = Bullet()
bullet_group.add(bullet)
bullet_timer = 10 # Reset timer to 10 frames.
The frame rate independent variant is to use the time that pygame.Clock.tick returns (the time that has passed since it was called the last time) and subtract it from the timer variable. If the timer is <= 0 we're ready to fire.
clock = pygame.time.Clock()
firing = False
bullet_timer = 0
while game.play:
# `dt` is the passed time since the last tick in seconds.
dt = clock.tick(30) / 1000
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
firing = True
elif event.type == pygame.KEYUP:
if event.key == pygame.K_SPACE:
firing = False
if bullet_timer > 0:
bullet_timer -= dt
elif firing: # Timer is below 0 and we're firing.
bullet = Bullet()
bullet_group.add(bullet)
bullet_timer = .5 # Reset timer to a half second.

pygame moving left and right issue

I have started making something on pygame but I have encountered an issue when moving left or right. if I quickly change from pressing the right arrow key to pressing the left one and also let go of the right one the block just stops moving. this is my code
bg = "sky.jpg"
ms = "ms.png"
import pygame, sys
from pygame.locals import *
x,y = 0,0
movex,movey=0,0
pygame.init()
screen=pygame.display.set_mode((664,385),0,32)
background=pygame.image.load(bg).convert()
mouse_c=pygame.image.load(ms).convert_alpha()
m = 0
pygame.event.pump()
while 1:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
if event.type==KEYDOWN:
if event.key==K_LEFT:
movex =-0.5
m = m + 1
if event.key==K_RIGHT:
movex=+0.5
m = m + 1
elif event.type == KEYUP:
if event.key==K_LEFT and not event.key==K_RIGHT:
movex = 0
if event.key==K_RIGHT and not event.key==K_LEFT:
movex =0
x+=movex
y=200
screen.blit(background, (0,0))
screen.blit(mouse_c,(x,y))
pygame.display.update()
is there a way I can change this so if the right arrow key is pressed and the left arrow key is released that it will go right instead of stopping?
P.S
I am still learning pygame and am very new to the module. I'm sorry if this seems like a stupid question but i couldn't find any answers to it.
Your problem is that when you test the KEYDOWN events with
if event.key==K_LEFT and not event.key==K_RIGHT:
you always get True, because when event.key==K_LEFT is True,
it also always is not event.key==K_RIGHT (because the key of the event is K_LEFT after all).
My approach to this kind of problem is to separate
the intent from the action. So, for the key
events, I would simply keep track of what action
is supposed to happen, like this:
moveLeft = False
moveRight = False
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
if event.type == KEYDOWN:
if event.key == K_LEFT: moveLeft = True
if event.key == K_RIGHT: moveRight = True
elif event.type == KEYUP:
if event.key == K_LEFT: moveLeft = False
if event.key == K_RIGHT: moveRight = False
Then, in the "main" part of the loop, you can
take action based on the input, such as:
while True:
for event in pygame.event.get():
...
if moveLeft : x -= 0.5
if moveRight : x += 0.5
the problem is that you have overlapping key features; If you hold down first right and then left xmove is first set to 1 and then changes to -1. But then you release one of the keys and it resets xmove to 0 even though you are still holding the other key. What you want to do is create booleans for each key. Here is an example:
demo.py:
import pygame
window = pygame.display.set_mode((800, 600))
rightPressed = False
leftPressed = False
white = 255, 255, 255
black = 0, 0, 0
x = 250
xmove = 0
while True:
window.fill(white)
pygame.draw.rect(window, black, (x, 300, 100, 100))
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_RIGHT:
rightPressed = True
if event.key == pygame.K_LEFT:
leftPressed = True
if event.type == pygame.KEYUP:
if event.key == pygame.K_RIGHT:
rightPressed = False
if event.key == pygame.K_LEFT:
leftPressed = False
xmove = 0
if rightPressed:
xmove = 1
if leftPressed:
xmove = -1
x += xmove
pygame.display.flip()
One way could be to create a queue that keeps track of the button that was pressed last. If we press the right arrow key we'll put the velocity first in the list, and if we then press the left arrow key we put the new velocity first in the list. So the button that was pressed last will always be first in the list. Then we just remove the button from the list when we release it.
import pygame
pygame.init()
screen = pygame.display.set_mode((720, 480))
clock = pygame.time.Clock()
FPS = 30
rect = pygame.Rect((350, 220), (32, 32)) # Often used to track the position of an object in pygame.
image = pygame.Surface((32, 32)) # Images are Surfaces, so here I create an 'image' from scratch since I don't have your image.
image.fill(pygame.Color('white')) # I fill the image with a white color.
velocity = [0, 0] # This is the current velocity.
speed = 200 # This is the speed the player will move in (pixels per second).
dx = [] # This will be our queue. It'll keep track of the horizontal movement.
while True:
dt = clock.tick(FPS) / 1000.0 # This will give me the time in seconds between each loop.
for event in pygame.event.get():
if event.type == pygame.QUIT:
raise SystemExit
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
dx.insert(0, -speed)
elif event.key == pygame.K_RIGHT:
dx.insert(0, speed)
elif event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT:
dx.remove(-speed)
elif event.key == pygame.K_RIGHT:
dx.remove(speed)
if dx: # If there are elements in the list.
rect.x += dx[0] * dt
screen.fill((0, 0, 0))
screen.blit(image, rect)
pygame.display.update()
# print dx # Uncomment to see what's happening.
You should of course put everything in neat functions and maybe create a Player class.
I know my answer is pretty late but im new to Pygame to and for beginner like me doing code like some previous answer is easy to understand but i have a solution to.I didn`t use the keydown line code, instead i just put the moving event code nested in the main game while loop, im bad at english so i give you guy an example code.
enter code here
while run:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT or event.type == pygame.K_ESCAPE:
run = False
win.blit(bg, (0, 0))
pressed = pygame.key.get_pressed()
if pressed[pygame.K_LEFT]:
x -= 5
if pressed[pygame.K_RIGHT]:
x += 5
if pressed[pygame.K_UP]:
y -= 5
if pressed[pygame.K_DOWN]:
y += 5
win.blit(image,(x,y))
pygame.display.update()
pygame.quit()
This will make the image move rapidly without repeating pushing the key, at long the code just in the main while loop with out inside any other loop.

How do I make a game object move continuously as long as the key is pressed?

I am trying to make a game object (here, the welcome text) move as long as the key is pressed on the keyboard. But in this code of mine,
import pygame , sys
from pygame.locals import *
pygame.init()
WHITE = (255 , 255 , 255)
RED = (255 , 0 , 0)
DISPLAYSURF = pygame.display.set_mode((800 , 400))
pygame.display.set_caption('Welcome Tanks')
#render(text, antialias, color, background=None)
fontObj = pygame.font.SysFont('serif' , 40)
text = fontObj.render('Welcome Folks' , True , RED )
x = 150
y = 29
while True:
DISPLAYSURF.fill(WHITE)
DISPLAYSURF.blit(text ,(x , y))
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit(0)
elif event.type == KEYDOWN or event.type == KEYUP:
if event.key == K_ESCAPE:
pygame.quit()
sys.exit(0)
elif event.key == K_DOWN:
y += 15
elif event.key == K_UP:
y -= 15
elif event.key == K_RIGHT:
x += 14
elif event.key == K_LEFT:
x -= 15
else:
x = 150
y = 29
pygame.display.update()
The object moves only once, even though the key is continuously pressed for a long time. In other words, the object changes its position only once when the keyboard button is pressed. I want it to move continuously while I hold the key.
Which event should I look for instead of event.KEYDOWN?
I suggest you to use the key.get_pressed(), e.g.
while True:
DISPLAYSURF.fill(WHITE)
DISPLAYSURF.blit(text ,(x , y))
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit(0)
elif event.type == KEYDOWN or event.type == KEYUP:
if event.key == K_ESCAPE:
pygame.quit()
sys.exit(0)
if pygame.key.get_pressed()[K_LEFT]:
x -= 15
if pygame.key.get_pressed()[K_RIGHT]:
x += 14
if pygame.key.get_pressed()[K_UP]:
y -= 15
if pygame.key.get_pressed()[K_DOWN]:
y += 15
pygame.display.update()
pygame.key.get_pressed()
Returns a sequence of boolean values representing the state of every
key on the keyboard. Use the key constant values to index the array. A
True value means the that button is pressed.
Getting the list of pushed buttons with this function is not the
proper way to handle text entry from the user. You have no way to know
the order of keys pressed, and rapidly pushed keys can be completely
unnoticed between two calls to pygame.key.get_pressed(). There is also
no way to translate these pushed keys into a fully translated
character value. See the pygame.KEYDOWN events on the event queue for
this functionality.
Also you can take a look at doc
keyState = pygame.key.get_pressed()
Declare that, and then you use keystate:
if KeyState()[K_DOWN]:
y += 15
You could try:
if key.get_pressed()
down = True
while down = True:
y+= 15
Then get FPS clock so it does not just flow over the screen!

Python-Pygame always crashing and Not Responding when running a module in IDLE

I'm quite new to Pygame or even Python, but i know that when something in the isn't right, it displays some text in the Python Shell telling you that there was some error. I've actually encountered many of them and this time, it finally runs and displays the window, but it does not respond. I know there might be some mistakes in my whole code so please feel free to correct me (and please, kindly explain since I'm still new to this stuff).
The code is below, but if it can help, if you'd ask for it, i'll see if i could post the file as well. Anyway, here's the codes:
#import Modules
import os, sys
import pygame
from pygame.locals import *
background_img="C:/Users/JM/Documents/Python/Pygame_Alpha/background_img.jpg"
cursor_img="C:/Users/JM/Documents/Python/Pygame_Alpha/pygameCursor.png"
def load_image(img_file, colorkey=None):
file_pathname = os.path.join("\Users\JM\Documents\Python\Pygame_Alpha",img_file)
try:
image = pygame.image.load(file_pathname).convert_alpha()
except pygame.error, message:
print "Can't load image:", file_pathname
raise SystemExit, message
image = image.convert()
if colorkey is not None:
if colorkey is -1:
colorkey = image.get_at((0,0))
image.set_colorkey(colorkey, RLEACCEL)
return image, image.get_rect()
#Main character's position and movements
char_x,char_y = 0,0
char_go_x,char_go_y = 0,0
#Main char class
class char(pygame.sprite.Sprite):
"""Main Character"""
def __init__(self):
pygame.sprite.Sprite.__init__(self)#call Sprite initializer
self.image, self.rect = load_image("char_img.png", -1)
self.jumping = 0
def update(self):
self.rect.midtop = char_x,char_y
if self.jumping == 1:
self.rect.move_ip(-35,-3)
def char_no_jump(self):
self.jumping = 0
pygame.init()
pygame.display.set_caption("pygame_Alpha")
screen = pygame.display.set_mode((800,480),0,32)
background = pygame.image.load(background_img).convert()
cursor = pygame.image.load(cursor_img).convert_alpha()
char = char()
clock = pygame.time.Clock()
millisec = clock.tick()
sec = millisec/1000.0
char_fall = sec*25
jump = sec*50
#blit the background
screen.blit(background,(0,0))
#Main Loop
while 1:
#Tell pygame not to exceed 60 FPS
clock.tick(60)
#Events
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
#Events triggered when a key/s is/are pressed
if event.type == KEYDOWN:
if event.key == K_ESCAPE:
pygame.quit()
sys.exit()
elif event.key == K_UP or event.key == K_w:
char.jumping = 1
elif event.key == K_DOWN or event.key == K_s:
char_go_y += 1
elif event.key == K_LEFT or event.key == K_a:
char_go_x -= 0.5
elif event.key == K_RIGHT or event.key == K_d:
char_go_x += 0.75
if char_x > 800:
char_x = 0
#Events triggered when a key/s is/are released
if event.type == KEYUP:
if event.key == K_UP or event.key == K_w:
char_go_y += 1
elif event.key == K_DOWN or event.key == K_s:
char_go_y = 0
elif event.key == K_LEFT or event.key == K_a:
char_go_x = 0
if char_x < 0:
char_x = 0
elif event.key == K_RIGHT or event.key == K_d:
char_go_x = 0
if char_x > 700:
char_x = 0
char.update()
while char_y < 200:
char_go_y += char_fall
if char_y > 200:
char_y = 200
#Update values of position of Main Char
char_x += char_go_x
char_y += char_go_y
#Position Variables of Cursor Image, setting its values equal to cursor pos, and blit it to screen
cursor_x,cursor_y = pygame.mouse.get_pos()
cursor_x -= cursor.get_width()/2
cursor_y -= cursor.get_height()/2
screen.blit(cursor,(cursor_x,cursor_y))
pygame.display.update()
Hmm...
while char_y < 200:
char_go_y += char_fall
Unless you have some interesting aliasing I'm not seeing, if char_y < 200 (which it should be at start, it will always be since you're updating char_go_y.
If that's not the issue, would still suggest adding some prints to figure out if it's getting through the loop or not.
is there any error message in idle when you run it? whenever the screen freezes you have something wrong, but its hard to pinpoint what without knowing the error messages. maybe it is trouble opening the picture, you should try putting .convert() at the end of your picture file name, but that is just a guess.
Calling pygame.quit and sys.exit are probably causing issues. Normally you'd never need them in pygame.
Instead of:
#Main Loop
while 1:
#Tell pygame not to exceed 60 FPS
clock.tick(60)
#Events
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
Do this
#Main Loop
done = False
while not done:
clock.tick(60)
for event in pygame.event.get():
if event.type == QUIT:
done = True
if event.type == KEYDOWN:
if event.key == K_ESC:
done = True

How to create walking character using multiple images from sprite sheet

I want to create the "illusion" so to speak that my character is walking, using multiple images from a sheet of multiple sprite positions. I only know how to move the single image using WASD. Here is my code so far:
room_bg = 'woodf.jpg'#wood floor background
screen = pygame.display.set_mode((640,360),0,32)
background = pygame.image.load(room_bg).convert()#background here
x,y = 290,150
movex, movey = 0,0
while 1:#blitting background to middle of screen, start of main game loop
screen.blit(background, (170,100))
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
if event.type == KEYDOWN:
if event.key == K_a:
movex = -1
pygame.image.load('s_left1.png')
pygame.Surface.blit(mc_left1)
elif event.key == K_d:
movex = +1
elif event.key == K_w:
movey = -1
elif event.key == K_s:
movey = +1
if event.type == KEYUP:
if event.key == K_a:
movex = 0
elif event.key == K_d:
movex = 0
elif event.key == K_w:
movey = 0
elif event.key == K_s:
movey = 0
x+= movex
y+= movey
mc = pygame.image.load('ss.png').convert()
mc.set_colorkey((0,0,0))
screen.blit(mc,(x,y))
pygame.display.update()
You first want to extract individual sprites from the sprite sheet, then you want to use, for example, an iterator for serving them to the drawing method in each call.
Here you have a tutorial on how to get individual images from the sprite sheet and how to use them for animation.
I doubt this is the most efficient way of animating a sprite, but it's been working for me so far.
First I load all the sprite frames into a list called spritesheet. Then each time a move event is triggered, I iterate through each frame, updating the display between each iteration. I also introduced a small time delay to make it look more fluid. Again, probably not the best way to do it, but it's a way.
for spriteframe in spritesheet:
x_add = x/len(spritesheet)
y_add = y/len(spritesheet)
player.setPosition( player.getX() + x_add, player.getY() + y_add )
updateBackground(current_map)
pygame.time.delay(40)
updateCharacter(player,spriteframe, image)
pygame.display.update()

Categories