I am trying to set the Boolean Variable "self.running" to True in order as a check to show that the application is running, and will refresh the canvas. However, whenever I run this code, I get back the error message:
"line 29, in mainloop
if self.running == True:
AttributeError: 'Game' object has no attribute 'running'"
the actual code for this is simply
self.running = True
I don't see the actual issue here, as I am a newbie to python and coding world in general, I searched around but found different scenarios then the one I had and couldn't apply their solutions to my issue. Thank you.
edit:Code
class Game:
def _init_(self):
self.tk = Tk()
self.running = False
self.tk.title("Man runs to door. Wins nobel prize.")
self.tk.resizable(0, 0)
self.tk.wm_attributes("-topmost", 1)
self.canvas = Canvas(self.tk, width=500, height=500, \
highlightthickness=0)
self.canvas.pack()
self.tk.update()
self.canvas_height = 500
self.canvas_width = 500
self.bg = PhotoImage(file="background.gif")
w = self.bg.width()
h = self.bg.height()
for x in range(0, 5):
for y in range(0, 5):
self.canvas.create_image(x * w, y * h, \
image=self.bg, anchor='nw')
self.sprites = []
self.running = True
def mainloop(self):
while 1:
if self.running == True:
for sprite in self.sprites:
sprite.move()
self.tk.update_idletasks()
self.tk.update()
time.sleep(0.01)
this is the entire initialization area and mainloop.
would this be a correct version of the code then?
class Game:
def _init_(self):
self.tk = Tk()
self.running = False
self.tk.title("Man runs to door. Wins nobel prize.")
self.tk.resizable(0, 0)
self.tk.wm_attributes("-topmost", 1)
self.canvas = Canvas(self.tk, width=500, height=500, \
highlightthickness=0)
self.canvas.pack()
self.tk.update()
self.canvas_height = 500
self.canvas_width = 500
self.bg = PhotoImage(file="background.gif")
w = self.bg.width()
h = self.bg.height()
for x in range(0, 5):
for y in range(0, 5):
self.canvas.create_image(x * w, y * h, \
image=self.bg, anchor='nw')
self.sprites = []
self.running = True
def mainloop(self):
while 1:
if self.running == True:
for sprite in self.sprites:
sprite.move()
self.tk.update_idletasks()
self.tk.update()
time.sleep(0.01)
I guess you might have a class called Game in your code and you just miss the "self.running" in the initialization:
class Game:
def __init__(self):
self.running = False
From the updated question - your mainloop is not inside your Game class, so self doesn't work as you expect. You need to properly indent your code:
class Game
def mainloop(self):
while 1:
if self.running == True:
for sprite in self.sprites:
sprite.move()
self.tk.update_idletasks()
self.tk.update()
time.sleep(0.01)
game = Game()
game.mainloop()
Ensure that mainloop is indented 4 spaces inside of Game.
This error message says your self.running has not been initialized.
I am not sure where do you assign self.running = True.
The best way to do is add this code into your __init__ method
The problem seems to be on your def __init__(self):
Note that the init is surrounded by two underscores and not just one like your example code.
The rest looks fine, but it would be more pythonic to just write
if self.running:
instead of comparing it to True.
Also, be sure to check your identation as pointed out by Martin Konecny.
Related
This is a function as part of a class to create tkinter Toplevel instances. I am trying to have the X button on each window destroy itself and then create two new windows. Every time I try running this, 'test' is only printed once and only 1 new window will appear. Why is this happening? Thanks!
Here is the class for creating tkinter instances
class App(Toplevel):
nid = 0
def __init__(self, master, title, f, nid):
# Creates Toplevel to allow for sub-windows
Toplevel.__init__(self, master)
self.thread = None
self.f = f
self.nid = nid
self.master = master
self.canvas = None
self.img = None
self.label = None
self.title(title)
self.geometry('300x300')
def window(self):
# Creates play_sound thread for self
self.thread = threading.Thread(target=lambda: play_sound())
# Disables resizing
self.resizable(False, False)
self.img = PhotoImage(file=self.f)
# Creates canvas
self.canvas = Canvas(self, width=300, height=300)
self.canvas.create_image(20, 20, anchor=NW, image=self.img)
self.canvas.pack(fill=BOTH, expand=1)
# Function to move each window to a random spot within the screen bounds
def move(self):
while True:
new_x = random.randrange(0, x)
new_y = random.randrange(0, y)
cur_x = self.winfo_x()
cur_y = self.winfo_y()
dir_x = random.choice(['-', '+'])
dir_y = random.choice(['-', '+'])
# Tests if the chosen position is within the monitor
try:
if (eval(f'{cur_x}{dir_x}{new_x}') in range(0, x)
and eval(f'{cur_y}{dir_y}{new_y}') in range(0, y)):
break
# Prevents crashing if the program happens to exceed the recursion limit
except RecursionError:
pass
# Sets geometry to the new position
self.geometry(f"+{new_x}+{new_y}")
# Repeats every second
self.after(1000, self.move)
# Starts sound thread
def sound(self):
self.thread.start()
# Changes the function of the X button
def new_protocol(self, func):
def run():
#do_twice
def cmd():
print('test')
func()
def both():
self.destroy()
return cmd()
self.protocol('WM_DELETE_WINDOW', both)
run()
Here is the function to create new windows
def create_window():
global num
# Hides root window
root.withdraw()
# Creates a new window with variable name root{num}.
d['root{0}'.format(num)] = App(root, 'HE HE HE HA', r'build\king_image.png', 0)
app_list.append(d['root{0}'.format(num)].winfo_id())
print(d['root{0}'.format(num)])
globals().update(d)
# Starts necessary commands for window
d['root{0}'.format(num)].window()
d['root{0}'.format(num)].move()
d['root{0}'.format(num)].new_protocol(create_window)
d['root{0}'.format(num)].sound()
d['root{0}'.format(num)].mainloop()
num += 1
Here is the decorator function:
def do_twice(func):
#functools.wraps(func)
def wrapper(*args, **kwargs):
func(*args, **kwargs)
func(*args, **kwargs)
return wrapper
If anyone needs any other parts of my code I will gladly edit this to include them.
so i am trying to make a 2d "minecraft" game in python, but i just cant get an image to show up
I have this code now:
from tkinter import *
import time
class Block:
def __init__(self, posx, posy, game):
self.x = posx
self.y = posy
self.game = game
self.grass_block = PhotoImage(file="grass_block.gif")
print("place")
self.image = self.game.canvas.create_image(posx, posy, image=self.grass_block, anchor="nw")
self.hoi = self.game.canvas.create_oval(100,100,100,100, fill = "red")
def get_image(self):
return self.image
class Game:
def __init__(self):
self.tk = Tk()
self.tk.title("MijnCraft")
self.tk.resizable(0, 0)
self.canvas = Canvas(self.tk, width=1000, height=1000, highlightthickness=0)
self.canvas.pack()
self.bg = PhotoImage(file="nacht.gif")
self.canvas.create_image(0, 0, image=self.bg, anchor="nw")
self.aan = True
self.genworld()
def genworld(self):
print("make")
Block(100, 100, self)
def gameloop(self):
while self.aan:
self.tk.update_idletasks()
self.tk.update()
time.sleep(0.01)
spel = Game()
spel.gameloop()
But i just cant get a block image to show up, i just get the backgound, does someone know what i am doing wrong, (i dont get any errors)(it does print the 2 debug messages)
i hope you can help!
Your instance of Block is a local object that is getting destroyed when genworld returns. To prevent this, save a reference to the block. Assuming you're going to want to create more than one block, you can use a list or dictionary.
class Game:
def __init__(self):
self.blocks = []
...
def genworld(self):
self.blocks.append(Block(100, 100, self))
I am creating a replica of dodger using tkinter. I am facing a problem with timing object movement. I was told the time module does not work well with tkinter, therefore I should use after() instead. However, I face the same problem with the after() function as I did with the time module. Here is my code:
from tkinter import *
from random import randint
class Window(Frame):
def __init__(self, master=None):
Frame.__init__(self, master)
self.master = master
self.initWindow()
def initWindow(self):
self.master.title('Dodger')
self.pack(fill=BOTH, expand=1)
self.master.geometry('600x800')
self.master.config(bg='black')
menu = Menu(self.master)
self.master.config(menu=menu)
def clientExit():
exit()
file = Menu(menu)
file.add_command(label='Exit', command=clientExit)
file.add_command(label='Start', command=self.game)
menu.add_cascade(label='File', menu=file)
def game(self):
canvas = Canvas(self.master, width='600', height='800', borderwidth='0', highlightthickness='0')
canvas.pack()
canvas.create_rectangle(0, 0, 600, 800, fill='black', outline='black')
character = canvas.create_rectangle(270, 730, 330, 760, fill='magenta', outline='cyan', width='2')
def left(event):
cord = canvas.coords(character)
if cord[0] <= 5:
pass
else:
canvas.move(character, -10, 0)
def right(event):
cord = canvas.coords(character)
if cord[2] >= 595:
pass
else:
canvas.move(character, 10, 0)
self.master.bind('<Left>', left)
self.master.bind('<Right>', right)
class variables:
sizeMin = 10
sizeMax = 80
y = 10
minX = 5
maxX = 545
def createShape():
size = randint(variables.sizeMin, variables.sizeMax)
x = randint(variables.minX, variables.maxX)
topLeft = [x, variables.y]
bottomRight = [x + size, variables.y + size]
shape = canvas.create_rectangle(topLeft[0], topLeft[1], bottomRight[0], bottomRight[1],
fill='red', outline='red')
return shape
def moveShape(shape):
canvas.move(shape, 0, 800)
for x in range(5):
x = createShape()
self.master.after(1000, moveShape(x))
root = Tk()
app = Window(root)
app.mainloop()
As you can see, at the bottom of the game instance, I created a square and moved it down five times at 1 second intervals. However, this did not work; my window just froze for the allotted time, then resumed afterwards. I am not sure if this is because my computer sucks or if I did something wrong. Please run my code in you editor and explain to me if I did something wrong.
The reason it freezes is because you're calling after wrong.
Consider this code:
self.master.after(1000, moveShape(x))
... it is exactly the same as this code:
result = moveShape(x)
self.master.after(1000, result)
... which is the same as this, since moveShape returns None:
result = moveShape(x)
self.master.after(1000, None)
... which is the same as this:
result = moveShape(x)
self.master.after(1000)
... which is the same as
result = moveShape(x)
time.sleep(1)
In other words, you're telling it to sleep, so it sleeps.
after requires a callable, or a reference to a function. You can pass additional args as arguments to after. So the proper way to call it is this:
self.master.after(1000, moveShape, x)
Though, I doubt that is exactly what you want, since all five iterations will try to run the code 1000ms after the loop starts, rather than 1000ms apart. That's just a simple matter of applying a little math.
You need to replace the sleep function and the loop with after. Try this:
def moveShape():
if self.step < 5:
canvas.move(shape, 0, 10)
self.master.after(1000, moveShape)
self.step += 1
self.step = 0
shape = createShape()
moveShape()
Also, if you move it by 800 pixels you won't see it after the first tick, so I reduced the amount to move to 10 pixels.
Edit: this plus a lot of other bugfixes and improvements:
import tkinter as tk
from random import randint
class variables:
sizeMin = 10
sizeMax = 80
y = 10
minX = 5
maxX = 545
class Window(tk.Frame):
def __init__(self, master=None):
tk.Frame.__init__(self, master)
self.master = master
self.initWindow()
def initWindow(self):
self.master.title('Dodger')
self.pack(fill=tk.BOTH, expand=1)
self.master.geometry('600x800')
self.master.config(bg='black')
menu = tk.Menu(self.master)
self.master.config(menu=menu)
file = tk.Menu(menu)
file.add_command(label='Exit', command=self.quit)
file.add_command(label='Start', command=self.game)
menu.add_cascade(label='File', menu=file)
def game(self):
self.canvas = tk.Canvas(self.master, width='600', height='800', borderwidth='0', highlightthickness='0')
self.canvas.pack()
self.canvas.create_rectangle(0, 0, 600, 800, fill='black', outline='black')
self.character = self.canvas.create_rectangle(270, 730, 330, 760, fill='magenta', outline='cyan', width='2')
self.createShape()
self.moveShape() # start the moving
self.master.bind('<Left>', self.left)
self.master.bind('<Right>', self.right)
def left(self, event):
cord = self.canvas.coords(self.character)
if cord[0] <= 5:
pass
else:
self.canvas.move(self.character, -10, 0)
def right(self, event):
cord = self.canvas.coords(self.character)
if cord[2] >= 595:
pass
else:
self.canvas.move(self.character, 10, 0)
def createShape(self):
size = randint(variables.sizeMin, variables.sizeMax)
x = randint(variables.minX, variables.maxX)
topLeft = [x, variables.y]
bottomRight = [x + size, variables.y + size]
self.shape = self.canvas.create_rectangle(topLeft[0], topLeft[1], bottomRight[0], bottomRight[1],
fill='red', outline='red')
def moveShape(self, x=0):
if x < 5: # loop 5 times
self.canvas.move(self.shape, 0, 10)
self.after(1000, self.moveShape, x+1) # run this method again in 1,000 ms
root = tk.Tk()
app = Window(root)
app.mainloop()
I am trying to wrap my head around parallel animations.
In the following code, clicking on a square will cause a small animation.
But declaring 2 boxes (or more) makes things more difficult: The animation called last will run and cause the other to pause and resume only after it is complete.
How to change my code so that all animation calls can run independently and in parallel?
#!python3
import tkinter as tk
import time
class Example(tk.Frame):
def __init__(self, parent):
tk.Frame.__init__(self, parent)
# create a canvas
self.canvas = tk.Canvas(width=400, height=400)
self.canvas.pack()
# create a couple of movable objects
self._create_token(100, 100, "green")
self._create_token(200, 100, "black")
def _create_token(self, x, y, color):
self.canvas.create_rectangle(x-25, y-25, x+25, y+25, outline=color, fill=color, tags=color)
self.canvas.tag_bind(color, "<ButtonPress-1>", self.on_token_press)
def on_token_press(self,event):
Rx = self.canvas.find_closest(event.x, event.y)
x = 0
y = 5
for i in range(25):
time.sleep(0.025)
self.canvas.move(Rx, x, y)
self.canvas.update()
for i in range(25):
time.sleep(0.025)
self.canvas.move(Rx, x, -y)
self.canvas.update()
if __name__ == "__main__":
root = tk.Tk()
Example(root).pack()
root.mainloop()
You should not use blocking tasks in a GUI, they live inside an event loop that allows them to verify events such as keyboard, mouse, etc, if you use those tasks the GUI will probably freeze. what you should do is use after() for periodic tasks, in the following solution I have proposed to create a class that manages the animation in a simple way.
#!python3
import tkinter as tk
import time
class AbstractAnimation:
def __init__(self, canvas, id_item, duration, _from = 0, _to = 1):
self.canvas = canvas
self.id_item = id_item
self._progress = 0
self._from = _from
self._to = _to
self.t = max(10, int(duration/(self._to -self._from)))
def start(self):
self.canvas.after(self.t, self.on_timeout)
def on_timeout(self):
if self._from <= self._progress < self._to:
self.interpolated(self._from, self._to, self._progress)
self._progress += 1
self.canvas.after(self.t, self.on_timeout)
def interpolated(self, _from, _to, _progress):
pass
class Animation(AbstractAnimation):
def interpolated(self, _from, _to, _progress):
x, y = 0, 5
if _progress < 25:
self.canvas.move(self.id_item, x, y)
else:
self.canvas.move(self.id_item, x, -y)
class Example(tk.Frame):
def __init__(self, parent):
tk.Frame.__init__(self, parent)
# create a canvas
self.canvas = tk.Canvas(width=400, height=400)
self.canvas.pack()
# create a couple of movable objects
self._create_token(100, 100, "green")
self._create_token(200, 100, "black")
def _create_token(self, x, y, color):
self.canvas.create_rectangle(x-25, y-25, x+25, y+25, outline=color, fill=color, tags=color)
self.canvas.tag_bind(color, "<ButtonPress-1>", self.on_token_press)
def on_token_press(self,event):
Rx = self.canvas.find_closest(event.x, event.y)
animation = Animation(self.canvas, Rx, 1250, 0, 50)
animation.start()
if __name__ == "__main__":
root = tk.Tk()
Example(root).pack()
root.mainloop()
As someone mention is the comments and #eyllanesc also mentions in his answer, you generally shouldn't call time.sleep() in a tkinter program because doing so temporarily halts its mainloop() which essentially halts the running GUI for the duration. Instead you should use the universal after() method.
However, you don't really need to use to get delays to animation. Instead it can be used to periodically run an arbitrary function within the mainloop(), which provides the leverage to animate things if desired.
In the code below, this is done by first defining a Token class to encapsulate the values associated with one, and then creating a list of them named _self._tokens, and finally using after() to schedule moving all the items in it that are currently active. The function to be called by after() in this case is the Example._update_tokens() method.
Here's code showing how to implement this approach:
import tkinter as tk
UPDATE_RATE = 10 # Updates-per-second.
UPDATE_DELAY = 1000//UPDATE_RATE # msec delay between updates.
class Token:
WIDTH, HEIGHT, INCR = 25, 25, 1
def __init__(self, canvas, x, y, color, max_value, dx, dy):
self.canvas, self.x, self.y = canvas, x, y
self.color, self.max_value, self.dx, self.dy = color, max_value, dx, dy
self.value, self.moving, self.saved_direction = 0, 0, 1
self.id = self.canvas.create_rectangle(x-self.WIDTH, y-self.HEIGHT,
x+self.WIDTH, y+self.HEIGHT,
outline=color, fill=color)
self.canvas.tag_bind(self.id, "<ButtonPress-1>", self._toggle)
def _toggle(self, _event):
""" Start movement of object if it's paused otherwise reverse its
direction.
"""
if self.moving:
self.moving = -self.moving # Reverse movement.
else: # Start it moving.
self.moving = self.saved_direction
def start(self):
self.moving = self.saved_direction
def pause(self):
if self.moving:
self.saved_direction = self.moving
self.moving = 0
class Example(tk.Frame):
def __init__(self, parent):
tk.Frame.__init__(self, parent)
self.canvas = tk.Canvas(width=400, height=400)
self.canvas.pack()
# Create list of movable objects.
self._tokens = []
self._tokens.append(Token(self.canvas, 100, 100, "green", 25, 0, 5))
self._tokens.append(Token(self.canvas, 200, 100, "black", 25, 0, 5))
tk.Button(self, text='Go', command=self._start_paused_tokens).pack(side=tk.LEFT)
tk.Button(self, text='Pause', command=self._pause_tokens).pack(side=tk.LEFT)
# Start the updating of active objects in _tokens list.
self.after(UPDATE_DELAY, self._update_tokens)
def _start_paused_tokens(self):
""" Start any paused Tokens. """
for token in self._tokens:
if token.moving == 0:
token.start()
def _pause_tokens(self):
""" Stop any moving Tokens. """
for token in self._tokens:
if token.moving != 0:
token.pause()
def _update_tokens(self):
""" Update any objects in Tokens lst that aren't paused. """
for token in self._tokens:
if token.moving > 0:
if token.value < token.max_value:
token.value += token.INCR
token.canvas.move(token.id, token.dx, token.dy)
else:
token.value = token.max_value
token.moving = -token.moving # Reverse moving.
token.canvas.move(token.id, token.dx, -token.dy)
elif token.moving < 0:
if token.value > 0:
token.value -= token.INCR
token.canvas.move(token.id, token.dx, -token.dy)
else:
token.value = 0
token.moving = -token.moving # Reverse moving.
token.canvas.move(token.id, token.dx, token.dy)
self.after(UPDATE_DELAY, self._update_tokens) # Continue doing updates.
def on_token_press(self, event):
closest_token = self.canvas.find_closest(event.x, event.y)
dx, dy = 0, 5
for i in range(25):
time.sleep(0.025)
self.canvas.move(closest_token, dx, dy)
self.canvas.update()
for i in range(25):
time.sleep(0.025)
self.canvas.move(closest_token, dx, -dy)
self.canvas.update()
if __name__ == "__main__":
root = tk.Tk()
Example(root).pack()
root.mainloop()
I am trying to make a simple game with pyglet, and it has to include an intro screen. Unfortunately, it's been proving more difficult than I expected.
The following code is a simpler version of what I am trying to do.
import pyglet
from game import intro
game_window = pyglet.window.Window(800, 600)
intro.play(game_window)
#game_window.event
def on_draw():
game_window.clear()
main_batch.draw()
def update(dt):
running = True
if __name__ == '__main__':
pyglet.clock.schedule_interval(update, 1/120.0)
main_batch = pyglet.graphics.Batch()
score_label = pyglet.text.Label(text = 'RUNNING GAME', x = 400, y = 200, batch=main_batch)
pyglet.app.run()
Where game/intro.py has the following written in it:
import pyglet
from time import sleep
def play(game_window):
game_window.clear()
studio = pyglet.text.Label('foo studios', font_size=36, font_name='Arial', x=400, y=300)
studio.draw()
sleep(5)
This opens a window (the intro window) and waits 5 seconds, after which the message "RUNNING GAME" appears, but the "foo studios" message does not appear.
Clearly I am doing something wrong.
I am not very experienced with pyglet, but I managed to get the game running (needs a bit of tweaking, but it's essentially done). All I need left is the intro screen.
If anyone knows a good way of doing an intro screen (just with text, I don't need any animations of music for now), I would be very grateful.
You're better off creating classes based on for instance pyglet.sprite.Sprite and using those objects as "windows" or "screens".
Feels like i'm pasting this code everywhere but use this, and in "def render()` put the different "scenarios"/"windows" you'd wish to be rendered at the time.
import pyglet
from time import time, sleep
class Window(pyglet.window.Window):
def __init__(self, refreshrate):
super(Window, self).__init__(vsync = False)
self.frames = 0
self.framerate = pyglet.text.Label(text='Unknown', font_name='Verdana', font_size=8, x=10, y=10, color=(255,255,255,255))
self.last = time()
self.alive = 1
self.refreshrate = refreshrate
def on_draw(self):
self.render()
def render(self):
self.clear()
if time() - self.last >= 1:
self.framerate.text = str(self.frames)
self.frames = 0
self.last = time()
else:
self.frames += 1
self.framerate.draw()
self.flip()
def on_close(self):
self.alive = 0
def run(self):
while self.alive:
self.render()
event = self.dispatch_events() # <-- This is the event queue
sleep(1.0/self.refreshrate)
win = Window(23) # set the fps
win.run()
What does it is the fact that you have a rendering function that clears and flips the entire graphical memory X times per second and you descide which objects are included in that render perior in the render function.
Try it out and see if it helps.
Here is a example using the above example, it consists of 3 things:
* A main window
* A Intro screen
* A Menu screen
You can ignore class Spr() and def convert_hashColor_to_RGBA(), these are mere helper functions to avoid repetative code further down.
I will also go ahead and mark the important bits that actually do things, the rest are just initation-code or positioning things.
import pyglet
from time import time, sleep
__WIDTH__ = 800
__HEIGHT__ = 600
def convert_hashColor_to_RGBA(color):
if '#' in color:
c = color.lstrip("#")
c = max(6-len(c),0)*"0" + c
r = int(c[:2], 16)
g = int(c[2:4], 16)
b = int(c[4:], 16)
color = (r,g,b,255)
return color
class Spr(pyglet.sprite.Sprite):
def __init__(self, texture=None, width=__WIDTH__, height=__HEIGHT__, color='#000000', x=0, y=0):
if texture is None:
self.texture = pyglet.image.SolidColorImagePattern(convert_hashColor_to_RGBA(color)).create_image(width,height)
else:
self.texture = texture
super(Spr, self).__init__(self.texture)
## Normally, objects in graphics have their anchor in the bottom left corner.
## This means that all X and Y cordinates relate to the bottom left corner of
## your object as positioned from the bottom left corner of your application-screen.
##
## We can override this and move the anchor to the WIDTH/2 (aka center of the image).
## And since Spr is a class only ment for generating a background-image to your "intro screen" etc
## This only affects this class aka the background, so the background gets positioned by it's center.
self.image.anchor_x = self.image.width / 2
self.image.anchor_y = self.image.height / 2
## And this sets the position.
self.x = x
self.y = y
def _draw(self):
self.draw()
## IntoScreen is a class that inherits a background, the background is Spr (our custom background-image class)
## IntoScreen contains 1 label, and it will change it's text after 2 seconds of being shown.
## That's all it does.
class IntroScreen(Spr):
def __init__(self, texture=None, width=300, height = 150, x = 10, y = 10, color='#000000'):
super(IntroScreen, self).__init__(texture, width=width, height=height, x=x, y=y, color=color)
self.intro_text = pyglet.text.Label('Running game', font_size=8, font_name=('Verdana', 'Calibri', 'Arial'), x=x, y=y, multiline=False, width=width, height=height, color=(100, 100, 100, 255), anchor_x='center')
self.has_been_visible_since = time()
def _draw(self): # <-- Important, this is the function that is called from the main window.render() function. The built-in rendering function of pyglet is called .draw() so we create a manual one that's called _draw() that in turn does stuff + calls draw(). This is just so we can add on to the functionality of Pyglet.
self.draw()
self.intro_text.draw()
if time() - 2 > self.has_been_visible_since:
self.intro_text.text = 'foo studios'
## Then we have a MenuScreen (with a red background)
## Note that the RED color comes not from this class because the default is black #000000
## the color is set when calling/instanciating this class further down.
##
## But all this does, is show a "menu" (aka a text saying it's the menu..)
class MenuScreen(Spr):
def __init__(self, texture=None, width=300, height = 150, x = 10, y = 10, color='#000000'):
super(MenuScreen, self).__init__(texture, width=width, height=height, x=x, y=y, color=color)
self.screen_text = pyglet.text.Label('Main menu screen', font_size=8, font_name=('Verdana', 'Calibri', 'Arial'), x=x, y=y+height/2-20, multiline=False, width=300, height=height, color=(100, 100, 100, 255), anchor_x='center')
def _draw(self):
self.draw()
self.screen_text.draw()
## This is the actual window, the game, the glory universe that is graphics.
## It will be blank, so you need to set up what should be visible when and where.
##
## I've creates two classes which can act as "screens" (intro, game, menu etc)
## And we'll initate the Window class with the IntroScreen() and show that for a
## total of 5 seconds, after 5 seconds we will swap it out for a MenuScreeen().
##
## All this magic is done in __init__() and render(). All the other functions are basically
## just "there" and executes black magic for your convencience.
class Window(pyglet.window.Window):
def __init__(self, refreshrate):
super(Window, self).__init__(vsync = False)
self.alive = 1
self.refreshrate = refreshrate
self.currentScreen = IntroScreen(x=320, y=__HEIGHT__/2, width=50) # <-- Important
self.screen_has_been_shown_since = time()
def on_draw(self):
self.render()
def on_key_down(self, symbol, mod):
print('Keyboard down:', symbol) # <-- Important
def render(self):
self.clear()
if time() - 5 > self.screen_has_been_shown_since and type(self.currentScreen) is not MenuScreen: # <-- Important
self.currentScreen = MenuScreen(x=320, y=__HEIGHT__-210, color='#FF0000') # <-- Important, here we switch screen (after 5 seconds)
self.currentScreen._draw() # <-- Important, draws the current screen
self.flip()
def on_close(self):
self.alive = 0
def run(self):
while self.alive:
self.render()
event = self.dispatch_events()
sleep(1.0/self.refreshrate)
win = Window(23) # set the fps
win.run()