655 lines
65 KiB
HTML
655 lines
65 KiB
HTML
|
|
||
|
<!DOCTYPE html>
|
||
|
|
||
|
<html>
|
||
|
<head>
|
||
|
<meta charset="utf-8" />
|
||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
|
||
|
|
||
|
<title>Pygame Tutorials - Help! How Do I Move An Image? — pygame v2.5.2 documentation</title>
|
||
|
<link rel="stylesheet" type="text/css" href="../_static/pygments.css" />
|
||
|
<link rel="stylesheet" type="text/css" href="../_static/pygame.css" />
|
||
|
<script data-url_root="../" id="documentation_options" src="../_static/documentation_options.js"></script>
|
||
|
<script src="../_static/jquery.js"></script>
|
||
|
<script src="../_static/underscore.js"></script>
|
||
|
<script src="../_static/doctools.js"></script>
|
||
|
<link rel="shortcut icon" href="../_static/pygame.ico"/>
|
||
|
<link rel="index" title="Index" href="../genindex.html" />
|
||
|
<link rel="search" title="Search" href="../search.html" />
|
||
|
<link rel="next" title="Pygame Intro" href="PygameIntro.html" />
|
||
|
<link rel="prev" title="Putting it all together" href="tom_games6.html" />
|
||
|
</head><body>
|
||
|
|
||
|
<div class="document">
|
||
|
|
||
|
<div class="header">
|
||
|
<div class="flex-container">
|
||
|
<div class="logo">
|
||
|
<a href="https://www.pygame.org/">
|
||
|
<img src="../_static/pygame_tiny.png"/>
|
||
|
</a>
|
||
|
<h5>pygame documentation</h5>
|
||
|
</div>
|
||
|
<div class="pagelinks">
|
||
|
<div class="top">
|
||
|
<a href="https://www.pygame.org/">Pygame Home</a> ||
|
||
|
<a href="../index.html">Help Contents</a> ||
|
||
|
<a href="../genindex.html">Reference Index</a>
|
||
|
|
||
|
<form action="../search.html" method="get" style="display:inline;float:right;">
|
||
|
<input name="q" value="" type="text">
|
||
|
<input value="search" type="submit">
|
||
|
</form>
|
||
|
</div>
|
||
|
<hr style="color:black;border-bottom:none;border-style: dotted;border-bottom-style:none;">
|
||
|
<p class="bottom"><b>Most useful stuff</b>:
|
||
|
<a href="../ref/color.html">Color</a> |
|
||
|
<a href="../ref/display.html">display</a> |
|
||
|
<a href="../ref/draw.html">draw</a> |
|
||
|
<a href="../ref/event.html">event</a> |
|
||
|
<a href="../ref/font.html">font</a> |
|
||
|
<a href="../ref/image.html">image</a> |
|
||
|
<a href="../ref/key.html">key</a> |
|
||
|
<a href="../ref/locals.html">locals</a> |
|
||
|
<a href="../ref/mixer.html">mixer</a> |
|
||
|
<a href="../ref/mouse.html">mouse</a> |
|
||
|
<a href="../ref/rect.html">Rect</a> |
|
||
|
<a href="../ref/surface.html">Surface</a> |
|
||
|
<a href="../ref/time.html">time</a> |
|
||
|
<a href="../ref/music.html">music</a> |
|
||
|
<a href="../ref/pygame.html">pygame</a>
|
||
|
</p>
|
||
|
|
||
|
<p class="bottom"><b>Advanced stuff</b>:
|
||
|
<a href="../ref/cursors.html">cursors</a> |
|
||
|
<a href="../ref/joystick.html">joystick</a> |
|
||
|
<a href="../ref/mask.html">mask</a> |
|
||
|
<a href="../ref/sprite.html">sprite</a> |
|
||
|
<a href="../ref/transform.html">transform</a> |
|
||
|
<a href="../ref/bufferproxy.html">BufferProxy</a> |
|
||
|
<a href="../ref/freetype.html">freetype</a> |
|
||
|
<a href="../ref/gfxdraw.html">gfxdraw</a> |
|
||
|
<a href="../ref/midi.html">midi</a> |
|
||
|
<a href="../ref/pixelarray.html">PixelArray</a> |
|
||
|
<a href="../ref/pixelcopy.html">pixelcopy</a> |
|
||
|
<a href="../ref/sndarray.html">sndarray</a> |
|
||
|
<a href="../ref/surfarray.html">surfarray</a> |
|
||
|
<a href="../ref/math.html">math</a>
|
||
|
</p>
|
||
|
|
||
|
<p class="bottom"><b>Other</b>:
|
||
|
<a href="../ref/camera.html">camera</a> |
|
||
|
<a href="../ref/sdl2_controller.html#module-pygame._sdl2.controller">controller</a> |
|
||
|
<a href="../ref/examples.html">examples</a> |
|
||
|
<a href="../ref/fastevent.html">fastevent</a> |
|
||
|
<a href="../ref/scrap.html">scrap</a> |
|
||
|
<a href="../ref/tests.html">tests</a> |
|
||
|
<a href="../ref/touch.html">touch</a> |
|
||
|
<a href="../ref/pygame.html#module-pygame.version">version</a>
|
||
|
</p>
|
||
|
</div>
|
||
|
</div>
|
||
|
</div>
|
||
|
|
||
|
<div class="documentwrapper">
|
||
|
<div class="body" role="main">
|
||
|
|
||
|
<section id="pygame-tutorials-help-how-do-i-move-an-image">
|
||
|
<section id="help-how-do-i-move-an-image">
|
||
|
<h2>Help! How Do I Move An Image?<a class="headerlink" href="#help-how-do-i-move-an-image" title="Permalink to this headline">¶</a></h2>
|
||
|
<dl class="docinfo field-list simple">
|
||
|
<dt class="field-odd">Author</dt>
|
||
|
<dd class="field-odd"><p>Pete Shinners</p>
|
||
|
</dd>
|
||
|
<dt class="field-even">Contact</dt>
|
||
|
<dd class="field-even"><p><a class="reference external" href="mailto:pete%40shinners.org">pete<span>@</span>shinners<span>.</span>org</a></p>
|
||
|
</dd>
|
||
|
</dl>
|
||
|
<p>Many people new to programming and graphics have a hard time figuring
|
||
|
out how to make an image move around the screen. Without understanding
|
||
|
all the concepts, it can be very confusing. You're not the first person
|
||
|
to be stuck here, I'll do my best to take things step by step. We'll even
|
||
|
try to end with methods of keeping your animations efficient.</p>
|
||
|
<p>Note that we won't be teaching you to program with python in this article,
|
||
|
just introduce you to some of the basics with pygame.</p>
|
||
|
<section id="just-pixels-on-the-screen">
|
||
|
<h3>Just Pixels On The Screen<a class="headerlink" href="#just-pixels-on-the-screen" title="Permalink to this headline">¶</a></h3>
|
||
|
<p>Pygame has a display Surface. This is basically an image that is visible
|
||
|
on the screen, and the image is made up of pixels. The main way you change
|
||
|
these pixels is by calling the blit() function. This copies the pixels
|
||
|
from one image onto another.</p>
|
||
|
<p>This is the first thing to understand. When you blit an image onto the
|
||
|
screen, you are simply changing the color of the pixels on the screen.
|
||
|
Pixels aren't added or moved, we just change the colors of the pixels already
|
||
|
on the screen. These images you blit to the screen are also Surfaces in
|
||
|
pygame, but they are in no way connected to the display Surface. When they
|
||
|
are blitted to the screen they are copied into the display, but you still
|
||
|
have a unique copy of the original.</p>
|
||
|
<p>With this brief description. Perhaps you can already understand what
|
||
|
is needed to "move" an image. We don't actually move anything at all. We
|
||
|
simply blit the image in a new position. But before we draw the image in
|
||
|
the new position, we'll need to "erase" the old one. Otherwise the image
|
||
|
will be visible in two places on the screen. By rapidly erasing the image
|
||
|
and redrawing it in a new place, we achieve the "illusion" of movement.</p>
|
||
|
<p>Through the rest of this tutorial we will break this process down into
|
||
|
simpler steps. Even explaining the best ways to have multiple images moving
|
||
|
around the screen. You probably already have questions. Like, how do we
|
||
|
"erase" the image before drawing it in a new position? Perhaps you're still
|
||
|
totally lost? Well hopefully the rest of this tutorial can straighten things
|
||
|
out for you.</p>
|
||
|
</section>
|
||
|
<section id="let-s-go-back-a-step">
|
||
|
<h3>Let's Go Back A Step<a class="headerlink" href="#let-s-go-back-a-step" title="Permalink to this headline">¶</a></h3>
|
||
|
<p>Perhaps the concept of pixels and images is still a little foreign to
|
||
|
you? Well good news, for the next few sections we are going to use code that
|
||
|
does everything we want, it just doesn't use pixels. We're going to create
|
||
|
a small python list of 6 numbers, and imagine it represents some fantastic
|
||
|
graphics we could see on the screen. It might actually be surprising how
|
||
|
closely this represents exactly what we'll later be doing with real graphics.</p>
|
||
|
<p>So let's begin by creating our screen list and fill it with a beautiful
|
||
|
landscape of 1s and 2s.</p>
|
||
|
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">screen</span> <span class="o">=</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">1</span><span class="p">]</span>
|
||
|
<span class="gp">>>> </span><span class="nb">print</span><span class="p">(</span><span class="n">screen</span><span class="p">)</span>
|
||
|
<span class="go">[1, 1, 2, 2, 2, 1]</span>
|
||
|
</pre></div>
|
||
|
</div>
|
||
|
<p>Now we've created our background. It's not going to be very exciting
|
||
|
unless we also draw a player on the screen. We'll create a mighty hero
|
||
|
that looks like the number 8. Let's stick him near the middle of the map
|
||
|
and see what it looks like.</p>
|
||
|
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">screen</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span> <span class="o">=</span> <span class="mi">8</span>
|
||
|
<span class="gp">>>> </span><span class="nb">print</span><span class="p">(</span><span class="n">screen</span><span class="p">)</span>
|
||
|
<span class="go">[1, 1, 2, 8, 2, 1]</span>
|
||
|
</pre></div>
|
||
|
</div>
|
||
|
<p>This might have been as far as you've gotten if you jumped right in doing
|
||
|
some graphics programming with pygame. You've got some nice looking stuff
|
||
|
on the screen, but it cannot move anywhere. Perhaps now that our screen
|
||
|
is just a list of numbers, it's easier to see how to move him?</p>
|
||
|
</section>
|
||
|
<section id="making-the-hero-move">
|
||
|
<h3>Making The Hero Move<a class="headerlink" href="#making-the-hero-move" title="Permalink to this headline">¶</a></h3>
|
||
|
<p>Before we can start moving the character. We need to keep track of some
|
||
|
sort of position for him. In the last section when we drew him, we just picked
|
||
|
an arbitrary position. Let's do it a little more officially this time.</p>
|
||
|
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">playerpos</span> <span class="o">=</span> <span class="mi">3</span>
|
||
|
<span class="gp">>>> </span><span class="n">screen</span><span class="p">[</span><span class="n">playerpos</span><span class="p">]</span> <span class="o">=</span> <span class="mi">8</span>
|
||
|
<span class="gp">>>> </span><span class="nb">print</span><span class="p">(</span><span class="n">screen</span><span class="p">)</span>
|
||
|
<span class="go">[1, 1, 2, 8, 2, 1]</span>
|
||
|
</pre></div>
|
||
|
</div>
|
||
|
<p>Now it is pretty easy to move him to a new position. We simply change
|
||
|
the value of playerpos, and draw him on the screen again.</p>
|
||
|
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">playerpos</span> <span class="o">=</span> <span class="n">playerpos</span> <span class="o">-</span> <span class="mi">1</span>
|
||
|
<span class="gp">>>> </span><span class="n">screen</span><span class="p">[</span><span class="n">playerpos</span><span class="p">]</span> <span class="o">=</span> <span class="mi">8</span>
|
||
|
<span class="gp">>>> </span><span class="nb">print</span><span class="p">(</span><span class="n">screen</span><span class="p">)</span>
|
||
|
<span class="go">[1, 1, 8, 8, 2, 1]</span>
|
||
|
</pre></div>
|
||
|
</div>
|
||
|
<p>Whoops. Now we can see two heroes. One in the old position, and one
|
||
|
in his new position. This is exactly the reason we need to "erase" the hero
|
||
|
in his old position before we draw him in the new position. To erase him,
|
||
|
we need to change that value in the list back to what it was before the hero
|
||
|
was there. That means we need to keep track of the values on the screen before
|
||
|
the hero replaced them. There's several ways you could do this, but the easiest
|
||
|
is usually to keep a separate copy of the screen background. This means
|
||
|
we need to make some changes to our little game.</p>
|
||
|
</section>
|
||
|
<section id="creating-a-map">
|
||
|
<h3>Creating A Map<a class="headerlink" href="#creating-a-map" title="Permalink to this headline">¶</a></h3>
|
||
|
<p>What we want to do is create a separate list we will call our background.
|
||
|
We will create the background so it looks like our original screen did,
|
||
|
with 1s and 2s. Then we will copy each item from the background to the screen.
|
||
|
After that we can finally draw our hero back onto the screen.</p>
|
||
|
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">background</span> <span class="o">=</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">1</span><span class="p">]</span>
|
||
|
<span class="gp">>>> </span><span class="n">screen</span> <span class="o">=</span> <span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">*</span><span class="mi">6</span> <span class="c1">#a new blank screen</span>
|
||
|
<span class="gp">>>> </span><span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">6</span><span class="p">):</span>
|
||
|
<span class="gp">... </span> <span class="n">screen</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">background</span><span class="p">[</span><span class="n">i</span><span class="p">]</span>
|
||
|
<span class="gp">>>> </span><span class="nb">print</span><span class="p">(</span><span class="n">screen</span><span class="p">)</span>
|
||
|
<span class="go">[1, 1, 2, 2, 2, 1]</span>
|
||
|
<span class="gp">>>> </span><span class="n">playerpos</span> <span class="o">=</span> <span class="mi">3</span>
|
||
|
<span class="gp">>>> </span><span class="n">screen</span><span class="p">[</span><span class="n">playerpos</span><span class="p">]</span> <span class="o">=</span> <span class="mi">8</span>
|
||
|
<span class="gp">>>> </span><span class="nb">print</span><span class="p">(</span><span class="n">screen</span><span class="p">)</span>
|
||
|
<span class="go">[1, 1, 2, 8, 2, 1]</span>
|
||
|
</pre></div>
|
||
|
</div>
|
||
|
<p>It may seem like a lot of extra work. We're no farther off than we were
|
||
|
before the last time we tried to make him move. But this time we have the
|
||
|
extra information we need to move him properly.</p>
|
||
|
</section>
|
||
|
<section id="making-the-hero-move-take-2">
|
||
|
<h3>Making The Hero Move (Take 2)<a class="headerlink" href="#making-the-hero-move-take-2" title="Permalink to this headline">¶</a></h3>
|
||
|
<p>This time it will be easy to move the hero around. First we will erase
|
||
|
the hero from his old position. We do this by copying the correct value
|
||
|
from the background onto the screen. Then we will draw the character in his
|
||
|
new position on the screen</p>
|
||
|
<div class="doctest highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="nb">print</span><span class="p">(</span><span class="n">screen</span><span class="p">)</span>
|
||
|
<span class="go">[1, 1, 2, 8, 2, 1]</span>
|
||
|
<span class="gp">>>> </span><span class="n">screen</span><span class="p">[</span><span class="n">playerpos</span><span class="p">]</span> <span class="o">=</span> <span class="n">background</span><span class="p">[</span><span class="n">playerpos</span><span class="p">]</span>
|
||
|
<span class="gp">>>> </span><span class="n">playerpos</span> <span class="o">=</span> <span class="n">playerpos</span> <span class="o">-</span> <span class="mi">1</span>
|
||
|
<span class="gp">>>> </span><span class="n">screen</span><span class="p">[</span><span class="n">playerpos</span><span class="p">]</span> <span class="o">=</span> <span class="mi">8</span>
|
||
|
<span class="gp">>>> </span><span class="nb">print</span><span class="p">(</span><span class="n">screen</span><span class="p">)</span>
|
||
|
<span class="go">[1, 1, 8, 2, 2, 1]</span>
|
||
|
</pre></div>
|
||
|
</div>
|
||
|
<p>There it is. The hero has moved one space to the left. We can use this
|
||
|
same code to move him to the left again.</p>
|
||
|
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">screen</span><span class="p">[</span><span class="n">playerpos</span><span class="p">]</span> <span class="o">=</span> <span class="n">background</span><span class="p">[</span><span class="n">playerpos</span><span class="p">]</span>
|
||
|
<span class="gp">>>> </span><span class="n">playerpos</span> <span class="o">=</span> <span class="n">playerpos</span> <span class="o">-</span> <span class="mi">1</span>
|
||
|
<span class="gp">>>> </span><span class="n">screen</span><span class="p">[</span><span class="n">playerpos</span><span class="p">]</span> <span class="o">=</span> <span class="mi">8</span>
|
||
|
<span class="gp">>>> </span><span class="nb">print</span><span class="p">(</span><span class="n">screen</span><span class="p">)</span>
|
||
|
<span class="go">[1, 8, 2, 2, 2, 1]</span>
|
||
|
</pre></div>
|
||
|
</div>
|
||
|
<p>Excellent! This isn't exactly what you'd call smooth animation. But with
|
||
|
a couple small changes, we'll make this work directly with graphics on
|
||
|
the screen.</p>
|
||
|
</section>
|
||
|
<section id="definition-blit">
|
||
|
<h3>Definition: "blit"<a class="headerlink" href="#definition-blit" title="Permalink to this headline">¶</a></h3>
|
||
|
<p>In the next sections we will transform our program from using lists to
|
||
|
using real graphics on the screen. When displaying the graphics we will
|
||
|
use the term <strong>blit</strong> frequently. If you are new to doing graphics
|
||
|
work, you are probably unfamiliar with this common term.</p>
|
||
|
<p>BLIT: Basically, blit means to copy graphics from one image
|
||
|
to another. A more formal definition is to copy an array of data
|
||
|
to a bitmapped array destination. You can think of blit as just
|
||
|
<em>"assigning"</em> pixels. Much like setting values in our screen-list
|
||
|
above, blitting assigns the color of pixels in our image.</p>
|
||
|
<p>Other graphics libraries will use the word <em>bitblt</em>, or just <em>blt</em>,
|
||
|
but they are talking about the same thing. It is basically copying
|
||
|
memory from one place to another. Actually, it is a bit more advanced than
|
||
|
straight copying of memory, since it needs to handle things like pixel
|
||
|
formats, clipping, and scanline pitches. Advanced blitters can also
|
||
|
handle things like transparency and other special effects.</p>
|
||
|
</section>
|
||
|
<section id="going-from-the-list-to-the-screen">
|
||
|
<h3>Going From The List To The Screen<a class="headerlink" href="#going-from-the-list-to-the-screen" title="Permalink to this headline">¶</a></h3>
|
||
|
<p>To take the code we see in the above to examples and make them work with
|
||
|
pygame is very straightforward. We'll pretend we have loaded some pretty
|
||
|
graphics and named them "terrain1", "terrain2", and "hero". Where before
|
||
|
we assigned numbers to a list, we now blit graphics to the screen. Another
|
||
|
big change, instead of using positions as a single index (0 through 5), we
|
||
|
now need a two dimensional coordinate. We'll pretend each of the graphics
|
||
|
in our game is 10 pixels wide.</p>
|
||
|
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">background</span> <span class="o">=</span> <span class="p">[</span><span class="n">terrain1</span><span class="p">,</span> <span class="n">terrain1</span><span class="p">,</span> <span class="n">terrain2</span><span class="p">,</span> <span class="n">terrain2</span><span class="p">,</span> <span class="n">terrain2</span><span class="p">,</span> <span class="n">terrain1</span><span class="p">]</span>
|
||
|
<span class="gp">>>> </span><span class="n">screen</span> <span class="o">=</span> <span class="n">create_graphics_screen</span><span class="p">()</span>
|
||
|
<span class="gp">>>> </span><span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">6</span><span class="p">):</span>
|
||
|
<span class="gp">... </span> <span class="n">screen</span><span class="o">.</span><span class="n">blit</span><span class="p">(</span><span class="n">background</span><span class="p">[</span><span class="n">i</span><span class="p">],</span> <span class="p">(</span><span class="n">i</span><span class="o">*</span><span class="mi">10</span><span class="p">,</span> <span class="mi">0</span><span class="p">))</span>
|
||
|
<span class="gp">>>> </span><span class="n">playerpos</span> <span class="o">=</span> <span class="mi">3</span>
|
||
|
<span class="gp">>>> </span><span class="n">screen</span><span class="o">.</span><span class="n">blit</span><span class="p">(</span><span class="n">playerimage</span><span class="p">,</span> <span class="p">(</span><span class="n">playerpos</span><span class="o">*</span><span class="mi">10</span><span class="p">,</span> <span class="mi">0</span><span class="p">))</span>
|
||
|
</pre></div>
|
||
|
</div>
|
||
|
<p>Hmm, that code should seem very familiar, and hopefully more importantly;
|
||
|
the code above should make a little sense. Hopefully my illustration of setting
|
||
|
simple values in a list shows the similarity of setting pixels on the screen
|
||
|
(with blit). The only part that's really extra work is converting the player position
|
||
|
into coordinates on the screen. For now we just use a crude <code class="code docutils literal notranslate"><span class="pre">(playerpos*10,</span> <span class="pre">0)</span></code> ,
|
||
|
but we can certainly do better than that. Now let's move the player
|
||
|
image over a space. This code should have no surprises.</p>
|
||
|
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">screen</span><span class="o">.</span><span class="n">blit</span><span class="p">(</span><span class="n">background</span><span class="p">[</span><span class="n">playerpos</span><span class="p">],</span> <span class="p">(</span><span class="n">playerpos</span><span class="o">*</span><span class="mi">10</span><span class="p">,</span> <span class="mi">0</span><span class="p">))</span>
|
||
|
<span class="gp">>>> </span><span class="n">playerpos</span> <span class="o">=</span> <span class="n">playerpos</span> <span class="o">-</span> <span class="mi">1</span>
|
||
|
<span class="gp">>>> </span><span class="n">screen</span><span class="o">.</span><span class="n">blit</span><span class="p">(</span><span class="n">playerimage</span><span class="p">,</span> <span class="p">(</span><span class="n">playerpos</span><span class="o">*</span><span class="mi">10</span><span class="p">,</span> <span class="mi">0</span><span class="p">))</span>
|
||
|
</pre></div>
|
||
|
</div>
|
||
|
<p>There you have it. With this code we've shown how to display a simple background
|
||
|
with a hero's image on it. Then we've properly moved that hero one space
|
||
|
to the left. So where do we go from here? Well for one the code is still
|
||
|
a little awkward. First thing we'll want to do is find a cleaner way to represent
|
||
|
the background and player position. Then perhaps a bit of smoother, real
|
||
|
animation.</p>
|
||
|
</section>
|
||
|
<section id="screen-coordinates">
|
||
|
<h3>Screen Coordinates<a class="headerlink" href="#screen-coordinates" title="Permalink to this headline">¶</a></h3>
|
||
|
<p>To position an object on the screen, we need to tell the blit() function
|
||
|
where to put the image. In pygame we always pass positions as an (X,Y) coordinate.
|
||
|
This represents the number of pixels to the right, and the number of pixels
|
||
|
down to place the image. The top-left corner of a Surface is coordinate (0,
|
||
|
0). Moving to the right a little would be (10, 0), and then moving down just
|
||
|
as much would be (10, 10). When blitting, the position argument represents
|
||
|
where the topleft corner of the source should be placed on the destination.</p>
|
||
|
<p>Pygame comes with a convenient container for these coordinates, it is a
|
||
|
Rect. The Rect basically represents a rectangular area in these coordinates.
|
||
|
It has topleft corner and a size. The Rect comes with a lot of convenient
|
||
|
methods which help you move and position them. In our next examples we will
|
||
|
represent the positions of our objects with the Rects.</p>
|
||
|
<p>Also know that many functions in pygame expect Rect arguments. All of these
|
||
|
functions can also accept a simple tuple of 4 elements (left, top, width,
|
||
|
height). You aren't always required to use these Rect objects, but you will
|
||
|
mainly want to. Also, the blit() function can accept a Rect as its position
|
||
|
argument, it simply uses the topleft corner of the Rect as the real position.</p>
|
||
|
</section>
|
||
|
<section id="changing-the-background">
|
||
|
<h3>Changing The Background<a class="headerlink" href="#changing-the-background" title="Permalink to this headline">¶</a></h3>
|
||
|
<p>In all our previous sections, we've been storing the background as a list
|
||
|
of different types of ground. That is a good way to create a tile-based game,
|
||
|
but we want smooth scrolling. To make that a little easier, we're going to
|
||
|
change the background into a single image that covers the whole screen. This
|
||
|
way, when we want to "erase" our objects (before redrawing them) we only need
|
||
|
to blit the section of the erased background onto the screen.</p>
|
||
|
<p>By passing an optional third Rect argument to blit, we tell blit to only
|
||
|
use that subsection of the source image. You'll see that in use below as we
|
||
|
erase the player image.</p>
|
||
|
<p>Also note, now when we finish drawing to the screen, we call pygame.display.update()
|
||
|
which will show everything we've drawn onto the screen.</p>
|
||
|
</section>
|
||
|
<section id="smooth-movement">
|
||
|
<h3>Smooth Movement<a class="headerlink" href="#smooth-movement" title="Permalink to this headline">¶</a></h3>
|
||
|
<p>To make something appear to move smoothly, we only want to move it a couple
|
||
|
pixels at a time. Here is the code to make an object move smoothly across
|
||
|
the screen. Based on what we already now know, this should look pretty simple.</p>
|
||
|
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">screen</span> <span class="o">=</span> <span class="n">create_screen</span><span class="p">()</span>
|
||
|
<span class="gp">>>> </span><span class="n">clock</span> <span class="o">=</span> <span class="n">pygame</span><span class="o">.</span><span class="n">time</span><span class="o">.</span><span class="n">Clock</span><span class="p">()</span> <span class="c1">#get a pygame clock object</span>
|
||
|
<span class="gp">>>> </span><span class="n">player</span> <span class="o">=</span> <span class="n">load_player_image</span><span class="p">()</span>
|
||
|
<span class="gp">>>> </span><span class="n">background</span> <span class="o">=</span> <span class="n">load_background_image</span><span class="p">()</span>
|
||
|
<span class="gp">>>> </span><span class="n">screen</span><span class="o">.</span><span class="n">blit</span><span class="p">(</span><span class="n">background</span><span class="p">,</span> <span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">))</span> <span class="c1">#draw the background</span>
|
||
|
<span class="gp">>>> </span><span class="n">position</span> <span class="o">=</span> <span class="n">player</span><span class="o">.</span><span class="n">get_rect</span><span class="p">()</span>
|
||
|
<span class="gp">>>> </span><span class="n">screen</span><span class="o">.</span><span class="n">blit</span><span class="p">(</span><span class="n">player</span><span class="p">,</span> <span class="n">position</span><span class="p">)</span> <span class="c1">#draw the player</span>
|
||
|
<span class="gp">>>> </span><span class="n">pygame</span><span class="o">.</span><span class="n">display</span><span class="o">.</span><span class="n">update</span><span class="p">()</span> <span class="c1">#and show it all</span>
|
||
|
<span class="gp">>>> </span><span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">100</span><span class="p">):</span> <span class="c1">#animate 100 frames</span>
|
||
|
<span class="gp">... </span> <span class="n">screen</span><span class="o">.</span><span class="n">blit</span><span class="p">(</span><span class="n">background</span><span class="p">,</span> <span class="n">position</span><span class="p">,</span> <span class="n">position</span><span class="p">)</span> <span class="c1">#erase</span>
|
||
|
<span class="gp">... </span> <span class="n">position</span> <span class="o">=</span> <span class="n">position</span><span class="o">.</span><span class="n">move</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span> <span class="c1">#move player</span>
|
||
|
<span class="gp">... </span> <span class="n">screen</span><span class="o">.</span><span class="n">blit</span><span class="p">(</span><span class="n">player</span><span class="p">,</span> <span class="n">position</span><span class="p">)</span> <span class="c1">#draw new player</span>
|
||
|
<span class="gp">... </span> <span class="n">pygame</span><span class="o">.</span><span class="n">display</span><span class="o">.</span><span class="n">update</span><span class="p">()</span> <span class="c1">#and show it all</span>
|
||
|
<span class="gp">... </span> <span class="n">clock</span><span class="o">.</span><span class="n">tick</span><span class="p">(</span><span class="mi">60</span><span class="p">)</span> <span class="c1">#update 60 times per second</span>
|
||
|
</pre></div>
|
||
|
</div>
|
||
|
<p>There you have it. This is all the code that is needed to smoothly animate
|
||
|
an object across the screen. We can even use a pretty background character.
|
||
|
Another benefit of doing the background this way, the image for the player
|
||
|
can have transparency or cutout sections and it will still draw correctly
|
||
|
over the background (a free bonus).</p>
|
||
|
<p>We also throw in a call to pygame.time.Clock() to grab the clock element.
|
||
|
With it, we can call clock.tick() to set the framerate in frames per second.
|
||
|
This slows down our program a little, otherwise it might run so fast you might
|
||
|
not see it.</p>
|
||
|
</section>
|
||
|
<section id="so-what-next">
|
||
|
<h3>So, What Next?<a class="headerlink" href="#so-what-next" title="Permalink to this headline">¶</a></h3>
|
||
|
<p>Well there we have it. Hopefully this article has done everything it promised
|
||
|
to do. But, at this point the code really isn't ready for the next best-selling
|
||
|
game. How do we easily have multiple moving objects? What exactly are those
|
||
|
mysterious functions like load_player_image()? We also need a way to get simple
|
||
|
user input, and loop for more than 100 frames. We'll take the example we
|
||
|
have here, and turn it into an object oriented creation that would make momma
|
||
|
proud.</p>
|
||
|
</section>
|
||
|
<section id="first-the-mystery-functions">
|
||
|
<h3>First, The Mystery Functions<a class="headerlink" href="#first-the-mystery-functions" title="Permalink to this headline">¶</a></h3>
|
||
|
<p>Full information on these types of functions can be found in other tutorials
|
||
|
and reference. The pygame.image module has a load() function which will do
|
||
|
what we want. The lines to load the images should become this.</p>
|
||
|
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">player</span> <span class="o">=</span> <span class="n">pygame</span><span class="o">.</span><span class="n">image</span><span class="o">.</span><span class="n">load</span><span class="p">(</span><span class="s1">'player.bmp'</span><span class="p">)</span><span class="o">.</span><span class="n">convert</span><span class="p">()</span>
|
||
|
<span class="gp">>>> </span><span class="n">background</span> <span class="o">=</span> <span class="n">pygame</span><span class="o">.</span><span class="n">image</span><span class="o">.</span><span class="n">load</span><span class="p">(</span><span class="s1">'liquid.bmp'</span><span class="p">)</span><span class="o">.</span><span class="n">convert</span><span class="p">()</span>
|
||
|
</pre></div>
|
||
|
</div>
|
||
|
<p>We can see that's pretty simple, the load function just takes a filename
|
||
|
and returns a new Surface with the loaded image. After loading we make a call
|
||
|
to the Surface method, convert(). Convert returns us a new Surface of the
|
||
|
image, but now converted to the same pixel format as our display. Since the
|
||
|
images will be the same format at the screen, they will blit very quickly.
|
||
|
If we did not convert, the blit() function is slower, since it has to convert
|
||
|
from one type of pixel to another as it goes.</p>
|
||
|
<p>You may also have noticed that both the load() and convert() return new
|
||
|
Surfaces. This means we're really creating two Surfaces on each of these
|
||
|
lines. In other programming languages, this results in a memory leak (not
|
||
|
a good thing). Fortunately Python is smart enough to handle this, and pygame
|
||
|
will properly clean up the Surface we end up not using.</p>
|
||
|
<p>The other mystery function we saw in the above example was create_screen().
|
||
|
In pygame it is simple to create a new window for graphics. The code to create
|
||
|
a 640x480 surface is below. By passing no other arguments, pygame will just
|
||
|
pick the best color depth and pixel format for us.</p>
|
||
|
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">screen</span> <span class="o">=</span> <span class="n">pygame</span><span class="o">.</span><span class="n">display</span><span class="o">.</span><span class="n">set_mode</span><span class="p">((</span><span class="mi">640</span><span class="p">,</span> <span class="mi">480</span><span class="p">))</span>
|
||
|
</pre></div>
|
||
|
</div>
|
||
|
</section>
|
||
|
<section id="handling-some-input">
|
||
|
<h3>Handling Some Input<a class="headerlink" href="#handling-some-input" title="Permalink to this headline">¶</a></h3>
|
||
|
<p>We desperately need to change the main loop to look for any user input, (like
|
||
|
when the user closes the window). We need to add "event handling" to our
|
||
|
program. All graphical programs use this Event Based design. The program
|
||
|
gets events like "keyboard pressed" or "mouse moved" from the computer. Then
|
||
|
the program responds to the different events. Here's what the code should
|
||
|
look like. Instead of looping for 100 frames, we'll keep looping until the
|
||
|
user asks us to stop.</p>
|
||
|
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="k">while</span> <span class="kc">True</span><span class="p">:</span>
|
||
|
<span class="gp">... </span> <span class="k">for</span> <span class="n">event</span> <span class="ow">in</span> <span class="n">pygame</span><span class="o">.</span><span class="n">event</span><span class="o">.</span><span class="n">get</span><span class="p">():</span>
|
||
|
<span class="gp">... </span> <span class="k">if</span> <span class="n">event</span><span class="o">.</span><span class="n">type</span> <span class="o">==</span> <span class="n">pygame</span><span class="o">.</span><span class="n">QUIT</span><span class="p">:</span>
|
||
|
<span class="gp">... </span> <span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">()</span>
|
||
|
<span class="gp">... </span> <span class="n">move_and_draw_all_game_objects</span><span class="p">()</span>
|
||
|
</pre></div>
|
||
|
</div>
|
||
|
<p>What this code simply does is, first loop forever, then check if there are
|
||
|
any events from the user. We exit the program if the user presses the close
|
||
|
button on the window. After we've checked all the events we move and draw
|
||
|
our game objects. (We'll also erase them before they move, too)</p>
|
||
|
</section>
|
||
|
<section id="moving-multiple-images">
|
||
|
<h3>Moving Multiple Images<a class="headerlink" href="#moving-multiple-images" title="Permalink to this headline">¶</a></h3>
|
||
|
<p>Here's the part where we're really going to change things around. Let's
|
||
|
say we want 10 different images moving around on the screen. A good way to
|
||
|
handle this is to use python's classes. We'll create a class that represents
|
||
|
our game object. This object will have a function to move itself, and then
|
||
|
we can create as many as we like. The functions to draw and move the object
|
||
|
need to work in a way where they only move one frame (or one step) at a time.
|
||
|
Here's the python code to create our class.</p>
|
||
|
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="k">class</span> <span class="nc">GameObject</span><span class="p">:</span>
|
||
|
<span class="gp">... </span> <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">image</span><span class="p">,</span> <span class="n">height</span><span class="p">,</span> <span class="n">speed</span><span class="p">):</span>
|
||
|
<span class="gp">... </span> <span class="bp">self</span><span class="o">.</span><span class="n">speed</span> <span class="o">=</span> <span class="n">speed</span>
|
||
|
<span class="gp">... </span> <span class="bp">self</span><span class="o">.</span><span class="n">image</span> <span class="o">=</span> <span class="n">image</span>
|
||
|
<span class="gp">... </span> <span class="bp">self</span><span class="o">.</span><span class="n">pos</span> <span class="o">=</span> <span class="n">image</span><span class="o">.</span><span class="n">get_rect</span><span class="p">()</span><span class="o">.</span><span class="n">move</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">height</span><span class="p">)</span>
|
||
|
<span class="gp">... </span> <span class="k">def</span> <span class="nf">move</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||
|
<span class="gp">... </span> <span class="bp">self</span><span class="o">.</span><span class="n">pos</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">pos</span><span class="o">.</span><span class="n">move</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">speed</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>
|
||
|
<span class="gp">... </span> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">pos</span><span class="o">.</span><span class="n">right</span> <span class="o">></span> <span class="mi">600</span><span class="p">:</span>
|
||
|
<span class="gp">... </span> <span class="bp">self</span><span class="o">.</span><span class="n">pos</span><span class="o">.</span><span class="n">left</span> <span class="o">=</span> <span class="mi">0</span>
|
||
|
</pre></div>
|
||
|
</div>
|
||
|
<p>So we have two functions in our class. The init function constructs our object.
|
||
|
It positions the object and sets its speed. The move method moves the object
|
||
|
one step. If it's gone too far, it moves the object back to the left.</p>
|
||
|
</section>
|
||
|
<section id="putting-it-all-together">
|
||
|
<h3>Putting It All Together<a class="headerlink" href="#putting-it-all-together" title="Permalink to this headline">¶</a></h3>
|
||
|
<p>Now with our new object class, we can put together the entire game. Here
|
||
|
is what the main function for our program will look like.</p>
|
||
|
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">screen</span> <span class="o">=</span> <span class="n">pygame</span><span class="o">.</span><span class="n">display</span><span class="o">.</span><span class="n">set_mode</span><span class="p">((</span><span class="mi">640</span><span class="p">,</span> <span class="mi">480</span><span class="p">))</span>
|
||
|
<span class="gp">>>> </span><span class="n">clock</span> <span class="o">=</span> <span class="n">pygame</span><span class="o">.</span><span class="n">time</span><span class="o">.</span><span class="n">Clock</span><span class="p">()</span> <span class="c1">#get a pygame clock object</span>
|
||
|
<span class="gp">>>> </span><span class="n">player</span> <span class="o">=</span> <span class="n">pygame</span><span class="o">.</span><span class="n">image</span><span class="o">.</span><span class="n">load</span><span class="p">(</span><span class="s1">'player.bmp'</span><span class="p">)</span><span class="o">.</span><span class="n">convert</span><span class="p">()</span>
|
||
|
<span class="gp">>>> </span><span class="n">background</span> <span class="o">=</span> <span class="n">pygame</span><span class="o">.</span><span class="n">image</span><span class="o">.</span><span class="n">load</span><span class="p">(</span><span class="s1">'background.bmp'</span><span class="p">)</span><span class="o">.</span><span class="n">convert</span><span class="p">()</span>
|
||
|
<span class="gp">>>> </span><span class="n">screen</span><span class="o">.</span><span class="n">blit</span><span class="p">(</span><span class="n">background</span><span class="p">,</span> <span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">))</span>
|
||
|
<span class="gp">>>> </span><span class="n">objects</span> <span class="o">=</span> <span class="p">[]</span>
|
||
|
<span class="gp">>>> </span><span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">10</span><span class="p">):</span> <span class="c1">#create 10 objects</i></span>
|
||
|
<span class="gp">... </span> <span class="n">o</span> <span class="o">=</span> <span class="n">GameObject</span><span class="p">(</span><span class="n">player</span><span class="p">,</span> <span class="n">x</span><span class="o">*</span><span class="mi">40</span><span class="p">,</span> <span class="n">x</span><span class="p">)</span>
|
||
|
<span class="gp">... </span> <span class="n">objects</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">o</span><span class="p">)</span>
|
||
|
<span class="gp">>>> </span><span class="k">while</span> <span class="kc">True</span><span class="p">:</span>
|
||
|
<span class="gp">... </span> <span class="k">for</span> <span class="n">event</span> <span class="ow">in</span> <span class="n">pygame</span><span class="o">.</span><span class="n">event</span><span class="o">.</span><span class="n">get</span><span class="p">():</span>
|
||
|
<span class="gp">... </span> <span class="k">if</span> <span class="n">event</span><span class="o">.</span><span class="n">type</span> <span class="o">==</span> <span class="n">pygame</span><span class="o">.</span><span class="n">QUIT</span><span class="p">:</span>
|
||
|
<span class="gp">... </span> <span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">()</span>
|
||
|
<span class="gp">... </span> <span class="k">for</span> <span class="n">o</span> <span class="ow">in</span> <span class="n">objects</span><span class="p">:</span>
|
||
|
<span class="gp">... </span> <span class="n">screen</span><span class="o">.</span><span class="n">blit</span><span class="p">(</span><span class="n">background</span><span class="p">,</span> <span class="n">o</span><span class="o">.</span><span class="n">pos</span><span class="p">,</span> <span class="n">o</span><span class="o">.</span><span class="n">pos</span><span class="p">)</span>
|
||
|
<span class="gp">... </span> <span class="k">for</span> <span class="n">o</span> <span class="ow">in</span> <span class="n">objects</span><span class="p">:</span>
|
||
|
<span class="gp">... </span> <span class="n">o</span><span class="o">.</span><span class="n">move</span><span class="p">()</span>
|
||
|
<span class="gp">... </span> <span class="n">screen</span><span class="o">.</span><span class="n">blit</span><span class="p">(</span><span class="n">o</span><span class="o">.</span><span class="n">image</span><span class="p">,</span> <span class="n">o</span><span class="o">.</span><span class="n">pos</span><span class="p">)</span>
|
||
|
<span class="gp">... </span> <span class="n">pygame</span><span class="o">.</span><span class="n">display</span><span class="o">.</span><span class="n">update</span><span class="p">()</span>
|
||
|
<span class="gp">... </span> <span class="n">clock</span><span class="o">.</span><span class="n">tick</span><span class="p">(</span><span class="mi">60</span><span class="p">)</span>
|
||
|
</pre></div>
|
||
|
</div>
|
||
|
<p>And there it is. This is the code we need to animate 10 objects on the screen.
|
||
|
The only point that might need explaining is the two loops we use to clear
|
||
|
all the objects and draw all the objects. In order to do things properly,
|
||
|
we need to erase all the objects before drawing any of them. In our sample
|
||
|
here it may not matter, but when objects are overlapping, using two loops
|
||
|
like this becomes important.</p>
|
||
|
</section>
|
||
|
<section id="preparing-for-improved-user-input">
|
||
|
<h3>Preparing for Improved User Input<a class="headerlink" href="#preparing-for-improved-user-input" title="Permalink to this headline">¶</a></h3>
|
||
|
<p>With all keyboard input terminating the program, that's not very interactive.
|
||
|
Let's add some extra user input!</p>
|
||
|
<p>First we should create a unique character that the player will control. We
|
||
|
can do that in much the same way we created the other movable entities. Let's
|
||
|
call the player object p. We can already move any object, but, a player should
|
||
|
have more input than simply moving right. To accommodate this, let's revamp
|
||
|
our move function under our GameObject class.</p>
|
||
|
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="k">def</span> <span class="nf">move</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">up</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span> <span class="n">down</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span> <span class="n">left</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span> <span class="n">right</span><span class="o">=</span><span class="kc">False</span><span class="p">):</span>
|
||
|
<span class="gp">... </span> <span class="k">if</span> <span class="n">right</span><span class="p">:</span>
|
||
|
<span class="gp">... </span> <span class="bp">self</span><span class="o">.</span><span class="n">pos</span><span class="o">.</span><span class="n">right</span> <span class="o">+=</span> <span class="bp">self</span><span class="o">.</span><span class="n">speed</span>
|
||
|
<span class="gp">... </span> <span class="k">if</span> <span class="n">left</span><span class="p">:</span>
|
||
|
<span class="gp">... </span> <span class="bp">self</span><span class="o">.</span><span class="n">pos</span><span class="o">.</span><span class="n">right</span> <span class="o">-=</span> <span class="bp">self</span><span class="o">.</span><span class="n">speed</span>
|
||
|
<span class="gp">... </span> <span class="k">if</span> <span class="n">down</span><span class="p">:</span>
|
||
|
<span class="gp">... </span> <span class="bp">self</span><span class="o">.</span><span class="n">pos</span><span class="o">.</span><span class="n">top</span> <span class="o">+=</span> <span class="bp">self</span><span class="o">.</span><span class="n">speed</span>
|
||
|
<span class="gp">... </span> <span class="k">if</span> <span class="n">up</span><span class="p">:</span>
|
||
|
<span class="gp">... </span> <span class="bp">self</span><span class="o">.</span><span class="n">pos</span><span class="o">.</span><span class="n">top</span> <span class="o">-=</span> <span class="bp">self</span><span class="o">.</span><span class="n">speed</span>
|
||
|
<span class="gp">... </span> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">pos</span><span class="o">.</span><span class="n">right</span> <span class="o">></span> <span class="n">WIDTH</span><span class="p">:</span>
|
||
|
<span class="gp">... </span> <span class="bp">self</span><span class="o">.</span><span class="n">pos</span><span class="o">.</span><span class="n">left</span> <span class="o">=</span> <span class="mi">0</span>
|
||
|
<span class="gp">... </span> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">pos</span><span class="o">.</span><span class="n">top</span> <span class="o">></span> <span class="n">HEIGHT</span><span class="o">-</span><span class="n">SPRITE_HEIGHT</span><span class="p">:</span>
|
||
|
<span class="gp">... </span> <span class="bp">self</span><span class="o">.</span><span class="n">pos</span><span class="o">.</span><span class="n">top</span> <span class="o">=</span> <span class="mi">0</span>
|
||
|
<span class="gp">... </span> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">pos</span><span class="o">.</span><span class="n">right</span> <span class="o"><</span> <span class="n">SPRITE_WIDTH</span><span class="p">:</span>
|
||
|
<span class="gp">... </span> <span class="bp">self</span><span class="o">.</span><span class="n">pos</span><span class="o">.</span><span class="n">right</span> <span class="o">=</span> <span class="n">WIDTH</span>
|
||
|
<span class="gp">... </span> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">pos</span><span class="o">.</span><span class="n">top</span> <span class="o"><</span> <span class="mi">0</span><span class="p">:</span>
|
||
|
<span class="gp">... </span> <span class="bp">self</span><span class="o">.</span><span class="n">pos</span><span class="o">.</span><span class="n">top</span> <span class="o">=</span> <span class="n">HEIGHT</span><span class="o">-</span><span class="n">SPRITE_HEIGHT</span>
|
||
|
</pre></div>
|
||
|
</div>
|
||
|
<p>There's certainly a lot more going on here, so let's take it one step at a time.
|
||
|
First, we've added some default values into the move function, declared as up,
|
||
|
down, left, and right. These booleans will allow us to specifically select a
|
||
|
direction that the object is moving in. The first part, where we go through and
|
||
|
check True for each variable, is where we will add to the position of the object,
|
||
|
much like before. Right controls horizontal, and top controls vertical positions.</p>
|
||
|
<p>Additionally, we've removed the magic number present previously, and replaced it
|
||
|
with the constants WIDTH, HEIGHT, SPRITE_WIDTH, and SPRITE_HEIGHT. These values
|
||
|
represent the screen width and height, along with the width and height of the object
|
||
|
displayed on the screen.</p>
|
||
|
<p>The second part, where the position is being checked, ensures that the position
|
||
|
is within the confines of our screen. With this in place, we need to make sure that
|
||
|
when one of our other objects calls move, we set right to true.</p>
|
||
|
</section>
|
||
|
<section id="adding-the-user-input">
|
||
|
<h3>Adding the User Input<a class="headerlink" href="#adding-the-user-input" title="Permalink to this headline">¶</a></h3>
|
||
|
<p>We've already seen that pygame has event handling, and we know that KEYDOWN is
|
||
|
an event in this loop. We could, under KEYDOWN, assert the key press matches an
|
||
|
arrow key, where we would then call move. However, this movement will only occur
|
||
|
once every time a key is pressed, and it therefore will be extremely choppy and
|
||
|
unpleasant.</p>
|
||
|
<p>For this, we can use pygame.key.get_pressed(), which returns a list of all keys,
|
||
|
and whether or not they are currently pressed. Since we want these key presses
|
||
|
to be maintained whether an event is currently happening or not, we should put
|
||
|
it outside of the main event handling loop, but still within our game loop.
|
||
|
Our functionality will look like this.</p>
|
||
|
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">keys</span> <span class="o">=</span> <span class="n">pygame</span><span class="o">.</span><span class="n">key</span><span class="o">.</span><span class="n">get_pressed</span><span class="p">()</span>
|
||
|
<span class="gp">>>> </span><span class="k">if</span> <span class="n">keys</span><span class="p">[</span><span class="n">pygame</span><span class="o">.</span><span class="n">K_UP</span><span class="p">]:</span>
|
||
|
<span class="gp">... </span> <span class="n">p</span><span class="o">.</span><span class="n">move</span><span class="p">(</span><span class="n">up</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
|
||
|
<span class="gp">>>> </span><span class="k">if</span> <span class="n">keys</span><span class="p">[</span><span class="n">pygame</span><span class="o">.</span><span class="n">K_DOWN</span><span class="p">]:</span>
|
||
|
<span class="gp">... </span> <span class="n">p</span><span class="o">.</span><span class="n">move</span><span class="p">(</span><span class="n">down</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
|
||
|
<span class="gp">>>> </span><span class="k">if</span> <span class="n">keys</span><span class="p">[</span><span class="n">pygame</span><span class="o">.</span><span class="n">K_LEFT</span><span class="p">]:</span>
|
||
|
<span class="gp">... </span> <span class="n">p</span><span class="o">.</span><span class="n">move</span><span class="p">(</span><span class="n">left</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
|
||
|
<span class="gp">>>> </span><span class="k">if</span> <span class="n">keys</span><span class="p">[</span><span class="n">pygame</span><span class="o">.</span><span class="n">K_RIGHT</span><span class="p">]:</span>
|
||
|
<span class="gp">... </span> <span class="n">p</span><span class="o">.</span><span class="n">move</span><span class="p">(</span><span class="n">right</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
|
||
|
</pre></div>
|
||
|
</div>
|
||
|
<p>We simply get our list of keys pressed, called keys. We can then check the index
|
||
|
at the key code position to see if it is held down. For more key codes, I recommend
|
||
|
checking out the documentation on pygame.key.</p>
|
||
|
<p>When up is held, we move our object, p, up. When down is held, we move down. Rinse and
|
||
|
repeat for all cases, and we're good to go!</p>
|
||
|
</section>
|
||
|
<section id="putting-it-all-together-one-more-time">
|
||
|
<h3>Putting it all Together One More time<a class="headerlink" href="#putting-it-all-together-one-more-time" title="Permalink to this headline">¶</a></h3>
|
||
|
<p>Now that we're finished with the player functionality, let's take one last look to make
|
||
|
sure we understand everything.</p>
|
||
|
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">screen</span> <span class="o">=</span> <span class="n">pygame</span><span class="o">.</span><span class="n">display</span><span class="o">.</span><span class="n">set_mode</span><span class="p">((</span><span class="mi">640</span><span class="p">,</span> <span class="mi">480</span><span class="p">))</span>
|
||
|
<span class="gp">>>> </span><span class="n">clock</span> <span class="o">=</span> <span class="n">pygame</span><span class="o">.</span><span class="n">time</span><span class="o">.</span><span class="n">Clock</span><span class="p">()</span> <span class="c1">#get a pygame clock object</span>
|
||
|
<span class="gp">>>> </span><span class="n">player</span> <span class="o">=</span> <span class="n">pygame</span><span class="o">.</span><span class="n">image</span><span class="o">.</span><span class="n">load</span><span class="p">(</span><span class="s1">'player.bmp'</span><span class="p">)</span><span class="o">.</span><span class="n">convert</span><span class="p">()</span>
|
||
|
<span class="gp">>>> </span><span class="n">entity</span> <span class="o">=</span> <span class="n">pygame</span><span class="o">.</span><span class="n">image</span><span class="o">.</span><span class="n">load</span><span class="p">(</span><span class="s1">'alien1.bmp'</span><span class="p">)</span><span class="o">.</span><span class="n">convert</span><span class="p">()</span>
|
||
|
<span class="gp">>>> </span><span class="n">background</span> <span class="o">=</span> <span class="n">pygame</span><span class="o">.</span><span class="n">image</span><span class="o">.</span><span class="n">load</span><span class="p">(</span><span class="s1">'background.bmp'</span><span class="p">)</span><span class="o">.</span><span class="n">convert</span><span class="p">()</span>
|
||
|
<span class="gp">>>> </span><span class="n">screen</span><span class="o">.</span><span class="n">blit</span><span class="p">(</span><span class="n">background</span><span class="p">,</span> <span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">))</span>
|
||
|
<span class="gp">>>> </span><span class="n">objects</span> <span class="o">=</span> <span class="p">[]</span>
|
||
|
<span class="gp">>>> </span><span class="n">p</span> <span class="o">=</span> <span class="n">GameObject</span><span class="p">(</span><span class="n">player</span><span class="p">,</span> <span class="mi">10</span><span class="p">,</span> <span class="mi">3</span><span class="p">)</span> <span class="c1">#create the player object</span>
|
||
|
<span class="gp">>>> </span><span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">10</span><span class="p">):</span> <span class="c1">#create 10 objects</i></span>
|
||
|
<span class="gp">... </span> <span class="n">o</span> <span class="o">=</span> <span class="n">GameObject</span><span class="p">(</span><span class="n">entity</span><span class="p">,</span> <span class="n">x</span><span class="o">*</span><span class="mi">40</span><span class="p">,</span> <span class="n">x</span><span class="p">)</span>
|
||
|
<span class="gp">... </span> <span class="n">objects</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">o</span><span class="p">)</span>
|
||
|
<span class="gp">>>> </span><span class="k">while</span> <span class="kc">True</span><span class="p">:</span>
|
||
|
<span class="gp">... </span> <span class="n">screen</span><span class="o">.</span><span class="n">blit</span><span class="p">(</span><span class="n">background</span><span class="p">,</span> <span class="n">p</span><span class="o">.</span><span class="n">pos</span><span class="p">,</span> <span class="n">p</span><span class="o">.</span><span class="n">pos</span><span class="p">)</span>
|
||
|
<span class="gp">... </span> <span class="k">for</span> <span class="n">o</span> <span class="ow">in</span> <span class="n">objects</span><span class="p">:</span>
|
||
|
<span class="gp">... </span> <span class="n">screen</span><span class="o">.</span><span class="n">blit</span><span class="p">(</span><span class="n">background</span><span class="p">,</span> <span class="n">o</span><span class="o">.</span><span class="n">pos</span><span class="p">,</span> <span class="n">o</span><span class="o">.</span><span class="n">pos</span><span class="p">)</span>
|
||
|
<span class="gp">... </span> <span class="n">keys</span> <span class="o">=</span> <span class="n">pygame</span><span class="o">.</span><span class="n">key</span><span class="o">.</span><span class="n">get_pressed</span><span class="p">()</span>
|
||
|
<span class="gp">... </span> <span class="k">if</span> <span class="n">keys</span><span class="p">[</span><span class="n">pygame</span><span class="o">.</span><span class="n">K_UP</span><span class="p">]:</span>
|
||
|
<span class="gp">... </span> <span class="n">p</span><span class="o">.</span><span class="n">move</span><span class="p">(</span><span class="n">up</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
|
||
|
<span class="gp">... </span> <span class="k">if</span> <span class="n">keys</span><span class="p">[</span><span class="n">pygame</span><span class="o">.</span><span class="n">K_DOWN</span><span class="p">]:</span>
|
||
|
<span class="gp">... </span> <span class="n">p</span><span class="o">.</span><span class="n">move</span><span class="p">(</span><span class="n">down</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
|
||
|
<span class="gp">... </span> <span class="k">if</span> <span class="n">keys</span><span class="p">[</span><span class="n">pygame</span><span class="o">.</span><span class="n">K_LEFT</span><span class="p">]:</span>
|
||
|
<span class="gp">... </span> <span class="n">p</span><span class="o">.</span><span class="n">move</span><span class="p">(</span><span class="n">left</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
|
||
|
<span class="gp">... </span> <span class="k">if</span> <span class="n">keys</span><span class="p">[</span><span class="n">pygame</span><span class="o">.</span><span class="n">K_RIGHT</span><span class="p">]:</span>
|
||
|
<span class="gp">... </span> <span class="n">p</span><span class="o">.</span><span class="n">move</span><span class="p">(</span><span class="n">right</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
|
||
|
<span class="gp">... </span> <span class="k">for</span> <span class="n">event</span> <span class="ow">in</span> <span class="n">pygame</span><span class="o">.</span><span class="n">event</span><span class="o">.</span><span class="n">get</span><span class="p">():</span>
|
||
|
<span class="gp">... </span> <span class="k">if</span> <span class="n">event</span><span class="o">.</span><span class="n">type</span> <span class="o">==</span> <span class="n">pygame</span><span class="o">.</span><span class="n">QUIT</span><span class="p">:</span>
|
||
|
<span class="gp">... </span> <span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">()</span>
|
||
|
<span class="gp">... </span> <span class="n">screen</span><span class="o">.</span><span class="n">blit</span><span class="p">(</span><span class="n">p</span><span class="o">.</span><span class="n">image</span><span class="p">,</span> <span class="n">p</span><span class="o">.</span><span class="n">pos</span><span class="p">)</span>
|
||
|
<span class="gp">... </span> <span class="k">for</span> <span class="n">o</span> <span class="ow">in</span> <span class="n">objects</span><span class="p">:</span>
|
||
|
<span class="gp">... </span> <span class="n">o</span><span class="o">.</span><span class="n">move</span><span class="p">()</span>
|
||
|
<span class="gp">... </span> <span class="n">screen</span><span class="o">.</span><span class="n">blit</span><span class="p">(</span><span class="n">o</span><span class="o">.</span><span class="n">image</span><span class="p">,</span> <span class="n">o</span><span class="o">.</span><span class="n">pos</span><span class="p">)</span>
|
||
|
<span class="gp">... </span> <span class="n">pygame</span><span class="o">.</span><span class="n">display</span><span class="o">.</span><span class="n">update</span><span class="p">()</span>
|
||
|
<span class="gp">... </span> <span class="n">clock</span><span class="o">.</span><span class="n">tick</span><span class="p">(</span><span class="mi">60</span><span class="p">)</span>
|
||
|
</pre></div>
|
||
|
</div>
|
||
|
<p>A few things not mentioned earlier: we load in a second image and call it entity,
|
||
|
and we use that for all objects that aren't the player, which uses the player
|
||
|
image defined earlier.</p>
|
||
|
<p>And that's all there is to it! Now we have a fully functional player object that
|
||
|
is controlled using the arrow keys!</p>
|
||
|
</section>
|
||
|
<section id="you-are-on-your-own-from-here">
|
||
|
<h3>You Are On Your Own From Here<a class="headerlink" href="#you-are-on-your-own-from-here" title="Permalink to this headline">¶</a></h3>
|
||
|
<p>So what would be next on your road to learning? Well first playing around
|
||
|
with this example a bit. The full running version of this example is available
|
||
|
in the pygame examples directory. It is the example named
|
||
|
<a class="reference internal" href="../ref/examples.html#pygame.examples.moveit.main" title="pygame.examples.moveit.main"><code class="xref py py-func docutils literal notranslate"><span class="pre">moveit.py</span></code></a> .
|
||
|
Take a look at the code and play with it, run it, learn it.</p>
|
||
|
<p>Things you may want to work on is maybe having more than one type of object.
|
||
|
Finding a way to cleanly "delete" objects when you don't want to show them
|
||
|
any more. Also updating the display.update() call to pass a list of the areas
|
||
|
on-screen that have changed.</p>
|
||
|
<p>There are also other tutorials and examples in pygame that cover these
|
||
|
issues. So when you're ready to keep learning, keep on reading. :-)</p>
|
||
|
<p>Lastly, you can feel free to come to the pygame mailing list or chatroom
|
||
|
with any questions on this stuff. There's always folks on hand who can help
|
||
|
you out with this sort of business.</p>
|
||
|
<p>Lastly, have fun, that's what games are for!</p>
|
||
|
</section>
|
||
|
</section>
|
||
|
</section>
|
||
|
|
||
|
|
||
|
<br /><br />
|
||
|
<hr />
|
||
|
<a href="https://github.com/pygame/pygame/edit/main/docs/reST/tut\MoveIt.rst" rel="nofollow">Edit on GitHub</a>
|
||
|
<div class="clearer"></div>
|
||
|
</div>
|
||
|
</div>
|
||
|
<div class="clearer"></div>
|
||
|
</div>
|
||
|
<div class="related" role="navigation" aria-label="related navigation">
|
||
|
<h3>Navigation</h3>
|
||
|
<ul>
|
||
|
<li class="right" style="margin-right: 10px">
|
||
|
<a href="../genindex.html" title="General Index"
|
||
|
accesskey="I">index</a></li>
|
||
|
<li class="right" >
|
||
|
<a href="../py-modindex.html" title="Python Module Index"
|
||
|
>modules</a> |</li>
|
||
|
<li class="right" >
|
||
|
<a href="PygameIntro.html" title="Pygame Intro"
|
||
|
accesskey="N">next</a> |</li>
|
||
|
<li class="right" >
|
||
|
<a href="tom_games6.html" title="Putting it all together"
|
||
|
accesskey="P">previous</a> |</li>
|
||
|
<li class="nav-item nav-item-0"><a href="../index.html">pygame v2.5.2 documentation</a> »</li>
|
||
|
<li class="nav-item nav-item-this"><a href="">Pygame Tutorials - Help! How Do I Move An Image?</a></li>
|
||
|
<script type="text/javascript" src="https://www.pygame.org/comment/jquery.plugin.docscomments.js"></script>
|
||
|
|
||
|
</ul>
|
||
|
</div>
|
||
|
<div class="footer" role="contentinfo">
|
||
|
© Copyright 2000-2023, pygame developers.
|
||
|
</div>
|
||
|
</body>
|
||
|
</html>
|