<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="../assets/xml/rss.xsl" media="all"?><rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0"><channel><title>Mauveweb (Pyweek)</title><link>http://mauveweb.co.uk/</link><description></description><atom:link rel="self" href="http://mauveweb.co.uk/categories/pyweek.xml" type="application/rss+xml"></atom:link><language>en</language><lastBuildDate>Sun, 25 Mar 2018 17:44:30 GMT</lastBuildDate><generator>https://getnikola.com/</generator><docs>http://blogs.law.harvard.edu/tech/rss</docs><item><title>My Sincerest Apologies Tear-down</title><link>http://mauveweb.co.uk/posts/2018/03/my-sincerest-apologies-teardown.html</link><dc:creator>Daniel Pope</dc:creator><description>&lt;div&gt;&lt;p&gt;On Reddit I often see a variation of a conversation like this:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Newbie: I want to write games in Python!&lt;/p&gt;
&lt;p&gt;Random person: Python is no good for games. You should use C++ or C#.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The claim that Python is not a good language to write games is not true.
It's more accurate to say "Python is not a good language to write games
alone."&lt;/p&gt;
&lt;p&gt;It is well known that Python trades raw performance for productivity. But if
you use it glue together powerful libraries written in faster languages then
you can do better - you can have performance &lt;em&gt;and&lt;/em&gt; productivity.&lt;/p&gt;
&lt;div class="section" id="my-sincerest-apologies"&gt;
&lt;h2&gt;My Sincerest Apologies&lt;/h2&gt;
&lt;p&gt;In October 2017 Larry Hastings and I teamed up to enter the &lt;a class="reference external" href="https://pyweek.org/24/"&gt;Pyweek&lt;/a&gt; Game Jam,
and we won! Our game was a fast-paced 2D shooter with real-time lighting
effects, called &lt;a class="reference external" href="https://pyweek.org/e/wasabi24/"&gt;My Sincerest Apologies&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Here's a clip:&lt;/p&gt;
&lt;iframe width="608" height="832" src="https://www.youtube.com/embed/T8EGe3ZP_HI" frameborder="0" allow="autoplay;
    encrypted-media" allowfullscreen&gt;&lt;/iframe&gt;&lt;p&gt;How did we write this in a week? With 3000 lines of Python code, but
importantly, with four high-performance libraries.&lt;/p&gt;
&lt;p&gt;Each one of these libraries is an independent project, written in its own way,
but we were able to put them together in a game engine in our spare time in
one week.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="pyglet"&gt;
&lt;h2&gt;Pyglet&lt;/h2&gt;
&lt;p&gt;&lt;a class="reference external" href="https://pyglet.readthedocs.io/en/pyglet-1.3-maintenance/"&gt;Pyglet&lt;/a&gt; provides bindings for OpenGL, sound, and input devices. As well as these
it has higher-level capabilities for rendering 2D sprites and text.&lt;/p&gt;
&lt;p&gt;Pyglet is written in pure Python using the ctypes module in the Python
standard library.&lt;/p&gt;
&lt;p&gt;Pyglet isn't the fastest OpenGL library around. However it gives you the tools
to draw hundreds of sprites with very minimal cost, by arranging them into
vertex buffers and handing them to OpenGL.&lt;/p&gt;
&lt;p&gt;When you're using Pyglet you're mostly delegating all the hard work to your
system's OpenGL drivers, and this is easily fast enough for writing many
types of games.&lt;/p&gt;
&lt;p&gt;All of the basic drawing we do in &lt;em&gt;My Sincerest Apologies&lt;/em&gt; is done using
Pyglet. We also use Pyglet to control the shaders, framebuffers and render
passes needed for our lighting effects.&lt;/p&gt;
&lt;div class="figure"&gt;
&lt;img alt="/2018/msa-pyglet.png" src="http://mauveweb.co.uk/2018/msa-pyglet.png"&gt;
&lt;p class="caption"&gt;The base scene as rendered by Pyglet with lighting shaders turned off.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="lepton"&gt;
&lt;h2&gt;Lepton&lt;/h2&gt;
&lt;p&gt;&lt;a class="reference external" href="http://pythonhosted.org/lepton/"&gt;Lepton&lt;/a&gt; is a venerable Python particle engine that I have recently taken
maintainership of.&lt;/p&gt;
&lt;p&gt;Lepton is written in C using the Python C API. Most common particle operations,
such as forces, rotation, scaling and fading are performed in C under the
control of Python. It also draws the particles using OpenGL.&lt;/p&gt;
&lt;p&gt;Lepton means that we never need to actually access the particle data in Python.
All we need to do is construct and modify Lepton's Emitter objects and let
Lepton take care of everything else in fast C code.&lt;/p&gt;
&lt;div class="figure"&gt;
&lt;img alt="/2018/msa-particles.png" src="http://mauveweb.co.uk/2018/msa-particles.png"&gt;
&lt;p class="caption"&gt;Short-lived particle emitters are spawned wherever a railgun ray hits.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="pymunk"&gt;
&lt;h2&gt;Pymunk&lt;/h2&gt;
&lt;p&gt;Most games need collision detection, and fast native code libraries are a great
tool here too.&lt;/p&gt;
&lt;p&gt;We used &lt;a class="reference external" href="http://www.pymunk.org/en/latest/"&gt;Pymunk&lt;/a&gt;, which is a Python library built around the &lt;a class="reference external" href="http://chipmunk-physics.net/"&gt;Chipmunk&lt;/a&gt; 2D
physics engine using &lt;a class="reference external" href="http://cffi.readthedocs.io/en/latest/"&gt;CFFI&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Pymunk gives us a lot of the tools we need to create a 2D game. For a start it
prevents the player character moving through walls. But it also gives us
collision events that we can attach Python code to, such as when a bullet hits
an enemy.&lt;/p&gt;
&lt;p&gt;It lets us do ray queries to test for objects hit by our railgun rays. We get
some great effects for free, such bouncing bullets or what happens when the
player character collides with crates:&lt;/p&gt;
&lt;video width="608" height="832" controls&gt;
    &lt;source src="http://mauveweb.co.uk/2018/msa-physics.webm" type="video/webm"&gt;
    Your browser does not support WEBM video.
&lt;/source&gt;&lt;/video&gt;&lt;/div&gt;
&lt;div class="section" id="lightvolume"&gt;
&lt;h2&gt;Lightvolume&lt;/h2&gt;
&lt;p&gt;&lt;a class="reference external" href="https://pypi.python.org/pypi/lightvolume"&gt;Lightvolume&lt;/a&gt; is the most unknown of the libraries we used - because I wrote
it during the competition!&lt;/p&gt;
&lt;p&gt;Lightvolume handles the rendering of volumetric (2D) lights. You feed it
geometry from Python and it implements the visibility algorithm described in
this &lt;a class="reference external" href="https://www.redblobgames.com/articles/visibility/"&gt;interactive article by Red Blob Games&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In fact it doesn't even implement this from scratch - it simply wraps the &lt;a class="reference external" href="https://github.com/trylock/visibility"&gt;C++
implementation of the algorithm provided by trylock on Github&lt;/a&gt;! What a cheat,
right? But this was very easy to wrap with just a little C/C++ code and CFFI
again.&lt;/p&gt;
&lt;p&gt;Lightvolume also takes care of rendering the lit area using OpenGL, meaning
that again, we don't need to funnel data managed in a native code library back
into Python. All we do with Python is feed in the lights and shadow casting
objects, and set up shaders.&lt;/p&gt;
&lt;div class="figure"&gt;
&lt;img alt="/2018/msa-lightvolume.png" src="http://mauveweb.co.uk/2018/msa-lightvolume.png"&gt;
&lt;p class="caption"&gt;A 2D lightvolume being rendered without shaders&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="why-not-try-it-yourself-in-pyweek-25"&gt;
&lt;h2&gt;Why not try it yourself in Pyweek 25?&lt;/h2&gt;
&lt;p&gt;That's what we did in Pyweek 24.&lt;/p&gt;
&lt;p&gt;But if you read this article and thought "I'd like to have a go", then fear
not!  &lt;a class="reference external" href="https://pyweek.org/25/"&gt;Pyweek 25&lt;/a&gt; is happening in April 2018, starting on April 15th, and it's
a great opportunity to try out some of these things for yourself.&lt;/p&gt;
&lt;p&gt;Join us at &lt;a class="reference external" href="https://pyweek.org/"&gt;pyweek.org&lt;/a&gt;!&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;</description><category>Games Programming</category><category>Pyweek</category><guid>http://mauveweb.co.uk/posts/2018/03/my-sincerest-apologies-teardown.html</guid><pubDate>Sun, 25 Mar 2018 17:06:14 GMT</pubDate></item><item><title>Pyweek Game Jam is 19th-26th February</title><link>http://mauveweb.co.uk/posts/2017/01/pyweek-23.html</link><dc:creator>Daniel Pope</dc:creator><description>&lt;div&gt;&lt;p&gt;The &lt;a class="reference external" href="http://www.pyweek.org/23/"&gt;23rd Pyweek games programming competition&lt;/a&gt; will run from the &lt;strong&gt;19th to
26th of February 2017&lt;/strong&gt;, from midnight to midnight (&lt;a class="reference external" href="https://www.timeanddate.com/time/aboututc.html"&gt;UTC&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;The Pyweek rules, in short, are:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Develop a game&lt;/li&gt;
&lt;li&gt;In Python (mostly, at least!)&lt;/li&gt;
&lt;li&gt;As an individual or with a team&lt;/li&gt;
&lt;li&gt;In exactly one week (or less!)&lt;/li&gt;
&lt;li&gt;From "scratch" - no personal codebases, only public, documented libraries&lt;/li&gt;
&lt;li&gt;On a theme that is selected by vote, announced at the moment the contest
starts.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Python has great libraries for programming games, both 2D and 3D, and the
flexibility of the language means you can achieve a lot in just 7 days. Pyweek
is open to programmers of all ages and experience levels, from anywhere in the
world, and it's a great way to challenge yourself and improve your skills.&lt;/p&gt;
&lt;p&gt;Games are scored by other entrants, on criteria of &lt;strong&gt;fun, production and
innovation&lt;/strong&gt;, and you'll have to think about all three to be in with a chance of
winning! It's a free competition though, so your prize is recognition :-)&lt;/p&gt;
&lt;p&gt;Here's what you need to do if you want to take part:&lt;/p&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;Sign up/login at &lt;a class="reference external" href="http://www.pyweek.org/"&gt;http://www.pyweek.org/&lt;/a&gt;, and then "Register an entry" at the
top-right.&lt;/li&gt;
&lt;li&gt;Familiarise yourself with some of the &lt;a class="reference external" href="https://pyweek.org/d/4008/"&gt;libraries and resources&lt;/a&gt; you can
use to make games.&lt;/li&gt;
&lt;li&gt;Join the IRC Channel, &lt;tt class="docutils literal"&gt;#pyweek&lt;/tt&gt; on &lt;a class="reference external" href="http://freenode.net"&gt;Freenode&lt;/a&gt;, for discussion and advice.&lt;/li&gt;
&lt;li&gt;Play some of the &lt;a class="reference external" href="http://www.pyweek.org/all_games/"&gt;previous entries&lt;/a&gt; at the Pyweek.org site.&lt;/li&gt;
&lt;li&gt;Why not post a &lt;a class="reference external" href="https://pyweek.org/23/diaries/"&gt;diary entry&lt;/a&gt; (from your entry page), introducing yourself
and your team?&lt;/li&gt;
&lt;li&gt;Put a "save the date" in your calendar! Theme voting starts 2017-02-12, and
the competition the week after, 2017-02-19 00:00 UTC.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Have fun, and good luck!&lt;/p&gt;&lt;/div&gt;</description><category>Pyweek</category><guid>http://mauveweb.co.uk/posts/2017/01/pyweek-23.html</guid><pubDate>Thu, 26 Jan 2017 19:49:36 GMT</pubDate></item><item><title>Pyweek 21 is one week away, 28th February-6th March 2016</title><link>http://mauveweb.co.uk/posts/2016/02/pyweek-21.html</link><dc:creator>Daniel Pope</dc:creator><description>&lt;div&gt;&lt;p&gt;The &lt;a class="reference external" href="https://pyweek.org/21/"&gt;next Pyweek competition&lt;/a&gt; will run from 00:00 UTC on Sunday 28th February
to 00:00 UTC on Sunday 6th March. &lt;strong&gt;That's next week!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Pyweek is a week-long games programming competition in which participants are
challenged to write a game, from scratch, in a week, in Python.&lt;/p&gt;
&lt;p&gt;This week, we vote on themes! The possible themes can be interpreted however
you like:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;em&gt;Jump in line&lt;/em&gt; - you could do a Dance Dance Revolution-style game with cute
animals&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Showtime!&lt;/em&gt; - perhaps a business sim in which you run a TV network?&lt;/li&gt;
&lt;li&gt;&lt;em&gt;The aftermath&lt;/em&gt; - clean up the mess from a house party before your parents
get home.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;The incantation&lt;/em&gt; - players enter a TV talent show to prove they are the best
spell-caster. Each week one is voted off! Featuring Will.i.am.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;In the model&lt;/em&gt; - this naturally lends itself to a totally awesome game in
which you have to develop a Python script with &lt;tt class="docutils literal"&gt;sklearn&lt;/tt&gt; to solve exciting
big data problems! With cute animals!&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;But seriously, if these theme ideas get your creative juices flowing, and you
have spare time to write a game next week, why not &lt;strong&gt;register an entry and give
it a go?&lt;/strong&gt;&lt;/p&gt;&lt;/div&gt;</description><category>Pyweek</category><guid>http://mauveweb.co.uk/posts/2016/02/pyweek-21.html</guid><pubDate>Sun, 21 Feb 2016 12:25:34 GMT</pubDate></item><item><title>Pyweek 20 announced, 9th-15th August 2015</title><link>http://mauveweb.co.uk/posts/2015/07/pyweek-20.html</link><dc:creator>Daniel Pope</dc:creator><description>&lt;div&gt;&lt;p&gt;The &lt;a class="reference external" href="https://pyweek.org/20/"&gt;next Pyweek competition&lt;/a&gt; has been announced, and will run from 00:00 UTC
on Sunday 9th August to 00:00 UTC on Sunday 16th August.&lt;/p&gt;
&lt;p&gt;Pyweek is a week-long games programming competition in which participants are
challenged to write a game, from scratch, in a week. You can enter as a team or
as an individual, and it's a great way to improve your experience with Python
and express your creativity at the same time.&lt;/p&gt;
&lt;p&gt;If writing a game seems like a daunting challenge, check out &lt;a class="reference external" href="http://pygame-zero.readthedocs.org/"&gt;Pygame Zero&lt;/a&gt;,
a zero-boilerplate game framework that can help you get up and running more
quickly.&lt;/p&gt;
&lt;p&gt;Due to various circumstances this has been delayed somewhat, and is now being
announced at somewhat short notice. Be aware that this means that theme voting
begins &lt;strong&gt;this Sunday&lt;/strong&gt;, 2nd August.&lt;/p&gt;&lt;/div&gt;</description><category>Pyweek</category><guid>http://mauveweb.co.uk/posts/2015/07/pyweek-20.html</guid><pubDate>Tue, 28 Jul 2015 07:22:52 GMT</pubDate></item><item><title>Pyweek 19 / Animations</title><link>http://mauveweb.co.uk/posts/2014/09/animations.html</link><dc:creator>Daniel Pope</dc:creator><description>&lt;div&gt;&lt;p&gt;&lt;a class="reference external" href="https://www.pyweek.org/19/"&gt;Pyweek 19&lt;/a&gt; is coming up in October, running from Sunday 5th (00:00 UTC) to
Sunday 12th (again, 00:00 UTC). Pyweek is a games programming contest in which
you have exactly one week to develop a game in Python, on a theme that is
selected by vote and announced at the moment the contest starts.&lt;/p&gt;
&lt;p&gt;You don't need to have a great deal of games programming savvy to take part:
whatever your level you'll find it fun and informative to program along with
other entrants, exchanging your experiences on the &lt;a class="reference external" href="https://www.pyweek.org/18/diaries/"&gt;challenge blog&lt;/a&gt; (link is
to the previous challenge).&lt;/p&gt;
&lt;p&gt;I'd encourage everyone to take part, either individually or as a team, because
there's a lot you can learn, about games programming and software development
generally.&lt;/p&gt;
&lt;p&gt;In celebration of the upcoming Pyweek, here's a little primer on how to write
an animation display system.&lt;/p&gt;
&lt;div class="section" id="animations"&gt;
&lt;h2&gt;Animations&lt;/h2&gt;
&lt;p&gt;An animation is made up of a set of frames, like these from &lt;a class="reference external" href="https://www.pyweek.org/e/wasabiparatha/"&gt;Last Train to
Nowhere&lt;/a&gt;:&lt;/p&gt;
&lt;img alt="/2014/animation-frames.png" src="http://mauveweb.co.uk/2014/animation-frames.png"&gt;
&lt;p&gt;Frames could be 2D sprites or 3D meshes, but for simplicity, let's assume
sprites. I always draw my sprites, but you can find &lt;a class="reference external" href="https://www.google.com/search?q=free+sprite+sheet&amp;amp;tbm=isch"&gt;sprite sheets on the
web&lt;/a&gt; if you're less confident in your art skills.&lt;/p&gt;
&lt;p&gt;Playing the animation in a game involves displaying one frame after another, at
the right place on the screen, so that the action looks smooth.&lt;/p&gt;
&lt;p&gt;First of all, let's look at the typical requirements for such a piece of code:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;It needs to be able to draw multiple copies of the same animation, each at
different frames and positions.&lt;/li&gt;
&lt;li&gt;It needs to be cycle through the frames at a certain rate, which will usually
be &lt;em&gt;slower&lt;/em&gt; than the rate I'm redrawing the entire game screen.&lt;/li&gt;
&lt;li&gt;It needs to draw each frame the right places relative to a fixed "insertion
point". That is, if the game treats the animation as being "at" a point &lt;tt class="docutils literal"&gt;(x,
y)&lt;/tt&gt;, then the frames should be drawn at an offset &lt;tt class="docutils literal"&gt;(x + ox, y + oy)&lt;/tt&gt; that
will cause them to appear in the right place. The offset vector &lt;tt class="docutils literal"&gt;(ox, oy)&lt;/tt&gt;
may vary between frames if the sprites are different sizes.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Another feature I've found useful in the past is to be able to select from a
number of different animations to "play" at the appropriate moment. So rather
than needing to create a new animation object to play a different sequence of
frames, I just instruct the animation to play a different named sequence:&lt;/p&gt;
&lt;pre class="code python"&gt;&lt;a name="rest_code_fea3e86bc4554cf6bde442825351f2e2-1"&gt;&lt;/a&gt;&lt;span class="n"&gt;anim&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;play&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'jump'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;p&gt;The chief benefit of this is that I can preconfigure what happens when
animations end. Some animations will loop - such as a running animation. Other
animations will segue into another animation - for example, shooting might run
for a few frames and then return to standing.&lt;/p&gt;
&lt;p&gt;The best approach for a system like this is with the &lt;a class="reference external" href="http://en.wikipedia.org/wiki/Flyweight_pattern"&gt;flyweight pattern&lt;/a&gt;.
Using the flyweight pattern we can split our animation system into two classes:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;The &lt;tt class="docutils literal"&gt;Animation&lt;/tt&gt; class will contain all the details of an animation: the
sprite sequences, per-sprites offsets, frame rates, details of what happens
when each sequence finishes, and so on. It's basically a collection of data
so it doesn't need many methods.&lt;/li&gt;
&lt;li&gt;The &lt;tt class="docutils literal"&gt;Animation Instance&lt;/tt&gt; class will refer to the &lt;tt class="docutils literal"&gt;Animation&lt;/tt&gt; for all of
the data it holds, and include just a few instance variables, things like the
current frame and coordinates of the animation on the screen. This will need
a lot more code, because your game code will move it around, draw it, and
tell it to play different animation sequences.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So the API for our solution might look something like this:&lt;/p&gt;
&lt;pre class="code python"&gt;&lt;a name="rest_code_d411357a71614d95863a63221be78c15-1"&gt;&lt;/a&gt;&lt;span class="c1"&gt;# A sprite and the (x, y) position at which it should be drawn, relative&lt;/span&gt;
&lt;a name="rest_code_d411357a71614d95863a63221be78c15-2"&gt;&lt;/a&gt;&lt;span class="c1"&gt;# to the animation instance&lt;/span&gt;
&lt;a name="rest_code_d411357a71614d95863a63221be78c15-3"&gt;&lt;/a&gt;&lt;span class="n"&gt;Frame&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;namedtuple&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Frame'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'sprite offset'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a name="rest_code_d411357a71614d95863a63221be78c15-4"&gt;&lt;/a&gt;
&lt;a name="rest_code_d411357a71614d95863a63221be78c15-5"&gt;&lt;/a&gt;&lt;span class="c1"&gt;# Sentinel value to indicate looping until told to stop, rather than&lt;/span&gt;
&lt;a name="rest_code_d411357a71614d95863a63221be78c15-6"&gt;&lt;/a&gt;&lt;span class="c1"&gt;# switching to a different animation&lt;/span&gt;
&lt;a name="rest_code_d411357a71614d95863a63221be78c15-7"&gt;&lt;/a&gt;&lt;span class="n"&gt;loop&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;object&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;a name="rest_code_d411357a71614d95863a63221be78c15-8"&gt;&lt;/a&gt;
&lt;a name="rest_code_d411357a71614d95863a63221be78c15-9"&gt;&lt;/a&gt;&lt;span class="c1"&gt;# A list of of frames plus the name of the next sequence to play when the&lt;/span&gt;
&lt;a name="rest_code_d411357a71614d95863a63221be78c15-10"&gt;&lt;/a&gt;&lt;span class="c1"&gt;# animation ends.&lt;/span&gt;
&lt;a name="rest_code_d411357a71614d95863a63221be78c15-11"&gt;&lt;/a&gt;&lt;span class="c1"&gt;#&lt;/span&gt;
&lt;a name="rest_code_d411357a71614d95863a63221be78c15-12"&gt;&lt;/a&gt;&lt;span class="c1"&gt;# Set next_sequence to ``loop`` to make the animation loop forever.&lt;/span&gt;
&lt;a name="rest_code_d411357a71614d95863a63221be78c15-13"&gt;&lt;/a&gt;&lt;span class="n"&gt;Sequence&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;namedtuple&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Sequence'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'frames next_sequence'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a name="rest_code_d411357a71614d95863a63221be78c15-14"&gt;&lt;/a&gt;
&lt;a name="rest_code_d411357a71614d95863a63221be78c15-15"&gt;&lt;/a&gt;
&lt;a name="rest_code_d411357a71614d95863a63221be78c15-16"&gt;&lt;/a&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Animation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a name="rest_code_d411357a71614d95863a63221be78c15-17"&gt;&lt;/a&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sequences&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;frame_rate&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;DEFAULT_FRAME_RATE&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a name="rest_code_d411357a71614d95863a63221be78c15-18"&gt;&lt;/a&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sequences&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sequences&lt;/span&gt;
&lt;a name="rest_code_d411357a71614d95863a63221be78c15-19"&gt;&lt;/a&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;frame_rate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;frame_rate&lt;/span&gt;
&lt;a name="rest_code_d411357a71614d95863a63221be78c15-20"&gt;&lt;/a&gt;
&lt;a name="rest_code_d411357a71614d95863a63221be78c15-21"&gt;&lt;/a&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create_instance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pos&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)):&lt;/span&gt;
&lt;a name="rest_code_d411357a71614d95863a63221be78c15-22"&gt;&lt;/a&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;AnimationInstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pos&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;direction&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a name="rest_code_d411357a71614d95863a63221be78c15-23"&gt;&lt;/a&gt;
&lt;a name="rest_code_d411357a71614d95863a63221be78c15-24"&gt;&lt;/a&gt;
&lt;a name="rest_code_d411357a71614d95863a63221be78c15-25"&gt;&lt;/a&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AnimationInstance&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a name="rest_code_d411357a71614d95863a63221be78c15-26"&gt;&lt;/a&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;animation&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pos&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)):&lt;/span&gt;
&lt;a name="rest_code_d411357a71614d95863a63221be78c15-27"&gt;&lt;/a&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;animation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;animation&lt;/span&gt;
&lt;a name="rest_code_d411357a71614d95863a63221be78c15-28"&gt;&lt;/a&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pos&lt;/span&gt;
&lt;a name="rest_code_d411357a71614d95863a63221be78c15-29"&gt;&lt;/a&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;play&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'default'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# Start default sequence&lt;/span&gt;
&lt;a name="rest_code_d411357a71614d95863a63221be78c15-30"&gt;&lt;/a&gt;        &lt;span class="n"&gt;clock&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;register_interval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;next_frame&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;animation&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;frame_rate&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a name="rest_code_d411357a71614d95863a63221be78c15-31"&gt;&lt;/a&gt;
&lt;a name="rest_code_d411357a71614d95863a63221be78c15-32"&gt;&lt;/a&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;play&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sequence_name&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a name="rest_code_d411357a71614d95863a63221be78c15-33"&gt;&lt;/a&gt;        &lt;span class="sd"&gt;"""Start playing the given sequence at the beginning."""&lt;/span&gt;
&lt;a name="rest_code_d411357a71614d95863a63221be78c15-34"&gt;&lt;/a&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;currentframe&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;a name="rest_code_d411357a71614d95863a63221be78c15-35"&gt;&lt;/a&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sequence&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;animation&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sequences&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;sequence_name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;a name="rest_code_d411357a71614d95863a63221be78c15-36"&gt;&lt;/a&gt;
&lt;a name="rest_code_d411357a71614d95863a63221be78c15-37"&gt;&lt;/a&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;next_frame&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a name="rest_code_d411357a71614d95863a63221be78c15-38"&gt;&lt;/a&gt;        &lt;span class="sd"&gt;"""Called by the clock to increment the frame number."""&lt;/span&gt;
&lt;a name="rest_code_d411357a71614d95863a63221be78c15-39"&gt;&lt;/a&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;currentframe&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;a name="rest_code_d411357a71614d95863a63221be78c15-40"&gt;&lt;/a&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;currentframe&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sequence&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;frames&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a name="rest_code_d411357a71614d95863a63221be78c15-41"&gt;&lt;/a&gt;            &lt;span class="nb"&gt;next&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sequence&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;next_sequence&lt;/span&gt;
&lt;a name="rest_code_d411357a71614d95863a63221be78c15-42"&gt;&lt;/a&gt;            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;next&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="n"&gt;loop&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a name="rest_code_d411357a71614d95863a63221be78c15-43"&gt;&lt;/a&gt;                &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;currentframe&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;a name="rest_code_d411357a71614d95863a63221be78c15-44"&gt;&lt;/a&gt;            &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a name="rest_code_d411357a71614d95863a63221be78c15-45"&gt;&lt;/a&gt;                &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;play&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a name="rest_code_d411357a71614d95863a63221be78c15-46"&gt;&lt;/a&gt;
&lt;a name="rest_code_d411357a71614d95863a63221be78c15-47"&gt;&lt;/a&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;draw&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a name="rest_code_d411357a71614d95863a63221be78c15-48"&gt;&lt;/a&gt;        &lt;span class="sd"&gt;"""Draw the animation at coordinates given by self.pos.&lt;/span&gt;
&lt;a name="rest_code_d411357a71614d95863a63221be78c15-49"&gt;&lt;/a&gt;
&lt;a name="rest_code_d411357a71614d95863a63221be78c15-50"&gt;&lt;/a&gt;&lt;span class="sd"&gt;        The current frame will be drawn at its corresponding offset.&lt;/span&gt;
&lt;a name="rest_code_d411357a71614d95863a63221be78c15-51"&gt;&lt;/a&gt;
&lt;a name="rest_code_d411357a71614d95863a63221be78c15-52"&gt;&lt;/a&gt;&lt;span class="sd"&gt;        """&lt;/span&gt;
&lt;a name="rest_code_d411357a71614d95863a63221be78c15-53"&gt;&lt;/a&gt;        &lt;span class="n"&gt;frame&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sequence&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;frames&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;currentframe&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;a name="rest_code_d411357a71614d95863a63221be78c15-54"&gt;&lt;/a&gt;        &lt;span class="n"&gt;ox&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;oy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;frame&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;offset&lt;/span&gt;
&lt;a name="rest_code_d411357a71614d95863a63221be78c15-55"&gt;&lt;/a&gt;        &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pos&lt;/span&gt;
&lt;a name="rest_code_d411357a71614d95863a63221be78c15-56"&gt;&lt;/a&gt;        &lt;span class="n"&gt;frame&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sprite&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;draw&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pos&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;ox&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;oy&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;a name="rest_code_d411357a71614d95863a63221be78c15-57"&gt;&lt;/a&gt;
&lt;a name="rest_code_d411357a71614d95863a63221be78c15-58"&gt;&lt;/a&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;destroy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a name="rest_code_d411357a71614d95863a63221be78c15-59"&gt;&lt;/a&gt;        &lt;span class="n"&gt;clock&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;unregister_interval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;next_frame&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;p&gt;This would allow you to define a fully-animated game character with a number of
animation sequences and transitions:&lt;/p&gt;
&lt;pre class="code python"&gt;&lt;a name="rest_code_e41f390ddf984a3994b4e772203423c3-1"&gt;&lt;/a&gt;&lt;span class="n"&gt;player_character&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Animation&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
&lt;a name="rest_code_e41f390ddf984a3994b4e772203423c3-2"&gt;&lt;/a&gt;    &lt;span class="s1"&gt;'default'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Sequence&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;loop&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;a name="rest_code_e41f390ddf984a3994b4e772203423c3-3"&gt;&lt;/a&gt;    &lt;span class="s1"&gt;'running'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Sequence&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;loop&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;a name="rest_code_e41f390ddf984a3994b4e772203423c3-4"&gt;&lt;/a&gt;    &lt;span class="s1"&gt;'jumping'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Sequence&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'default'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;a name="rest_code_e41f390ddf984a3994b4e772203423c3-5"&gt;&lt;/a&gt;    &lt;span class="s1"&gt;'dying'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Sequence&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'dead'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;a name="rest_code_e41f390ddf984a3994b4e772203423c3-6"&gt;&lt;/a&gt;    &lt;span class="s1"&gt;'dead'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Sequence&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;loop&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a name="rest_code_e41f390ddf984a3994b4e772203423c3-7"&gt;&lt;/a&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/pre&gt;&lt;p&gt;You'd have to find a suitable clock object to ensure &lt;tt class="docutils literal"&gt;next_frame()&lt;/tt&gt; is called
at the right rate. Pyglet has just such a &lt;a class="reference external" href="http://www.pyglet.org/doc/api/pyglet.clock.Clock-class.html"&gt;Clock class&lt;/a&gt;; Pygame doesn't, but
there might be &lt;a class="reference external" href="http://www.pygame.org/wiki/ConstantGameSpeed"&gt;suitable classes&lt;/a&gt; in the &lt;a class="reference external" href="http://www.pygame.org/wiki/CookBook"&gt;Pygame Cookbook&lt;/a&gt;. (Take care that
the &lt;tt class="docutils literal"&gt;next_frame()&lt;/tt&gt; method gets unscheduled when the animation is destroyed -
note the &lt;tt class="docutils literal"&gt;destroy()&lt;/tt&gt; method above. You'll need to call &lt;tt class="docutils literal"&gt;destroy()&lt;/tt&gt;, or use
weakrefs, to avoid keeping references to dead objects and "leak" memory.)&lt;/p&gt;
&lt;p&gt;There's potentially a lot of metadata there about the various animation
sequences, offsets and so on. You might want to load it from a JSON file rather
than declaring it in Python - that way opens it up to writing some quick tools
to create or preview the animations.&lt;/p&gt;
&lt;p&gt;Next, you need to create the flyweight instance and play the right animations
as your character responds to game events - perhaps you'd wrap a class around
it like this:&lt;/p&gt;
&lt;pre class="code python"&gt;&lt;a name="rest_code_b7b1937c76b04a899c3042ce1d779e83-1"&gt;&lt;/a&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Player&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;a name="rest_code_b7b1937c76b04a899c3042ce1d779e83-2"&gt;&lt;/a&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a name="rest_code_b7b1937c76b04a899c3042ce1d779e83-3"&gt;&lt;/a&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;anim&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;player_character&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create_instance&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;a name="rest_code_b7b1937c76b04a899c3042ce1d779e83-4"&gt;&lt;/a&gt;
&lt;a name="rest_code_b7b1937c76b04a899c3042ce1d779e83-5"&gt;&lt;/a&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;jump&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a name="rest_code_b7b1937c76b04a899c3042ce1d779e83-6"&gt;&lt;/a&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;anim&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;play&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'jumping'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;a name="rest_code_b7b1937c76b04a899c3042ce1d779e83-7"&gt;&lt;/a&gt;
&lt;a name="rest_code_b7b1937c76b04a899c3042ce1d779e83-8"&gt;&lt;/a&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a name="rest_code_b7b1937c76b04a899c3042ce1d779e83-9"&gt;&lt;/a&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;anim&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pos&lt;/span&gt;
&lt;a name="rest_code_b7b1937c76b04a899c3042ce1d779e83-10"&gt;&lt;/a&gt;
&lt;a name="rest_code_b7b1937c76b04a899c3042ce1d779e83-11"&gt;&lt;/a&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;draw&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;a name="rest_code_b7b1937c76b04a899c3042ce1d779e83-12"&gt;&lt;/a&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;anim&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;draw&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;p&gt;I've used this basic pattern in a &lt;a class="reference external" href="https://www.pyweek.org/u/mauve/"&gt;fair number of games&lt;/a&gt;. There are lots of
different ways to extend it. Your requirements will depend on the kind of game
you're writing. Here are a couple of ideas:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;You might want the flyweight instances to be able to flip or rotate the
animation. You might store a &lt;tt class="docutils literal"&gt;direction&lt;/tt&gt; flag or &lt;tt class="docutils literal"&gt;angle&lt;/tt&gt; variable.&lt;/li&gt;
&lt;li&gt;You might want to be able to register arbitrary callback functions, to be
called when an animation finishes. This would allow game events to be cued
from the animations, which will help to make sure everything syncs up, even
as you change the animations.&lt;/li&gt;
&lt;li&gt;You could use vector graphics of some sort, and interpolate between keyframes
rather than selecting just one frame to show. This would offer smoother
animation, but you'd need good tooling to create the animations (tools like
&lt;a class="reference external" href="http://esotericsoftware.com/"&gt;Spine&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;I've assumed some sort of global clock object. You might want to link
animations to a specific clock that you control. This would allow you to
pause the animations when the game is paused, by pausing the animation clock.
You could go more advanced and manipulate the speed at which the clock runs
to do cool time-bending effects.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Have fun coding, and I hope to see your animations in Pyweek!&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;</description><category>Games Programming</category><category>Pyweek</category><guid>http://mauveweb.co.uk/posts/2014/09/animations.html</guid><pubDate>Wed, 10 Sep 2014 21:00:00 GMT</pubDate></item><item><title>Pyweek 18 announced</title><link>http://mauveweb.co.uk/posts/2014/03/pyweek-18.html</link><dc:creator>Daniel Pope</dc:creator><description>&lt;div&gt;&lt;p&gt;&lt;a class="reference external" href="http://www.pyweek.org/18/"&gt;Pyweek 18&lt;/a&gt; was announced last week, to run from the 11th May to 18th May
2014, midnight to midnight (UTC).&lt;/p&gt;
&lt;p&gt;Pyweek is a bi-annual games programming contest in which teams or individuals
compete to develop a game, in Python, from scratch, in exactly one week, on a
theme that is selected by vote and announced at the moment the contest
starts.&lt;/p&gt;
&lt;p&gt;The contest offers the opportunity to program alongside other Python
programmers on a level playing field, with teams diarising their progress via
the pyweek.org site, as well as chatting on IRC (&lt;tt class="docutils literal"&gt;#pyweek&lt;/tt&gt; on &lt;a class="reference external" href="http://freenode.net"&gt;Freenode&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Games are scored by other entrants, on criteria of fun, production and
innovation, and it's a hectic juggling act to achieve all three in the limited
time available.&lt;/p&gt;
&lt;p&gt;It's open to all, and very beginner friendly. You don't need a team, you don't
need finely honed artistic ability, and you don't need to set aside the whole
week - &lt;a class="reference external" href="http://www.pyweek.org/e/Tee-py15/"&gt;winning games&lt;/a&gt; have been created in less than a day. I'd encourage
you to take part: it's a great opportunity to explore your creative potential
and learn something new.&lt;/p&gt;
&lt;p&gt;Browse (and play) the &lt;a class="reference external" href="http://www.pyweek.org/all_games/"&gt;previous entries&lt;/a&gt; at the Pyweek.org site.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Pyweek 18 kicks off with the theme voting starting at 2014-05-04 00:00 UTC.&lt;/strong&gt;&lt;/p&gt;&lt;/div&gt;</description><category>Pyweek</category><guid>http://mauveweb.co.uk/posts/2014/03/pyweek-18.html</guid><pubDate>Sun, 23 Mar 2014 10:53:32 GMT</pubDate></item><item><title>Interview: Andy Kelley of Superjoe Software</title><link>http://mauveweb.co.uk/posts/2011/05/interview-superjoe.html</link><dc:creator>Daniel Pope</dc:creator><description>&lt;div&gt;&lt;p&gt;Andrew Kelley graduated with a degree in Computer Science from Arizona State
University last Thursday. He loves programming, game development, and
&lt;a class="reference external" href="http://theburningawesome.bandcamp.com/"&gt;composing electronic music&lt;/a&gt;. In two months, he's starting work for Amazon in
Seattle. Oh, and his entry, &lt;a class="reference external" href="http://pyweek.org/e/superjoe/"&gt;Lemming&lt;/a&gt;, was voted the winning solo
entry in the &lt;a class="reference external" href="http://pyweek.org/12/"&gt;latest Pyweek competition&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Congratulations on your PyWeek win - and with your first PyWeek entry too! Did it come as a surprise or were you feeling fairly confident?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Thank you!&lt;/p&gt;
&lt;p&gt;I knew I would rank at least up in the top few games, simply because I was in that beautiful stage of freelancing where you have just finished a job, have plenty of money in the bank, and don't have to work for a while. With only 2 classes and no girlfriend I was able to spend upwards of 90 hours on the game. I think that's probably a bit more time than most other contestants had.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Have you written many Python games before?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This was my first Python (and Pyglet) game. I have a few &lt;a class="reference external" href="http://superjoesoftware.com/games/"&gt;really old Flash
games online&lt;/a&gt; though. First game ever was in VB6, and the platform I've
written the most games for is probably TI-83 (I had a long bus ride home back
in high school).&lt;/p&gt;
&lt;p&gt;Writing a game in Python was interesting. It's perfect for a rapid development competition like this - Python is fantastic with the arbitrary data structures you often need to solve one-off quick problems in game programming. On the other hand, I &lt;em&gt;did&lt;/em&gt; experience some loss in CPU efficiency in my physics loop that writing it in C or C++ probably would have improved.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What would you say are most important lessons you learned through developing Lemming?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Do not write a level editor during PyWeek&lt;/em&gt;. I did this the first day, and then
&lt;a class="reference external" href="https://github.com/superjoe30/lemming/commit/1bdb8117898ecd2604e0d6a163566046bf303934"&gt;scrapped pretty much all my day 1 code on day 2&lt;/a&gt; in favor of &lt;a class="reference external" href="http://www.mapeditor.org/"&gt;Tiled&lt;/a&gt; and
DR0ID's &lt;a class="reference external" href="https://code.google.com/p/pytmxloader/"&gt;tiledtmxloader&lt;/a&gt;. I'm very happy that I made that decision.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Reserve a non-trivial chunk of time for playtesting on friends and family&lt;/em&gt; -
people who aren't a part of the development effort. You'll get a sneak peak of
what everyone is going to complain about when they judge your game, and hence a
chance to prevent that. Or even better, you'll get a preview of how judges will
praise your game, and you can use that knowledge to expand upon that aspect.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Start 'em off really easy&lt;/em&gt;. The way your gameplay works to you is obvious,
since you conceptualized and coded it. Not so for someone who hasn't seen your
game yet. You don't want judges to get stuck on level 2 and give up, never to
see all the cool stuff in levels 3 and above. There's a time and a place for
really hard, difficult gameplay, and that is after the player has proven that
they are ready for it. I think Loopback executed this perfectly with their
difficulty modes. After playing on easy and getting the hang of it, you can
move on to challenging for the really interesting gameplay.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Find good tools and practice before PyWeek&lt;/em&gt;. It shouldn't be a pain in the
butt to create art, animations, and levels for your game. If it is, keep
looking. You need good tools that stay out of your way so you can have more
time developing and less time fighting with tools.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Was your original idea anything like the final submission or did it change a
lot in the making?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;According to my &lt;a class="reference external" href="https://github.com/superjoe30/lemming/blob/master/ideas/theme-brainstorming"&gt;theme brainstorming document&lt;/a&gt;, my original idea was for the
&lt;em&gt;Fry Cook on Venus&lt;/em&gt; possible theme, "You're a french fry leading a stampede of
lemming french fries. When you die control transfers to the next one behind
you. Your death affects the environment."&lt;/p&gt;
&lt;p&gt;When it came time to think of ideas for Nine Times, I thought, "The french fry
game but with only 9 of you. And let's use lemmings instead of french fries."&lt;/p&gt;
&lt;p&gt;So I pretty much implemented my original idea exactly, but the idea was
purposefully vague enough to expand into the different possibilities that came
out of it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What in the world is that main character supposed to be, anyway?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I have no idea. Guesses people have made include "CigarMan", "Dog Poo on Fire
...Man", "The Sausage King from &lt;a class="reference external" href="http://pyweek.org/p/16/"&gt;one of the other PyWeek theme proposals&lt;/a&gt;"
and "The Peperami Guy". I'm no artist. To me he's just a really happy brown
rectangle with a death wish.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;How did you design the gameplay elements?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The process for inventing gameplay went something like this:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Roughly &lt;a class="reference external" href="http://superjoesoftware.com/temp/lemming-factory-sketch.jpg"&gt;sketch a level idea on paper&lt;/a&gt;, with gameplay concepts that I haven't programmed yet.&lt;/li&gt;
&lt;li&gt;Simultaneously create the art and code for the gameplay elements I had sketched out - make them work.&lt;/li&gt;
&lt;li&gt;Use Tiled to actually build the level I had sketched, utilizing the new art and code.&lt;/li&gt;
&lt;li&gt;Repeat. I only ended up going through 2 iterations.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;In the reviews, your level design was praised - and cursed! ;-) - in equal
measure. Was the level design something you put a lot of effort into?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Level design is really important to me. I think it can make or break a game.
This is why doing most of the level design in crunch time was my biggest
mistake. With half of the last day left, I only had 1 really hard grassy-hill
themed level, and 1 really hard factory themed level.&lt;/p&gt;
&lt;p&gt;I actually split the original level 1 into what is now levels 1, 2, and 3, in
order to make them easier. Level 1 is fine, but everybody still gets stuck on
levels 2 and 3. What this means is that my concept of difficulty was way off. I
should have had more people playtest the game so that they could tell me it was
too hard and so that I could make the difficulty ramp up more slowly, while
still introducing cool gameplay concepts.&lt;/p&gt;
&lt;p&gt;One of the pieces of feedback on the levels that really struck home for me was
this: &lt;em&gt;"The later levels of your walkthrough remind me of a Rube Goldberg
device with the player getting flung hither and thither with no idea of what to
expect next. That's not something it's really feasible to master."&lt;/em&gt; This
comment is spot-on. I fell into a trap - I wanted to show off how capable and
bug-free my physics engine was by making levels as complicated as possible.
There is a time and a place for that, but in the case of Lemming the commenter
is right, it happened far too much.&lt;/p&gt;
&lt;p&gt;I think that as is, the current 9 levels only expose about 10% of the cool
gameplay and puzzle levels you could achieve, with already existing code. Since
time is a zero-sum game during PyWeek, this means I should have spent less time
developing gameplay elements and more time level designing. &lt;a class="reference external" href="http://www.pyweek.org/e/multifac/"&gt;Fractured Soul&lt;/a&gt;
pulled off this balance beautifully. They have a pretty simple gameplay -
there's not much more to it than jumping and placing 9 statues in each level.
Yet they have a ton of wonderfully crafted puzzles that keep the game fresh.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What would you have added or changed if you'd had another week to work on
Lemming?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Well, I &lt;em&gt;have&lt;/em&gt; had another few weeks to work on Lemming, and I've done
absolutely nothing, so I guess that's the honest answer. But hypothetically,
the next few things I would add would be more levels, a better victory sound,
more level themes and gameplay elements, more ways to die. I'd improve the
level design, tweak various physics variables, like turning friction down, and
fix some bugs!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Do you have any other projects you're working on?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Yes! Notably, &lt;a class="reference external" href="https://github.com/superjoe30/mineflayer"&gt;mineflayer&lt;/a&gt;, a bot framework for &lt;a class="reference external" href="http://www.minecraft.net/"&gt;MineCraft&lt;/a&gt;. Mineflayer makes
it dead simple to create MineCraft bots in JavaScript.&lt;/p&gt;
&lt;p&gt;I'm in the middle of refactoring it into a library so that we can kind of merge
projects with &lt;a class="reference external" href="https://github.com/Charged/Miners"&gt;Charged Miners&lt;/a&gt;, an OpenGL MineCraft viewer. Together this will
provide an alternate client for people to play MineCraft with.&lt;/p&gt;
&lt;p&gt;We hang out in #mcdevs on freenode. It's a pretty fun channel.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What aspects attract you about MineCraft?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I think the idea of starting out weak and vulnerable, but by slowly working
your way up, you can become strong and powerful, is a big part of it. It's
interesting how none of that is by "leveling up" but actually by moving,
placing, and/or physically acquiring certain objects is what makes you strong
and powerful. It's nothing inherent.&lt;/p&gt;
&lt;p&gt;The &lt;a class="reference external" href="http://www.escapistmagazine.com/videos/view/zero-punctuation/2680-Minecraft"&gt;Zero Punctuation video&lt;/a&gt; pretty much sums it all up.&lt;/p&gt;
&lt;p&gt;Nowadays, I think the #mcdevs aspect of it is more fun than the actual game -
that is, the community of people who are making MineCraft-related projects.
Another example is &lt;a class="reference external" href="http://bravoserver.org"&gt;bravo&lt;/a&gt;, an alternate server written in Python. One of our
favorite pastimes is to gather in the IRC channel after a big MineCraft update
and complain loudly together about how bad a programmer Notch is. ;-)&lt;/p&gt;&lt;/div&gt;</description><category>Interviews</category><category>Pyweek</category><guid>http://mauveweb.co.uk/posts/2011/05/interview-superjoe.html</guid><pubDate>Sun, 15 May 2011 16:03:30 GMT</pubDate></item><item><title>Interview: Christopher Night of Team Multiverse Factory</title><link>http://mauveweb.co.uk/posts/2011/05/interview-christopher-night.html</link><dc:creator>Daniel Pope</dc:creator><description>&lt;div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;Christopher Night, aka Cosmologicon, was the director and producer on the Team Multiverse Factory entry for Pyweek 12, &lt;a href="http://www.pyweek.org/e/multifac/"&gt;Fractured Soul&lt;/a&gt;, which placed second in the team competition. Christopher has also had two previous Pyweek winners in the individual competition, &lt;a href="http://www.pyweek.org/e/unifac11/"&gt;Mortimer the Lepidopterist&lt;/a&gt; in Pyweek 11, and &lt;a href="http://www.pyweek.org/e/unifac8/"&gt;Panspermia&lt;/a&gt;, in Pyweek 8.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://themonkeyproject.wordpress.com/2011/05/13/interview-christopher-night/screenshot_2011-05-13_001551-908199/" rel="attachment wp-att-107"&gt;&lt;img src="http://themonkeyproject.files.wordpress.com/2011/05/screenshot_2011-05-13_001551-908199.png?w=150" alt="" title="screenshot_2011-05-13_00:15:51.908199" width="150" height="116" class="alignright size-thumbnail wp-image-107"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What inspires you/drives you to make games using Python?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This is probably different for me than for most people. I don't like using libraries or frameworks. I've made about 10 solo games in Python now, and I've never used anything beyond Pygame, PyOpenGL, and NumPy. What I like about Python is its highly expressive syntax and powerful standard library. Game development in, say, C++ is mature enough that everyone has a complicated framework they like, so there's little attention paid to development without one. Whereas with Python, I feel like you can jump right in.&lt;/p&gt;
&lt;p&gt;Pyweek also has a lot to do with it. I like Pyweek a lot. The scope and community are just about right for me. I originally learned Python in order to compete in Pyweek 6.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What games/genres influence you most, and how?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I don't have any conscious influences that I can think of, as in, I enjoy this game so I want to make more games like it. Games are definitely good for reference, though. When it comes to designing controls and UI, it's great to know a lot of games and understand the design choices and why they work, so that you can make the best choices for your own game. But when it comes to a core mechanic, I like to try to do something different. I actually don't play that many games, but my favorites are single-player action, adventure, and strategy games with a strong story like Zelda.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://themonkeyproject.wordpress.com/2011/05/13/interview-christopher-night/screenshot_2011-05-13_000747-897588/" rel="attachment wp-att-108"&gt;&lt;img src="http://themonkeyproject.files.wordpress.com/2011/05/screenshot_2011-05-13_000747-897588.png?w=150" alt="" title="screenshot_2011-05-13_00:07:47.897588" width="150" height="116" class="alignright size-thumbnail wp-image-108"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;I was particularly impressed by the idea of freezing yourself into statues in Fractured Soul. How did you come up with the concept?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Nothing special, I think it just came from the idea of playing through the level nine times. You can look at the entirety of the concept as it was when the game started &lt;a href="https://code.google.com/p/multifac/wiki/ThemeNineTimes"&gt;on our wiki under IDEA1&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It wasn't a unique idea, either, someone else posted &lt;a href="http://www.pyweek.org/d/3736/"&gt;basically the exact same idea we had&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Yes, actually &lt;a href="http://www.pyweek.org/e/superjoe/"&gt;superjoe's winning individual entry&lt;/a&gt; also has the concept of piling up duplicates of your character. Did you spot any really original ideas in other Pyweek entries?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Not as many as in previous Pyweeks. Lots of people did as good a job as possible with the theme ["Nine Times"], but I didn't think this theme really lent itself to much originality. The only examples of really original interpretations (IMHO) I can think of are &lt;a href="http://www.pyweek.org/e/Tee-py12/"&gt;Tee&lt;/a&gt; and &lt;a href="http://www.pyweek.org/e/why_so_Swedish/"&gt;adrwen&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://themonkeyproject.wordpress.com/2011/05/13/interview-christopher-night/screenshot_2011-05-13_000846-096837/" rel="attachment wp-att-109"&gt;&lt;img src="http://themonkeyproject.files.wordpress.com/2011/05/screenshot_2011-05-13_000846-096837.png?w=150" alt="" title="screenshot_2011-05-13_00:08:46.096837" width="150" height="116" class="alignright size-thumbnail wp-image-109"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;How did you tune the difficulty of the game?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Poorly. This is a very important issue for puzzle design, and if things had been slightly different it could have gone badly for us. We were fortunate enough to have enough content that we could make all the stages after the tutorial optional. That way if one of the levels was too hard it wouldn't break the game.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;How close to your original concept was the final submission?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The mechanics were very similar. You could see the original concept in the link above. The idea of the "counterweight" platforms came pretty early on day 1. The storyline, sound, and graphical style were pretty much absent from the original concept. They all came late in the week.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Was there anything exciting that you left on the cutting-room floor?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;There are usually features I want to add but don't have time for. That wasn't the case this time. There were several features that were somewhere between "jotted in the margin of my notes" and "implemented but disabled" that got cut, namely: double-jumping, wall-jumping, enemies, rolling boulders, water/lava whose level can change, keys, ladders, elevators, teleporters, mobile portals, switches in the ceiling, levels with bizarro mechanics, and using stones to keep objects from moving. (There's no way we would have had time to implement all of them, of course.) The reason these were cut, though, is because the game was already pretty full. I don't know about the rest of the team, but I prefer depth to breadth in gameplay. That is, really exploring a small set of mechanics rather than superficially using a larger set.&lt;/p&gt;
&lt;p&gt;One exciting non-mechanic feature we cut was the ability to record yourself playing through a level, save it to a file, and play it back. This was working midway through the week, and we used it for some playtesting, but we had to break it on the last day.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Some of those features sound brilliant - I'd love to see what puzzles you could create with water and lava. Will they ever see the light of day or is the game done and dusted now?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Yeah, we're thinking of continuing work on it, and that would include adding some mechanics. I haven't gotten around to it yet myself, but I'd like to, especially if we can get someone to work on the art.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;You've personally had winning entries in Pyweek twice. Can you speculate on the formula for a winning entry?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;So, I've entered Pyweek solo five times, and placed 7th, 1st, 9th, 4th, and 1st. That's enough to form some comparisons, and I can look at the other games and try to work out patterns.&lt;/p&gt;
&lt;p&gt;My winning entries were based on ideas I came up with early on day 1 and stuck with. Starting halfway through doesn't work, nor does forming your idea before the competition begins.&lt;/p&gt;
&lt;p&gt;I think that a winning entry tends to feel complete, even if it's not complete in your mind. One finished level leaves a better impression than three half-finished levels. If people don't know the features were planned, they won't miss them. Winning entries tend to be easy to medium difficulty.  For solo entries, winning entries tend to do more with less. Simple, retro graphics and geometric shapes are fine.&lt;/p&gt;
&lt;p&gt;But of course, I don't really believe in a winning formula. Mostly it's just making a good game. :)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;One last question. What's next for you personally, and for next PyWeek?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;As much as I like Python, I'm becoming frustrated that my games are difficult to distribute. Browser-based games get so much more coverage these days than downloadable games. If someone can get pygame running in Google Native Client or something like that, that would be great! In the meantime, I'm trying to learn HTML5 or Flash.&lt;/p&gt;
&lt;p&gt;But I'm always planning come back for Pyweek. Multiverse Factory was a very successful experiment in working on a team, from my point of view. But I don't know if I'll be entering solo or on a team next time.&lt;/p&gt;&lt;/div&gt;</description><category>Interviews</category><category>Pyweek</category><guid>http://mauveweb.co.uk/posts/2011/05/interview-christopher-night.html</guid><pubDate>Fri, 13 May 2011 12:00:57 GMT</pubDate></item></channel></rss>