[Tutor] engines
Gregor Lingl
glingl@aon.at
Thu, 18 Jul 2002 19:53:55 +0200
This is a multi-part message in MIME format.
--------------020609000405030103040107
Content-Type: text/plain; charset=us-ascii; format=flowed
Content-Transfer-Encoding: 7bit
Hi Cameron, hi Pythonistas!
By accident I'm just working on a tiny (and well known) game
(see attachment!) It has an example of a game-engine built in -
or at least what I could imagine this could be.
It's designed to serve for some educational meterial I'm
going to prepare and it's not finished yet - so it's not well
documented.I'm learning more than I'm programming, at the moment.
Nevertheless it may serve as an example, Cameron was searching for
in his posting.
Of course I'm interested to know, if you all consider it a
useful example.
Specifically I use a pattern for implementing a keyboard-controlled
animation, which I would like to know if it's the standard way doing
things like this with Tkinter or if there are better ways to do it.
It goes like this:
1.) a function like
eventlist = []
def taste(event):
key = event.keysym
if key in goodkeys:
self.eventlist.append(key)
is bound to the GUI and maintains a list of
events, which serve to control the
2.) animation, which runs in some canvas:
def run():
taste = None
# 1. suck one command from the eventlist
if self.eventlist:
taste = self.eventlist[0]
self.eventlist = self.eventlist[1:]
# 2. then process some sort of finite state machine:
if state == "start":
if taste == ...:
* do this *
elif taste == ...:
* do that *
< if necessary change state >
elif state = "running":
< do other stuff depending on commands
waiting in eventlist >
....
elif state = "over":
<etc.. >
# 3. finally
canvas.update()
canvas.after(100, run)
Have fun studying it ( and perhaps even playing it ;;;-) ).
Critical comments and suggestions for improvement of the code
are VERY welcome.
With kind regards
Gregor
Cameron Stoner schrieb:
> Hi all,
>
> How does a program engine work? How do you develope one and how do
> you use it?
>
> Thanks,
>
> Cameron Stoner
--------------020609000405030103040107
Content-Type: text/plain;
name="snake.py"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
filename="snake.py"
""" snake - OOP training (V. OOP12)
author: gregor lingl, vienna. email: glingl@aon.at """
from Tkinter import *
from Canvas import Rectangle
import sys, random
class Spielbrett(Canvas):
def __init__(self, root, NX, NY, feldbreite=12, **kwargs):
Canvas.__init__(self, root, kwargs)
w,h = NX*feldbreite, NY*feldbreite
self.config(width=w+2, height=h+2, bg = 'yellow')
self.grid = {}
for zeile in range(NY):
for spalte in range(NX):
x0 = 2 + spalte * feldbreite
y0 = 2 + zeile * feldbreite
x1 = x0 + feldbreite
y1 = y0 + feldbreite
r = Rectangle(self, x0, y0, x1, y1,
fill='yellow', outline='yellow' )
self.grid[(spalte,zeile)] = r
def set(self,feld,farbe):
self.grid[feld]['fill'] = farbe
class Snake:
def __init__(self, size):
self.N = size
self.futter = None
self.reset()
def reset(self):
self.schlange = [(self.N/2,self.N/2)]
selfFutter = None
self.setzeFutter()
self.richtung = None
self.alive = 1
def setzeFutter(self):
while not self.futter or self.futter in self.schlange:
self.futter = (random.randrange(self.N), random.randrange(self.N))
def getscore(self):
return "Score: " + str(max(0,len(self.schlange)-4))
def schwanzAb(self):
self.schlange = self.schlange[1:]
def kopfDran(self,feld):
self.schlange.append(feld)
def neuesFeld(self):
x,y = self.schlange[-1]
if self.richtung == 'Up':
y=y-1
elif self.richtung == 'Down':
y=y+1
elif self.richtung == 'Left':
x=x-1
elif self.richtung == 'Right':
x=x+1
else:
return None
return (x,y)
def amBrett(self, neu):
x,y=neu
return 0 <= x < self.N and 0 <= y < self.N
def schritt(self, neueRichtung):
changed = {}
if neueRichtung:
if (neueRichtung,self.richtung) not in (('Up','Down'),('Down','Up'),
('Right','Left'),('Left','Right')):
self.richtung = neueRichtung
neu = self.neuesFeld()
# Fall 1: angestossen
if not self.amBrett(neu) or neu in self.schlange:
self.alive = 0
for glied in self.schlange:
changed[glied]='black'
# Fall 2: Futter gefunden
elif neu == self.futter:
self.kopfDran(neu)
changed[neu]='red'
self.setzeFutter()
changed[self.futter]='blue'
# Fall 3: normaler Schritt
else:
if len(self.schlange) > 3:
changed[self.schlange[0]]='yellow'
self.schwanzAb()
self.kopfDran(neu)
changed[neu]='red'
return changed
class SnakeEngine:
def __init__(self, N):
self.N = N
root = Tk()
root.title("SNAKE")
root.bind('<KeyPress>', self.taste)
self.brett = Spielbrett(root,N,N)
self.brett.pack()
self.scorelabel = Label(root,width=22,text="",font=("Courier",14,"bold"),fg='red')
self.hintlabel = Label(root,width=22,text="",font=("Courier",14,"normal"))
self.scorelabel.pack()
self.hintlabel.pack()
self.schlange = Snake(N)
self.reset()
def taste(self,event):
key = event.keysym
if key == 'Return':
sys.exit(0)
if key in ['Up','Down','Left','Right','space']:
self.eventlist.append(key)
def reset(self):
for feld in self.brett.grid:
self.brett.set(feld,'yellow')
self.eventlist = []
self.state = "waiting"
self.schlange.reset()
self.brett.set(self.schlange.schlange[0],'red')
self.brett.set(self.schlange.futter,'blue')
self.brett.update()
self.hintlabel.config(text="Steuerung: Pfeiltasten")
self.scorelabel.config(text=self.schlange.getscore())
def run(self):
changed = {}
taste = None
if self.eventlist:
taste = self.eventlist[0]
self.eventlist = self.eventlist[1:]
if self.state == "waiting":
if taste in ['Up','Down','Right','Left']:
self.state = "running"
if self.state == "running":
if taste in ['Up','Down','Right','Left', None]:
changed = self.schlange.schritt(taste)
self.scorelabel.config(text=self.schlange.getscore())
if not self.schlange.alive:
self.state="over"
self.hintlabel.config(text="Neues Spiel: Leertaste")
elif self.state == "over":
if taste == 'space':
self.reset()
for feld in changed:
self.brett.set(feld, changed[feld])
self.brett.update()
self.brett.after(100, self.run)
SnakeEngine(21).run()
mainloop()
--------------020609000405030103040107--