Pygame - event.pos not working in def main() - python

I've read some similar questions but couldn't understand so just gonna ask here...
import pygame as pg
from pygame import *
import sys, os
pg.init()
current_path = os.path.dirname(__file__)
image_path = os.path.join(current_path, "images")
screen = pg.display.set_mode((1920, 1080))
class token(pg.sprite.Sprite):
def __init__(self, path, x, y):
super().__init__()
self.image = pg.image.load(path)
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
self.click = False
token_group.add(self)
def offset(self):
self.offset_x = event.pos[0] - self.rect.x
self.offset_y = event.pos[1] - self.rect.y
def drag(self):
self.rect.x = event.pos[0] - self.offset_x
self.rect.y = event.pos[1] - self.offset_y
token_group = pg.sprite.Group()
token1 = token("images/token1.png", 1920/2, 1080/2)
def main():
running = True
while running:
for event in pg.event.get():
if event.type == QUIT:
pg.quit()
sys.exit()
elif event.type == KEYDOWN:
if event.key == K_ESCAPE:
running = False
elif event.type == MOUSEBUTTONDOWN:
if event.button == 1:
for x in token_group:
if x.rect.collidepoint(event.pos):
x.click = True
x.offset()
elif event.type == MOUSEMOTION:
for x in token_group:
if x.click:
x.drag()
elif event.type == MOUSEBUTTONUP:
for x in token_group:
x.click = False
screen.fill((255, 255, 255))
token_group.draw(screen)
pg.display.update()
main()
If I don't put it in the main(), it works fine but this one has the error below.
File "C:\Users\zsa77\OneDrive\desktop\For_Python\project\ggggg.py", line 63, in <module>
main()
File "C:\Users\zsa77\OneDrive\desktop\For_Python\project\ggggg.py", line 47, in main
x.offset()
File "C:\Users\zsa77\OneDrive\desktop\For_Python\project\ggggg.py", line 21, in offset
self.offset_x = event.pos[0] - self.rect.x
AttributeError: module 'pygame.event' has no attribute 'pos'
I'm doing this to make main() start when clicking the start button in the main menu. But if I make two def(main menu(), main()) and put main() in main menu(), the error occurs. The main menu() which is not written here didn't have a problem of event.pos, but main() did. The error says the problem is event.pos of class token, but I can't find a way to solve this. How should I do about this?

You need to pass the event object to the methods. Add an event parameter to the methods:
class token(pg.sprite.Sprite):
def __init__(self, path, x, y):
# [...]
def offset(self, event):
self.offset_x = event.pos[0] - self.rect.x
self.offset_y = event.pos[1] - self.rect.y
def drag(self, event):
self.rect.x = event.pos[0] - self.offset_x
self.rect.y = event.pos[1] - self.offset_y
Add the event argument when calling the methods:
def main():
running = True
while running:
for event in pg.event.get():
if event.type == QUIT:
# [...]
elif event.type == KEYDOWN:
# [...]
elif event.type == MOUSEBUTTONDOWN:
if event.button == 1:
for x in token_group:
if x.rect.collidepoint(event.pos):
x.click = True
x.offset(event) # <---
elif event.type == MOUSEMOTION:
for x in token_group:
if x.click:
x.drag(event) # <---
elif event.type == MOUSEBUTTONUP:
# [...]

Related

pygame.error: display Surface quit after filling the surface black

After I paint my surface black in pygame. I get the error
pygame.error: display Surface quit.
Full error:
>
D:\Programme\Anaconda3\envs\gameDev\python.exe "C:/Users/xxx/PycharmProjects/Workspace/pygame snake/main.py"
pygame 1.9.6
Hello from the pygame community. https://www.pygame.org/contribute.html
Traceback (most recent call last):
File "C:/Users/xxx/PycharmProjects/Workspace/pygame snake/main.py", line 81, in <module>
thegame.execute()
File "C:/Users/xxx/PycharmProjects/Workspace/pygame snake/main.py", line 74, in execute
self.render(self._display_surf)
File "C:/Users/xxx/PycharmProjects/Workspace/pygame snake/main.py", line 41, in render
_display_surf.fill((0,0,0))
pygame.error: display Surface quit
<Surface(Dead Display)>
I tried instead of:
_display_surf.fill((0,0,0))
using:
_display_surf.fill(pygame.color("black"))
But that didnt work either.
Here is my full source code:
import pygame
from pygame.locals import *
class Player(object):
x = 10
y = 10
speed = 1
def moveRight(self):
self.x = self.x + self.speed
def moveLeft(self):
self.x = self.x - self.speed
def moveUp(self):
self.y = self.y - self.speed
def moveDown(self):
self.y = self.y + self.speed
class game:
def __init__(self):
self.resolution = (800, 500)
self._running = True
self._display_surf = None
self.player = Player()
def on_init(self):
pygame.init()
self._display_surf = pygame.display.set_mode(self.resolution)
pygame.display.set_caption("Snake!")
self._running = True
def on_cleanup(self):
pygame.quit()
def render(self, _display_surf):
print(_display_surf)
_display_surf.fill((0,0,0))
pygame.draw.rect(self._display_surf, (0, 128, 255), pygame.Rect(self.player.x, self.player.y, 30, 30))
pygame.display.flip()
def loop(self):
pass
def on_event(self, event):
if event.type == pygame.quit():
print("quiet")
self._running = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_RIGHT:
self.player.moveRight()
elif event.key == pygame.K_LEFT:
self.player.moveLeft()
elif event.key == pygame.K_UP:
self.player.moveUp()
elif event.key == pygame.K_DOWN:
self.player.moveDown()
def execute(self):
if self.on_init() == False:
self._running = False
while self._running:
for event in pygame.event.get():
self.on_event(event)
self.render(self._display_surf)
self.loop()
self.on_cleanup()
if __name__ == "__main__":
thegame = game()
thegame.execute()
I expect that I have a black surface and nothing happens. But instead, it crashes when I try to paint it black. Hope somebody can help
Solution:
For anybody who is intrested in
instead of
if event.type == pygame.quit():
print("quiet")
self._running = False
i need to to
if event.type == pygame.QUIT:
print("quiet")
self._running = False
The code
if event.type == pygame.quit():
print("quiet")
doesn't do what you expect it to do. pygame.quit() is a function call and uninitializes all pygame modules. The function returns None and so the condition fails. The code runs through and crashes at the next instruction which tries to access a pygame module.
You've to compare event.type to the event enumerator constant pygame.QUIT, which identifies the quit event instead:
if event.type == pygame.QUIT:
print("quiet")
self._running = False
See the documentation of pygame.event.

How to make multiple Instances from a class move at the same time in gyame

import pygame, os, sys
from pygame import *
pygame.init()
RED = ( 255, 0, 0)
class WPawn():
def __init__(self, x, y):
self.x = x
self.y = y
self.image = pygame.transform.scale(pygame.image.load('wpawn.png'), (100,100))
self.move_x = 0
self.move_y = 0
def event_handler(self):
for event in pygame.event.get():
if event.type == KEYDOWN:
if event.key == K_UP:
self.move_y = -100
if event.key == K_DOWN:
self.move_y = 100
elif event.type == KEYUP:
if event.key in (K_UP, K_DOWN):
self.move_y = 0
def update(self, screen):
self.y = self.y + self.move_y
def draw(self, screen):
screen.blit(self.image, (self.x, self.y))
class Game():
def __init__(self):
screen_width = 900
screen_height = 900
self.screen = pygame.display.set_mode((screen_width,screen_height))
pygame.display.set_caption ("Chess Project")
self.pawn1 = WPawn(50,650)
self.pawn2 = WPawn(150,650)
self.pawn3 = WPawn(250,650)
self.pawn4 = WPawn(350,650)
self.pawn5 = WPawn(450,650)
self.pawn6 = WPawn(550,650)
self.pawn7 = WPawn(650,650)
self.pawn8 = WPawn(750,650)
def play(self):
clock = pygame.time.Clock()
RUNNING = True
while RUNNING:
for event in pygame.event.get():
if event.type == pygame.QUIT:
RUNNING = False
clock.tick(30)
self.pawn1.event_handler()
self.pawn2.event_handler()
self.pawn3.event_handler()
self.pawn4.event_handler()
self.pawn5.event_handler()
self.pawn6.event_handler()
self.pawn7.event_handler()
self.pawn8.event_handler()
self.pawn1.update(self.screen)
self.pawn2.update(self.screen)
self.pawn3.update(self.screen)
self.pawn4.update(self.screen)
self.pawn5.update(self.screen)
self.pawn6.update(self.screen)
self.pawn7.update(self.screen)
self.pawn8.update(self.screen)
self.screen.fill(RED)
self.pawn1.draw(self.screen)
self.pawn2.draw(self.screen)
self.pawn3.draw(self.screen)
self.pawn4.draw(self.screen)
self.pawn5.draw(self.screen)
self.pawn6.draw(self.screen)
self.pawn7.draw(self.screen)
self.pawn8.draw(self.screen)
pygame.display.update()
Game().play()
pygame.quit()
The KEY_UP event (or whatever) is consumed when you process it. So whichever WPawn class gets the event first will move.
Generally an event-driven program has only one event loop.
It may be easier to make this work by handling the event processing outside of the game objects. Have the single event loop handle record the key press, then move each WPawn that you wish to be moved.
Perhaps something like:
event = pygame.event.get()
if event.type == K_DOWN:
foreach pawn in all_pawns:
pawn.moveDown()
elif event.type == K_UP:
foreach pawn in all_pawns:
pawn.moveUp()

How do you move a sprite up and down?

I've been at it for a while, and I cannot seem to figure out why my sprite is not moving up or down when the program is run.
Player Sprite Class
def __init__(self,name,x,y):
pygame.sprite.Sprite.__init__(self)
self.name = str(name)
self.speed = 5
self.image = pygame.image.load(name+'.png').convert_alpha()
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
def move_up(self):
self.rect.y -= self.speed
def move_down(self):
self.rect.y += self.speed
def move_left(self):
self.rect.x -= self.speed
def move_right(self):
self.rect.x += self.speed
def update(self):
self.screen.blit(self.image,(self.rect))
Main File / Loop
class Console:
def __init__(self,width,height):
pygame.init()
self.w = width
self.h = height
self.clock = pygame.time.Clock()
self.screen = pygame.display.set_mode((self.w,self.h))
self.screenName = pygame.display.set_caption("Star's Labyrinth")
class Background(pygame.sprite.Sprite):
def __init__(self,image_file,x,y):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load(image_file)
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
def main():
gameExit = False
game_display = Console(1024,576)
game_display.screen
starboy = Player("starboy",200,200)
background = Background("background.png",0,0)
while not gameExit:
for event in pygame.event.get():
if event.type == pygame.QUIT:
gameExit = True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_a:
starboy.move_left()
elif event.key == pygame.K_d:
starboy.move_right()
elif event.type == pygame.K_w:
starboy.move_up()
elif event.type == pygame.K_s:
starboy.move_down()
print(pygame.event.get())
game_display.screen.blit(background.image,background.rect)
starboy.update
game_display.screen.blit(starboy.image,(starboy.rect.x,starboy.rect.y))
pygame.display.update()
game_display.clock.tick(30)
I have tried different types of commands trying to figure out whether it's a variable or function problem. Also is there a way I can make it move without having to tap the key.
In the event loop you're checking if the event.type is pygame.K_w or pygame.K_s, but you have to check if the event.key is equal to these constants. Change
elif event.type == pygame.K_w:
starboy.move_up()
elif event.type == pygame.K_s:
starboy.move_down()
to:
elif event.key == pygame.K_w:
starboy.move_up()
elif event.key == pygame.K_s:
starboy.move_down()
You also forgot the parentheses behind starboy.update.

How to get coordinates of image in pygame

I just started learning Pygame and I'm doing a little game (school project), where using mouse I can click on the image and drag it. There are a lot of images, so my question is how I can identify what image is chosen. Thank you!
Here are some code:
def Transformation(element):
element = pygame.transform.scale(element,(50,75))
fire = pygame.image.load("ElementIcon/fire.png").convert_alpha()
Transformation(fire)
fire.set_colorkey(BLACK)
fire_rect = fire.get_rect()
earth = pygame.image.load("ElementIcon/earth.png").convert_alpha()
Transformation(earth)
earth.set_colorkey(BLACK)
earth_rect = earth.get_rect()
while not done:
screen.fill(WHITE)
#Update the screen with drawings
screen.blit(fire,(408,450))
screen.blit(earth,(419, 350))
mouse_pos = pygame.mouse.get_pos()
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
print("User quits the game :(")
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
done = True
print("Game stopped early by user :( ")
if event.type == pygame.MOUSEBUTTONDOWN:
print mouse_pos
print fire_rect
if fire_rect.collidepoint(mouse_pos):
print "over fire"
if earth_rect.collidepoint(mouse_pos):
print "mama"
When I try to print fire_rect I get <0,0,62,75>
Have a play with this code:
import pygame
from pygame.locals import *
pygame.init()
screen = pygame.display.set_mode((600,600))
clock = pygame.time.Clock()
FPS = 60
class MovableImage(pygame.Surface):
def __init__(self, image, xpos=0, ypos=0):
self.image = image
self.xpos = xpos
self.ypos = ypos
self.width = image.get_width()
self.height = image.get_height()
self.selected = False
self.rect = pygame.Rect(xpos, ypos, image.get_width(), image.get_height())
def move(self, move):
self.xpos += move[0]
self.ypos += move[1]
self.rect = pygame.Rect(self.xpos, self.ypos, self.width, self.height)
def Transformation(element):
element = pygame.transform.scale(element,(50,75))
def init():
global ImageList
fire = pygame.Surface((50,50))
fire.fill((255,0,0))
#fire = pygame.image.load("ElementIcon/fire.png").convert_alpha()
#Transformation(fire)
#fire.set_colorkey(BLACK)
#fire_rect = fire.get_rect()
earth = pygame.Surface((50,50))
earth.fill((255,255,0))
#earth = pygame.image.load("ElementIcon/earth.png").convert_alpha()
#Transformation(earth)
#earth.set_colorkey(BLACK)
#earth_rect = earth.get_rect()
fire_obj = MovableImage(fire, 408, 450)
earth_obj = MovableImage(earth, 419,350)
ImageList =[]
ImageList.append(fire_obj)
ImageList.append(earth_obj)
def run():
global done
done = False
while not done:
check_events()
update()
clock.tick(60)
def check_events():
global done
global ImageList
mouse_pos = pygame.mouse.get_pos()
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
print("User quits the game :(")
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
done = True
print("Game stopped early by user :( ")
if event.type == pygame.MOUSEBUTTONDOWN:
for im in ImageList:
if im.rect.collidepoint(mouse_pos):
im.selected = not im.selected
if event.type == pygame.MOUSEBUTTONUP:
for im in ImageList:
if im.rect.collidepoint(mouse_pos):
im.selected = False
if event.type == pygame.MOUSEMOTION:
for im in ImageList:
if im.rect.collidepoint(mouse_pos) and im.selected:
xmv = event.rel[0]
ymv = event.rel[1]
if event.buttons[0]:
if xmv < 0:
if im.xpos > 0:
im.move((xmv,0))
elif event.rel[0] > 0:
if im.xpos < screen.get_width():
im.move((xmv,0))
elif event.rel[1] < 0:
if im.ypos > 0:
im.move((0,ymv))
elif event.rel[1] > 0:
if im.ypos < screen.get_height():
im.move((0,ymv))
def update():
global ImageList
screen.fill((255, 255, 255)) #WHITE)
#Update the screen with drawings
for im in ImageList:
screen.blit(im.image, (im.xpos, im.ypos))
pygame.display.update()
if __name__=="__main__":
init()
run()
You can get the mouse pos and the image rect and check for collision:
pos = pygame.mouse.get_pos()
if image.rect.collidepoint(pos)
# move it
If you want to move the image with the mouse you can get the relative x/y movement with pygame.mouse.get_rel() and use that to change the image location.

pygame sprite not moving

I'm faced with a logic error where the sprite simply doesn't move regardless of input.
My code will be below so no context is left out, it's fairly short.
Is there a better way of moving the sprite apart from the blit?
I've seen somewhere stuff about updating the sprite or some such, done quite differently to simply blitting it.
import pygame
pygame.init()
import random
import math
screen=pygame.display.set_mode([700,400])
black = ( 0, 0, 0)
white = ( 255, 255, 255)
red = ( 255, 0, 0)
player_x=350
player_y=200
player_x_vel=0
player_y_vel=0
rot_player=pygame.image
pi=math.pi
class Player(pygame.sprite.Sprite):
def __init__(self):
global player
pygame.sprite.Sprite.__init__(self)
self.pos=(350,200)
self.image=pygame.image.load("arrowtest.png").convert()
self.rect=self.image.get_rect()
screen=pygame.display.get_surface()
self.area=screen.get_rect()
self.speed=10
self.state="still"
self.reinit()
def reinit(self):
self.state="still"
self.movepos=[0,0]
def update(self):
newpos=self.rect.move(self.movepos)
if self.area.contains(newpos):
self.rect=newpos
pygame.event.pump()
def moveup(self):
self.movepos[1]-=(self.speed)
self.state="moveup"
def movedown(self):
self.movepos[1]+=(self.speed)
self.state="movedown"
def moveleft(self):
self.movepos[0]-=(self.speed)
self.state="moveleft"
def moveright(self):
self.movepos[0]+=(self.speed)
self.state="moveright"
def moveupright(self):
self.movepos[1]-=(self.speed)
self.movepos[0]+=(self.speed)
def moveupleft(self):
self.movepos[1]-=(self.speed)
self.movepos[0]-=(self.speed)
def movedownright(self):
self.movepos[1]+=(self.speed)
self.movepos[0]+=(self.speed)
def movedownleft(self):
self.movepos[1]+=(self.speed)
self.movepos[0]-=(self.speed)
def angleplayer(self):
mouse_pos=pygame.mouse.get_pos()
dx=mouse_pos[0]-player_x
dy=mouse_pos[1]-player_y
rads=math.atan2(-dy, dx)
rads %= 2*pi
angle = math.degrees(rads)
print angle
rot_player.image=pygame.transform.rotate(player.image, angle-90)
done=False
clock=pygame.time.Clock()
while done==False:
player = Player()
for event in pygame.event.get():
if event.type == pygame.QUIT:
done=True
if event.type == pygame.MOUSEBUTTONDOWN:
fired_pos=pygame.mouse.get_pos()
fired=True
if event.type == pygame.KEYDOWN:
player.angleplayer()
if event.key == pygame.K_w:
player.moveup()
if event.key == pygame.K_s:
player.movedown()
if event.key == pygame.K_a:
player.moveleft()
if event.key == pygame.K_d:
player.moveright()
print "co ords", player_x,player_y
print "x vel", player_x_vel
print "y vel", player_y_vel
if event.type == pygame.KEYUP:
player.movepos=[0,0]
player.state="still"
player.angleplayer()
screen.fill(white)
screen.blit(player.image, player.pos)
clock.tick(20)
pygame.display.flip()
pygame.quit()
Thanks in advance
First of all, you are creating a new player every iteration of your main loop:
...
while done == False:
player = Player()
...
You want to create the player once, so move the creation outside the loop:
...
player = Player()
while not done:
...
Second: To get the position of the player, you use player.pos:
...
screen.blit(player.image, player.pos)
...
but you never update player.pos (it's always (350,200)), you only change self.rect:
def update(self):
newpos=self.rect.move(self.movepos)
if self.area.contains(newpos):
self.rect=newpos
pygame.event.pump()
either use player.rect to get the player position, or update player.pos accordingly:
def update(self):
newpos=self.rect.move(self.movepos)
if self.area.contains(newpos):
self.rect = newpos
self.pos = self.rect.topleft
# don't call pygame.event.pump() here. Doesn't make any sense :-)
Third, you update the player position in the update function, but you never call it. Call it before drawing the player:
...
while not done:
...
player.update()
screen.fill(white)
screen.blit(player.image, player.pos)
...
You can simplify your code alot by setting movepos directly and removing the move... functions.
working example:
import pygame
pygame.init()
colors = pygame.color.THECOLORS
screen = pygame.display.set_mode([700,400])
class Player(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.surface.Surface((32,32))
self.image.fill(colors['green'])
self.rect = self.image.get_rect().move(350, 200)
self.speed = 4
def update(self):
dx, dy = self.movepos[0] * self.speed, self.movepos[1] * self.speed
self.rect = self.rect.move(dx, dy)
done=False
clock = pygame.time.Clock()
player = Player()
while not done:
if pygame.event.get(pygame.QUIT):
break
pressed = pygame.key.get_pressed()
l, r, u, d = [pressed[k] for k in pygame.K_a, pygame.K_d, pygame.K_w, pygame.K_s]
player.movepos = -l + r, -u + d
player.update()
screen.fill(colors['white'])
screen.blit(player.image, player.rect.topleft)
pygame.display.flip()
clock.tick(60)
You have a lot of move functions. Try combining them into a simple two function class like this example:
class Puck(pygame.sprite.Sprite):
def __init__(self, image_file, speed, location):
pygame.sprite.Sprite.__init__(self) #call Sprite initializer
self.image = pygame.image.load(image_file)
self.rect = self.image.get_rect()
self.rect.left, self.rect.top = location
The two main controllers are the self.rect.left and self.rect.top. By changing their values, you can move the sprites like in this example.
#Name of varible# = Puck('#Image File#', [#value of self.rect.left#, value of self.rect.top]
Then you can use events to change them like:
for event in pygame.event.get():
if event.type==pygame.QUIT:
pygame.quit()
exit(0)
elif event.type == pygame.KEYDOWN:
if event.key == K_UP:
random.rect.top =random.rect.top - 75
elif event.key == K_LEFT:
random.rect.left = random.rect.left - 75
elif event.key == K_DOWN:
random.rect.top = random.rect.top + 75
elif event.key == K_RIGHT:
randoml.rect.left = randoml.rect.left + 75
elif event.key == K_w:
random.rect.top = random.rect.top - 50
elif event.key == K_a:
random.rect.left = random.rect.left - 50
elif event.key == K_s:
random.rect.top = random.rect.top + 50
elif event.key == K_d:
random.rect.left = random.rect.left + 50
This should be able to move your sprite.

Categories

Resources