AttributeError: 'Event' object has no attribute 'mouse_pos' - events

I simply want to save the mouse position at every instant. Why is this simple code not working?
import pygame
screen = pygame.display.set_mode((500,500))
screen.fill((255,255,255))
while True:
ev = pygame.event.get()
for event in ev:
pos = pygame.mouse.get_pos()
if event.type != pygame.NOEVENT:
mouse_pos = pygame.mouse.get_pos()
x, y = event.mouse_pos
print(x, y)

The mouse position can be tracked outside of the event processing loop.
import pygame
import sys
screen = pygame.display.set_mode((500,500))
screen.fill((255,255,255))
last_pos = (-1,-1)
while True:
# handle user events
ev = pygame.event.get()
for event in ev:
if event.type == pygame.QUIT:
sys.exit()
# track the mouse co-ords
mouse_pos = pygame.mouse.get_pos()
if ( mouse_pos != last_pos ):
x,y = mouse_pos
print(x, y)
last_pos = mouse_pos

Related

How to add random number of falling balls in pygame?

Here is some code for random falling balls, I am able to generate one falling ball. Having hard time to randomize the number of falling balls, also they need to be some random delays falling from "sky". Could you tell how to do it ?
import pygame
import random
pygame.init()
width, height = 640, 480
screen = pygame.display.set_mode((width, height))
robot = pygame.image.load("robot.png")
y1 = 0
y2 = 0
speed1 = 1
speed2 = 2
clock = pygame.time.Clock()
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
exit()
screen.fill((0, 0, 0))
robots = []
screen.blit(robot, (100, y1))
y1 += speed1
if y1 >= 640:
y1 = 0
pygame.display.flip()
clock.tick(60)
Maybe this is the best solution for your problem. I did a list with position (x, y) and then I used this values in for loop.
Here is code example:
balls_num = 100
robots = [[random.randint(0, width), random.randint(-600, 0)] for _ in range(balls_num)]
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
exit()
screen.fill((0, 0, 0))
for pos in robots:
screen.blit(robot, (pos[0], pos[1]))
pos[1] += speed1
if pos[1] >= 640:
pos[1] = -100
I hope it will help you, Adam

Pygame text not going away

So I have been working on a game and for some odd reason down in the level1 function I thought if I had a while loop with leveltext1 = false then I could write the text onto the screen, and then wait 2 seconds and then make level1text = true and it would go away. I guess it didnt...
Code:
#!/usr/bin/python
import pygame
import time
pygame.init()
blue = (25,25,112)
black = (0,0,0)
red = (200,0,0)
bright_red = (255,0,0)
white = (255,255,255)
groundcolor = (139,69,19)
green = (80,80,80)
other_green = (110,110,110)
lives = 0
gameDisplay = pygame.display.set_mode((1336,768))
pygame.display.set_caption("TheAviGame")
direction = 'none'
clock = pygame.time.Clock()
img = pygame.image.load('guyy.bmp')
famousdude = pygame.image.load('kitten1.bmp')
kitten = pygame.image.load('macharacterbrah.bmp')
dorritosman = pygame.image.load('Doritos.bmp')
backround = pygame.image.load('backroundd.bmp')
playernormal = pygame.image.load('normalguy.bmp')
playerocket = pygame.image.load('rocketguyy.bmp')
rocketcat = pygame.image.load('jetpackcat.bmp')
mlglogo = pygame.image.load('mlg.bmp')
level1bg = pygame.image.load('level1background.bmp')
def mts(text, textcolor, x, y, fs):
font = pygame.font.Font(None,fs)
text = font.render(text, True, textcolor)
gameDisplay.blit(text, [x,y])
def button(x,y,w,h,ic,ac):
mouse = pygame.mouse.get_pos()
click = pygame.mouse.get_pressed()
if x+w > mouse[0] > x and y+h > mouse[1] > y:
pygame.draw.rect(gameDisplay, ac,(x,y,w,h))
if click[0] == 1:
gameloop()
else:
pygame.draw.rect(gameDisplay, ic,(x,y,w,h))
def game_intro():
intro = True
while intro:
for event in pygame.event.get():
#print(event)
if event.type == pygame.QUIT:
pygame.quit()
quit()
gameDisplay.fill(black)
button(450,450,250,70,green,other_green)
mts("Play", white, 540, 470, 50)
mts("THE AVI GAME", red, 380, 100, 100)
gameDisplay.blit(famousdude, (100,100))
gameDisplay.blit(kitten, (700,300))
gameDisplay.blit(dorritosman, (1000,400))
pygame.display.update()
clock.tick(15)
def gameloop():
imgx = 1000
imgy = 100
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_RIGHT:
imgx += 10
gameDisplay.blit(backround, (30,30))
gameDisplay.blit(rocketcat, (imgx,imgy))
pygame.display.update()
clock.tick(15)
def level1():
imgx = 500
imgy = 500
leveltext = False
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
while not leveltext:
gameDisplay.blit(level1bg, (0,0))
mts("LEVEL 1:", red, 450, 220, 60)
mts('Controls: W or Up to move up.', white, 450, 300, 40)
mts('Controls: A or Left to move left.', white, 450, 340, 40)
mts('Controls: S or Down to move down.', white, 450, 390, 40)
mts('Controls: D or Right to move Right.', white, 450, 430, 40)
time.sleep(2)
leveltext = True
pygame.display.update()
level1()
From my understanding, when you blit text onto a surface it permanently becomes part of that surface. If you want the font to disappear, you could try blitting it onto a copy of that surface and then blit the altered surface to the display.

image changing to another image changing in pygame

i made a program in pygame ware a mine turtle runs in a sqare but when you click in the box he explodes but when i change the image to an explodtion it shows th mineturtle first
here's my code:
import pygame, sys, time
from pygame.locals import *
pygame.init()
FPS = 40 # frames per second setting
fpsClock = pygame.time.Clock()
# set up the window
DISPLAYSURF = pygame.display.set_mode((400, 300), 0, 32)
pygame.display.set_caption('Animation')
WHITE = (255, 255, 255)
print("if you click the mine tutle box he will explode")
cat = pygame.image.load("mineturtle.PNG")
catx = 10
caty = 10
direction = 'right'
s=15
while True: # the main game loop
DISPLAYSURF.fill(WHITE)
if direction == 'right':
catx += s
if catx == 280:
direction = 'down'
elif direction == 'down':
caty += s
if caty == 220:
direction = 'left'
elif direction == 'left':
catx -= s
if catx == 10:
direction = 'up'
elif direction == 'up':
caty -= s
if caty == 10:
direction = 'right'
DISPLAYSURF.blit(cat, (catx, caty))
for event in pygame.event.get():
if event.type == MOUSEBUTTONDOWN:
b = pygame.image.load("b.png")
time.sleep(2)
pygame.quit()
sys.exit()
if event.type == QUIT:
pygame.quit()
sys.exit()
pygame.display.update()
fpsClock.tick(FPS)
i already have all of the files in the same loaction but when i did the image swich id didn't work! plz help
To show changes on screen you need to call pygame.display.update(). When you call sleep and exit, it does not update the screen, and no changes are seen.
time.
EDIT:
If you wish to show a new image for 2 seconds and then close the program, you should use pygame.time module. Have a variable that will store the time since the last click. You add the result of tick(). When the value will be high enough, you can exit pygame.
This will not freeze the window, and you will be able to see the changes.
i just did this
import pygame, sys, time
from pygame.locals import *
pygame.init()
FPS = 40 # frames per second setting
fpsClock = pygame.time.Clock()
# set up the window
DISPLAYSURF = pygame.display.set_mode((400, 300), 0, 32)
pygame.display.set_caption('Animation')
WHITE = (255, 255, 255)
print("if you click the mine tutle box he will explode")
cat = pygame.image.load("mineturtle.PNG")
catx = 10
caty = 10`enter code here`
direction = 'right'
s=15
explodetick=0
move=True
while True: # the main game loop
DISPLAYSURF.fill(WHITE)
#for event in pygame.event.get():
#
if explodetick>0:
explodetick+=1
if explodetick==81:
pygame.quit()
if move:
if direction == 'right':
catx += s
if catx == 280:
direction = 'down'
elif direction == 'down':
caty += s
if caty == 220:
direction = 'left'
elif direction == 'left':
catx -= s
if catx == 10:
direction = 'up'
elif direction == 'up':
caty -= s
if caty == 10:
direction = 'right'
DISPLAYSURF.blit(cat, (catx, caty))
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
if event.type == MOUSEBUTTONDOWN:
cat = pygame.image.load("b.png")
pygame.display.update()
explodetick=1
move=False
pygame.display.update()
fpsClock.tick(FPS)

Pygame: How to tile subsurfaces on an image

I'm completely new to Python/Pygame and I'm trying to slice an image up into subsurfaces and then blit them in order to the screen (so that later on I can modify it to call upon a certain tile and then blit it).
E1: I think I've finally managed to slice it the right way but there's a little hitch with the blitting.
E2: Updated the code and error (been getting this one on most of the code I tried before as well).
import pygame
from pygame.locals import *
pygame.init()
screen = pygame.display.set_mode((640, 480))
screen.fill((255, 255, 255))
def load_tileset(filename, width, height):
image = pygame.image.load(filename).convert()
image_width, image_height = image.get_size()
tileset = []
for tile_x in range(0, image_width//width):
line = []
tileset.append(line)
for tile_y in range(0, image_height//height):
rect = (tile_x*width, tile_y*height, width, height)
line.append(image.subsurface(rect))
return tileset
def draw_background(screen, tile_img, field_rect):
img_rect = tile_img.get_rect()
for y in range(0,400,32):
for x in range(0,600,32):
screen.blit(tile_img, (x,y))
Field_Rect = Rect(50,50, 300,300)
tileset = load_tileset("platform1.bmp", 17, 17)
bg_tile_img = tileset[0]
draw_background(screen, bg_tile_img, Field_Rect)
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
if event.type == KEYDOWN:
if event.key == K_ESCAPE:
pygame.quit()
pygame.display.flip()
The error it gives atm is:
img_rect = tile_img.get_rect()
AttributeError: 'list' object has no attribute 'get_rect'
In this function here where you create the tileset:
def load_tileset(filename, width, height):
image = pygame.image.load(filename).convert()
image_width, image_height = image.get_size()
tileset = []
for tile_x in range(0, image_width//width):
line = []
tileset.append(line)
for tile_y in range(0, image_height//height):
rect = (tile_x*width, tile_y*height, width, height)
line.append(image.subsurface(rect))
return tileset
...you will notice that tileset is a list, and each element of tileset (labeled as line), is also a list.
So in this code here:
tileset = load_tileset("platform1.bmp", 17, 17)
bg_tile_img = tileset[0]
draw_background(screen, bg_tile_img, Field_Rect)
...you are passing a list, called bg_tile_img, to the draw_background function.
Your draw_background function should instead look more like this:
def draw_background(screen, tile_img, field_rect):
for img in tile_img:
img_rect = img.get_rect()
for y in range(0,400,32):
for x in range(0,600,32):
screen.blit(img, (x,y))
Alternatively, instead of passing bg_tile_img as a list, pop an element off of it to pass to the draw_background function.
You are not assigning the tileset:
load_tileset("platform1.bmp", 17, 17)
should be:
tileset = load_tileset("platform1.bmp", 17, 17)
Update:
set_mode creates the window, so it should be outside the main loop (load_tileset too):
screen = pygame.display.set_mode((640, 480))
tileset = load_tileset("platform1.bmp", 17, 17)
while True:
for event in pygame.event.get():
...
Also, I can't see any call to draw_background.
Update2:
As Haz said, tileset is a list of lines (a matrix), you could use coordinates to retrieve a specific tile:
bg_tile_img = tileset[0][0]
Or make the tileset a plain list, adding everything directly to the tileset instead of using lines.

Animate like Google Finance charts in Matplotlib?

I just started toying around with Matplotlib's Animation capabilities in order to produce a Google Finance looking chart.
I combined two examples I found on the project website (Draggable rectangle exercise, api example code: date_demo.py) and tweaked them a bit to come up with the code listed at the bottom.
While it doesn't look too bad, I would like the top chart (master) update dynamically as the bottom chart (slave) selection is moved around, and not only when the bottom selection is released. How can I do this? I tried to move the self.rect.figure.canvas.draw() bit to the on_motion method, but it seems to interfere with the blit stuff as the bottom selection won't render properly.
So I would assume the solution would be to do the intelligent animation for the bottom chart, i.e., the blit-ing bit, while the top chart is just re-drawn altogether. The issue is that the only way I can redraw anything is through the re-drawing the whole canvas, and this would include the bottom chart. I did find the draw() method for matplotlib.axes, but I can't get it to work. As I said above, preferably I would like to just re-draw the top chart while the bottom one is blit-ed the clever way. Does anyone know how to do this?
Here is my code so far. Please excuse the code, it's a bit untidy.
import datetime
import numpy as np
import sys
import time
import wx
import matplotlib
from matplotlib.figure import Figure
import matplotlib.dates as mdates
import matplotlib.ticker as mtickers
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas
import matplotlib.patches as mpatches
class DraggableRectangle:
lock = None
def __init__(self, rect, master, xMin, xMax):
self.rect = rect
self.press = None
self.background = None
self.xMax = xMax
self.xMin = xMin
self.master = master
def connect(self):
self.cidpress = self.rect.figure.canvas.mpl_connect('button_press_event', self.on_press)
self.cidrelease = self.rect.figure.canvas.mpl_connect('button_release_event', self.on_release)
self.cidmotion = self.rect.figure.canvas.mpl_connect('motion_notify_event', self.on_motion)
def on_press(self, event):
if event.inaxes != self.rect.axes: return
if DraggableRectangle.lock is not None: return
contains, attrd = self.rect.contains(event)
if not contains: return
x0, y0 = self.rect.xy
self.press = x0, y0, event.xdata, event.ydata
DraggableRectangle.lock = self
canvas = self.rect.figure.canvas
axes = self.rect.axes
self.rect.set_animated(True)
canvas.draw()
self.background = canvas.copy_from_bbox(self.rect.axes.bbox)
axes.draw_artist(self.rect)
canvas.blit(axes.bbox)
def on_motion(self, event):
if DraggableRectangle.lock is not self: return
if event.inaxes != self.rect.axes: return
x0, y0, xpress, ypress = self.press
dx = event.xdata - xpress
dy = 0
if x0+dx > self.xMax:
self.rect.set_x(self.xMax)
elif x0+dx < self.xMin:
self.rect.set_x(self.xMin)
else:
self.rect.set_x(x0+dx)
self.rect.set_y(y0+dy)
canvas = self.rect.figure.canvas
axes = self.rect.axes
canvas.restore_region(self.background)
self.master.set_xlim(self.rect.get_x(), self.rect.get_x() + 92)
axes.draw_artist(self.rect)
canvas.blit(axes.bbox)
def on_release(self, event):
if DraggableRectangle.lock is not self: return
self.press = None
DraggableRectangle.lock = None
self.rect.set_animated(False)
self.background = None
self.rect.figure.canvas.draw()
def disconnect(self):
self.rect.figure.canvas.mpl_disconnect(self.cidpress)
self.rect.figure.canvas.mpl_disconnect(self.cidrelease)
self.rect.figure.canvas.mpl_disconnect(self.cidmotion)
class MplCanvasFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, wx.ID_ANY, title='First Chart', size=(800, 700))
datafile = matplotlib.get_example_data('goog.npy')
r = np.load(datafile).view(np.recarray)
datesFloat = matplotlib.dates.date2num(r.date)
figure = Figure()
xMaxDatetime = r.date[len(r.date)-1]
xMinDatetime = r.date[0]
xMaxFloat = datesFloat[len(datesFloat)-1]
xMinFloat = datesFloat[0]
yMin = min(r.adj_close) // 5 * 5
yMax = (1 + max(r.adj_close) // 5) * 5
master = figure.add_subplot(211)
master.plot(datesFloat, r.adj_close)
master.xaxis.set_minor_locator(mdates.MonthLocator())
master.xaxis.set_major_locator(mdates.MonthLocator(bymonth=(1,4,7,10)))
master.xaxis.set_major_formatter(mdates.DateFormatter('%b-%y'))
master.set_xlim(datesFloat[120], datesFloat[120]+92)
master.yaxis.set_minor_locator(mtickers.MultipleLocator(50))
master.yaxis.set_major_locator(mtickers.MultipleLocator(100))
master.set_ylim(yMin, yMax)
master.set_position([0.05,0.20,0.92,0.75])
master.xaxis.grid(True, which='minor')
master.yaxis.grid(True, which='minor')
slave = figure.add_subplot(212, yticks=[])
slave.plot(datesFloat, r.adj_close)
slave.xaxis.set_minor_locator(mdates.MonthLocator())
slave.xaxis.set_major_locator(mdates.YearLocator())
slave.xaxis.set_major_formatter(mdates.DateFormatter('%b-%y'))
slave.set_xlim(xMinDatetime, xMaxDatetime)
slave.set_ylim(yMin, yMax)
slave.set_position([0.05,0.05,0.92,0.10])
rectangle = mpatches.Rectangle((datesFloat[120], yMin), 92, yMax-yMin, facecolor='yellow', alpha = 0.4)
slave.add_patch(rectangle)
canvas = FigureCanvas(self, -1, figure)
drag = DraggableRectangle(rectangle, master, xMinFloat, xMaxFloat - 92)
drag.connect()
app = wx.PySimpleApp()
frame = MplCanvasFrame()
frame.Show(True)
app.MainLoop()
I had a chance to work on this this morning (we are having a 2nd blizzard for the last 3 days). You are right, if you try to redraw the entire figure in the on_motion, it messes up the animation of the yellow rectangle. The key is to also blit the line on the master sub plot.
Try this code out:
import datetime
import numpy as np
import sys
import time
import wx
import matplotlib
from matplotlib.figure import Figure
import matplotlib.dates as mdates
import matplotlib.ticker as mtickers
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas
import matplotlib.patches as mpatches
class DraggableRectangle:
lock = None
def __init__(self, rect, master, xMin, xMax):
self.rect = rect
self.press = None
self.slave_background = None
self.master_background = None
self.xMax = xMax
self.xMin = xMin
self.master = master
self.master_line, = self.master.get_lines()
def connect(self):
self.cidpress = self.rect.figure.canvas.mpl_connect('button_press_event', self.on_press)
self.cidrelease = self.rect.figure.canvas.mpl_connect('button_release_event', self.on_release)
self.cidmotion = self.rect.figure.canvas.mpl_connect('motion_notify_event', self.on_motion)
def on_press(self, event):
if event.inaxes != self.rect.axes: return
if DraggableRectangle.lock is not None: return
contains, attrd = self.rect.contains(event)
if not contains: return
x0, y0 = self.rect.xy
self.press = x0, y0, event.xdata, event.ydata
DraggableRectangle.lock = self
canvas = self.rect.figure.canvas
axes = self.rect.axes
# set up our animated elements
self.rect.set_animated(True)
self.master_line.set_animated(True)
self.master.xaxis.set_visible(False) #we are not animating this
canvas.draw()
# backgrounds for restoring on animation
self.slave_background = canvas.copy_from_bbox(self.rect.axes.bbox)
self.master_background = canvas.copy_from_bbox(self.master.axes.bbox)
axes.draw_artist(self.rect)
canvas.blit(axes.bbox)
def on_motion(self, event):
if DraggableRectangle.lock is not self: return
if event.inaxes != self.rect.axes: return
x0, y0, xpress, ypress = self.press
dx = event.xdata - xpress
dy = 0
if x0+dx > self.xMax:
self.rect.set_x(self.xMax)
elif x0+dx < self.xMin:
self.rect.set_x(self.xMin)
else:
self.rect.set_x(x0+dx)
self.rect.set_y(y0+dy)
canvas = self.rect.figure.canvas
axes = self.rect.axes
# restore backgrounds
canvas.restore_region(self.slave_background)
canvas.restore_region(self.master_background)
# set our limits for animated line
self.master.set_xlim(self.rect.get_x(), self.rect.get_x() + 92)
# draw yellow box
axes.draw_artist(self.rect)
canvas.blit(axes.bbox)
#draw line
self.master.axes.draw_artist(self.master_line)
canvas.blit(self.master.axes.bbox)
def on_release(self, event):
if DraggableRectangle.lock is not self: return
self.press = None
DraggableRectangle.lock = None
# unanimate rect and lines
self.rect.set_animated(False)
self.master_line.set_animated(False)
self.slave_background = None
self.master_background = None
# redraw whole figure
self.master.xaxis.set_visible(True)
self.rect.figure.canvas.draw()
def disconnect(self):
self.rect.figure.canvas.mpl_disconnect(self.cidpress)
self.rect.figure.canvas.mpl_disconnect(self.cidrelease)
self.rect.figure.canvas.mpl_disconnect(self.cidmotion)
class MplCanvasFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, wx.ID_ANY, title='First Chart', size=(800, 700))
datafile = matplotlib.get_example_data('goog.npy')
r = np.load(datafile).view(np.recarray)
datesFloat = matplotlib.dates.date2num(r.date)
figure = Figure()
xMaxDatetime = r.date[len(r.date)-1]
xMinDatetime = r.date[0]
xMaxFloat = datesFloat[len(datesFloat)-1]
xMinFloat = datesFloat[0]
yMin = min(r.adj_close) // 5 * 5
yMax = (1 + max(r.adj_close) // 5) * 5
master = figure.add_subplot(211)
master.plot(datesFloat, r.adj_close)
master.xaxis.set_minor_locator(mdates.MonthLocator())
master.xaxis.set_major_locator(mdates.MonthLocator(bymonth=(1,4,7,10)))
master.xaxis.set_major_formatter(mdates.DateFormatter('%b-%y'))
master.set_xlim(datesFloat[120], datesFloat[120]+92)
master.yaxis.set_minor_locator(mtickers.MultipleLocator(50))
master.yaxis.set_major_locator(mtickers.MultipleLocator(100))
master.set_ylim(yMin, yMax)
master.set_position([0.05,0.20,0.92,0.75])
master.xaxis.grid(True, which='minor')
master.yaxis.grid(True, which='minor')
slave = figure.add_subplot(212, yticks=[])
slave.plot(datesFloat, r.adj_close)
slave.xaxis.set_minor_locator(mdates.MonthLocator())
slave.xaxis.set_major_locator(mdates.YearLocator())
slave.xaxis.set_major_formatter(mdates.DateFormatter('%b-%y'))
slave.set_xlim(xMinDatetime, xMaxDatetime)
slave.set_ylim(yMin, yMax)
slave.set_position([0.05,0.05,0.92,0.10])
rectangle = mpatches.Rectangle((datesFloat[120], yMin), 92, yMax-yMin, facecolor='yellow', alpha = 0.4)
slave.add_patch(rectangle)
canvas = FigureCanvas(self, -1, figure)
drag = DraggableRectangle(rectangle, master, xMinFloat, xMaxFloat - 92)
drag.connect()
app = wx.PySimpleApp()
frame = MplCanvasFrame()
frame.Show(True)
app.MainLoop()

Resources