-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpyadventure-basic-inventory-update.html
356 lines (310 loc) · 36.6 KB
/
pyadventure-basic-inventory-update.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="generator" content="Pelican" />
<title>PyAdventure Basic Inventory Update</title>
<link rel="stylesheet" href="https://yashaslokesh.github.io/theme/css/main.css" />
<link href="https://yashaslokesh.github.io/feeds/all.atom.xml" type="application/atom+xml" rel="alternate" title="Yashas's Blog Atom Feed" />
<meta name="description" content="An update to my adventure game where I create the inventory interface and provide some basic controls for it." />
</head>
<body id="index" class="home">
<header id="banner" class="body">
<h1><a href="https://yashaslokesh.github.io/">Yashas's Blog</a></h1>
<nav><ul>
<li><a href="https://yashaslokesh.github.io/pages/about-me.html">About</a></li>
<li><a href="https://yashaslokesh.github.io/category/misc.html">misc</a></li>
<li class="active"><a href="https://yashaslokesh.github.io/category/python.html">Python</a></li>
</ul></nav>
</header><!-- /#banner -->
<section id="content" class="body">
<article>
<header>
<h1 class="entry-title">
<a href="https://yashaslokesh.github.io/pyadventure-basic-inventory-update.html" rel="bookmark"
title="Permalink to PyAdventure Basic Inventory Update">PyAdventure Basic Inventory Update</a></h1>
</header>
<div class="entry-content">
<footer class="post-info">
<abbr class="published" title="2019-12-15T06:00:00-05:00">
Published: Sun 15 December 2019
</abbr>
<br />
<abbr class="modified" title="2019-12-15T06:00:00-05:00">
Updated: Sun 15 December 2019
</abbr>
<address class="vcard author">
By <a class="url fn" href="https://yashaslokesh.github.io/author/yashas-lokesh.html">Yashas Lokesh</a>
</address>
<p>In <a href="https://yashaslokesh.github.io/category/python.html">Python</a>.</p>
<p>tags: <a href="https://yashaslokesh.github.io/tag/python.html">python</a> <a href="https://yashaslokesh.github.io/tag/pygame.html">pygame</a> </p>
</footer><!-- /.post-info --> <h2>Setup</h2>
<p>So for my yet-to-be-named adventure game, I decided that one good area to make progress in
would be creating an inventory system. In this post, I'll talk about how I created the
basic interface for the inventory, including the controls for navigating around. This
only took about 45 minutes to create from start to finish, with most of the time being spent
to get it to look <em>just</em> right.</p>
<p>To start off, I created the <code>inventory.py</code> file inside the <code>core/</code> package, then added some
necessary imports:</p>
<div class="highlight"><pre><span></span><code><span class="kn">import</span> <span class="nn">pygame</span>
<span class="kn">from</span> <span class="nn">pygame.locals</span> <span class="kn">import</span> <span class="o">*</span>
<span class="kn">from</span> <span class="nn">random</span> <span class="kn">import</span> <span class="n">randint</span>
<span class="kn">import</span> <span class="nn">core.constants</span> <span class="k">as</span> <span class="nn">c</span>
</code></pre></div>
<p>The first two lines import the <a href="https://www.pygame.org/news">pygame</a> library and
the set of constants from <code>pygame.locals</code>. These constants are used when detecting
events or key/mouse presses, among other things.</p>
<p>On the next line, we import the <code>randint</code> function so we can create randomly-colored
components in the inventory window (these serve as placeholders for actual items).</p>
<p>Next, the constants created for the game are imported. I'm not sure what the best practice
or best way to do this is, so I just import the module as <code>c</code> so that I don't
get confused on where a particular constant comes from. </p>
<h2>Classes</h2>
<p>So the way the game is structured right now calls for creating a class for each usable
thing on the screen and then calling the <code>update()</code> method on the relevant group of
objects. If you haven't work with classes in Python before, it's really simple;
we're going to add a constructor, an <code>update()</code> method, and a <code>draw()</code> method.</p>
<p>Here's the basic skeleton of how we create that:</p>
<p><code>inventory.py</code>:</p>
<div class="highlight"><pre><span></span><code><span class="k">class</span> <span class="nc">Inventory</span><span class="p">(</span><span class="nb">object</span><span class="p">):</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="k">pass</span>
<span class="k">def</span> <span class="nf">update</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">keydown_event</span><span class="p">):</span>
<span class="k">pass</span>
<span class="k">def</span> <span class="nf">draw</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">screen</span><span class="p">):</span>
<span class="k">pass</span>
</code></pre></div>
<p>We'll set a few constants for inventory size and position on the screen.</p>
<p><code>constants.py</code>:</p>
<div class="highlight"><pre><span></span><code><span class="n">INVENTORY_SIZE</span> <span class="o">=</span> <span class="n">INVENTORY_WIDTH</span><span class="p">,</span> <span class="n">INVENTORY_HEIGHT</span> <span class="o">=</span> <span class="p">(</span>
<span class="mi">600</span><span class="p">,</span>
<span class="mi">600</span><span class="p">,</span>
<span class="p">)</span>
<span class="n">INVENTORY_COORDS</span> <span class="o">=</span> <span class="n">INVENTORY_X</span><span class="p">,</span> <span class="n">INVENTORY_Y</span> <span class="o">=</span> <span class="p">(</span>
<span class="n">SCREEN_WIDTH</span> <span class="o">//</span> <span class="mi">2</span> <span class="o">-</span> <span class="n">INVENTORY_WIDTH</span> <span class="o">//</span> <span class="mi">2</span><span class="p">,</span>
<span class="n">SCREEN_HEIGHT</span> <span class="o">//</span> <span class="mi">2</span> <span class="o">-</span> <span class="n">INVENTORY_HEIGHT</span> <span class="o">//</span> <span class="mi">2</span><span class="p">,</span>
<span class="p">)</span>
</code></pre></div>
<p>And now we can work on the constructor. We want the active item, i.e. the box
that the player has currently selected, to start at some constant, say <code>[0,0]</code>,
and we make this value a list so that we can alter the position of the active item later.</p>
<p>Next, every pygame object has to have a <code>Rect</code> associated with it. We want our <code>Rect</code>
to be static, fixed in a certain position on the screen. Using the above constants,
we can use the constructor for <code>Rect</code> and store this in the class. </p>
<p>Finally, let's create a 4x4 array of RGB values that we can use to create the
squares of the inventory. To do this, we can create an empty list and then populate
it with four lists of four RBG triples each.</p>
<p>All together, it could look something like this:</p>
<p><code>inventory.py</code>:</p>
<div class="highlight"><pre><span></span><code><span class="k">class</span> <span class="nc">Inventory</span><span class="p">(</span><span class="nb">object</span><span class="p">):</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="bp">self</span><span class="o">.</span><span class="n">active_item</span> <span class="o">=</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="bp">self</span><span class="o">.</span><span class="n">rect</span> <span class="o">=</span> <span class="n">pygame</span><span class="o">.</span><span class="n">Rect</span><span class="p">(</span>
<span class="n">c</span><span class="o">.</span><span class="n">INVENTORY_X</span><span class="p">,</span> <span class="n">c</span><span class="o">.</span><span class="n">INVENTORY_Y</span><span class="p">,</span> <span class="n">c</span><span class="o">.</span><span class="n">INVENTORY_WIDTH</span><span class="p">,</span> <span class="n">c</span><span class="o">.</span><span class="n">INVENTORY_HEIGHT</span>
<span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">sample_item_colors</span> <span class="o">=</span> <span class="p">[]</span>
<span class="c1"># set rectangle colors for sample inventory</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">4</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">sample_item_colors</span><span class="o">.</span><span class="n">append</span><span class="p">([])</span>
<span class="k">for</span> <span class="n">j</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">4</span><span class="p">):</span>
<span class="n">r</span><span class="p">,</span> <span class="n">g</span><span class="p">,</span> <span class="n">b</span> <span class="o">=</span> <span class="n">randint</span><span class="p">(</span><span class="mi">50</span><span class="p">,</span> <span class="mi">255</span><span class="p">),</span> <span class="n">randint</span><span class="p">(</span><span class="mi">50</span><span class="p">,</span> <span class="mi">255</span><span class="p">),</span> <span class="n">randint</span><span class="p">(</span><span class="mi">50</span><span class="p">,</span> <span class="mi">255</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">sample_item_colors</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">.</span><span class="n">append</span><span class="p">((</span><span class="n">r</span><span class="p">,</span> <span class="n">g</span><span class="p">,</span> <span class="n">b</span><span class="p">))</span>
</code></pre></div>
<p>Note that we use the <code>self.</code> syntax to indicate instance variables.
This code just sets up a rough visual look for the inventory. Next, we want to
draw this inventory to the screen. The <code>blit()</code> method of a <code>Surface</code> object will
draw one surface onto another. </p>
<p><code>inventory.py</code>:</p>
<div class="highlight"><pre><span></span><code><span class="k">class</span> <span class="nc">Inventory</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
<span class="sd">""" omitted code """</span>
<span class="k">def</span> <span class="nf">draw</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">screen</span><span class="p">:</span> <span class="n">pygame</span><span class="o">.</span><span class="n">Surface</span><span class="p">):</span>
<span class="n">pygame</span><span class="o">.</span><span class="n">draw</span><span class="o">.</span><span class="n">rect</span><span class="p">(</span><span class="n">screen</span><span class="p">,</span> <span class="p">(</span><span class="mi">172</span><span class="p">,</span> <span class="mi">237</span><span class="p">,</span> <span class="mi">182</span><span class="p">),</span> <span class="bp">self</span><span class="o">.</span><span class="n">rect</span><span class="p">)</span>
<span class="n">item_rect</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">rect</span><span class="o">.</span><span class="n">copy</span><span class="p">()</span>
<span class="n">item_rect</span><span class="o">.</span><span class="n">size</span> <span class="o">=</span> <span class="mi">150</span><span class="p">,</span> <span class="mi">150</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">4</span><span class="p">):</span>
<span class="n">item_rect</span><span class="o">.</span><span class="n">x</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">rect</span><span class="o">.</span><span class="n">x</span> <span class="o">+</span> <span class="p">(</span><span class="n">i</span> <span class="o">*</span> <span class="mi">150</span><span class="p">)</span>
<span class="k">for</span> <span class="n">j</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">4</span><span class="p">):</span>
<span class="c1"># item_rect = self.rect.copy()</span>
<span class="c1"># item_rect.x, item_rect.y = item_rect.x + (i * 150), item_rect.y + (j * 150)</span>
<span class="n">item_rect</span><span class="o">.</span><span class="n">y</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">rect</span><span class="o">.</span><span class="n">y</span> <span class="o">+</span> <span class="p">(</span><span class="n">j</span> <span class="o">*</span> <span class="mi">150</span><span class="p">)</span>
<span class="c1"># item_rect.size = 150, 150</span>
<span class="n">pygame</span><span class="o">.</span><span class="n">draw</span><span class="o">.</span><span class="n">rect</span><span class="p">(</span><span class="n">screen</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">sample_item_colors</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">j</span><span class="p">],</span> <span class="n">item_rect</span><span class="p">)</span>
</code></pre></div>
<p>This code draws a <code>rect</code> of a light-green color, almost like the color of jade. Then it copies the
rect of the inventory object and adjusts the size to draw each tile of the inventory. The
inventory's rect is copied because it already has the correct <code>(x, y)</code> coordinates. Then, we
simply do a 4x4 loop to draw the entire inventory using the appropriate colors from
<code>self.sample_item_colors</code>. </p>
<p>There's one more component I want to add to the inventory this time, and that's a selection
box for picking whatever object you want from the screen. So the user needs to be able to hit
some buttons to scroll through our inventory and pick the appropriate item. We'll make the controls
for picking items be the arrow keys. Recall that we defined the <code>active_item</code> instance variable
earlier. We'll be mutating this list as we receive input. We can create an <code>update()</code> method
that accepts an object describing a keydown event.</p>
<p><code>inventory.py</code>:</p>
<div class="highlight"><pre><span></span><code><span class="k">class</span> <span class="nc">Inventory</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
<span class="sd">""" omitted code """</span>
<span class="k">def</span> <span class="nf">update</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">keydown_event</span><span class="p">):</span>
<span class="k">if</span> <span class="n">keydown_event</span><span class="o">.</span><span class="n">key</span> <span class="o">==</span> <span class="n">K_DOWN</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">active_item</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">+=</span> <span class="mi">1</span>
<span class="k">elif</span> <span class="n">keydown_event</span><span class="o">.</span><span class="n">key</span> <span class="o">==</span> <span class="n">K_UP</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">active_item</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">+=</span> <span class="o">-</span><span class="mi">1</span>
<span class="k">elif</span> <span class="n">keydown_event</span><span class="o">.</span><span class="n">key</span> <span class="o">==</span> <span class="n">K_LEFT</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">active_item</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">-=</span> <span class="mi">1</span>
<span class="k">elif</span> <span class="n">keydown_event</span><span class="o">.</span><span class="n">key</span> <span class="o">==</span> <span class="n">K_RIGHT</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">active_item</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">+=</span> <span class="mi">1</span>
</code></pre></div>
<p>To use this method, we need to pass in an appropriate event. How do we do that? All pygame events
can be obtained using <code>pygame.event.get()</code>, and as we iterate through the returned collection, if
the type of the event is <code>KEYDOWN</code>, (so <code>event.type == KEYDOWN</code>, where <code>KEYDOWN</code> comes from
<code>pygame.locals</code>). The argument <code>keydown_event</code> should be of this type (we can add some error
throwing code to catch any errors related to this at another time).</p>
<p>So we then check the <code>key</code> attribute for each of the arrow keys. If the user hits the down arrow
key, we move down the <code>active_item</code> position. A problem quickly shows up if we try hitting the
button 4 or more times... this should cause the active item pointer to wrap back around
to the top of the inventory selection screen, but it just goes down forever. This
has an easy fix; when we go to the -1 or the 4 position we wrap back to the appropriate side
of the inventory square.</p>
<p><code>inventory.py</code>:</p>
<div class="highlight"><pre><span></span><code><span class="k">class</span> <span class="nc">Inventory</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
<span class="k">def</span> <span class="nf">update</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">keydown_event</span><span class="p">):</span>
<span class="k">if</span> <span class="n">keydown_event</span><span class="o">.</span><span class="n">key</span> <span class="o">==</span> <span class="n">K_DOWN</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">active_item</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">+=</span> <span class="mi">1</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">active_item</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">==</span> <span class="mi">4</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">active_item</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span>
<span class="k">elif</span> <span class="n">keydown_event</span><span class="o">.</span><span class="n">key</span> <span class="o">==</span> <span class="n">K_UP</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">active_item</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">+=</span> <span class="o">-</span><span class="mi">1</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">active_item</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">==</span> <span class="o">-</span><span class="mi">1</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">active_item</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="mi">3</span>
<span class="k">elif</span> <span class="n">keydown_event</span><span class="o">.</span><span class="n">key</span> <span class="o">==</span> <span class="n">K_LEFT</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">active_item</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">-=</span> <span class="mi">1</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">active_item</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">==</span> <span class="o">-</span><span class="mi">1</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">active_item</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="mi">3</span>
<span class="k">elif</span> <span class="n">keydown_event</span><span class="o">.</span><span class="n">key</span> <span class="o">==</span> <span class="n">K_RIGHT</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">active_item</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">+=</span> <span class="mi">1</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">active_item</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">==</span> <span class="mi">4</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">active_item</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span>
</code></pre></div>
<p>Now we actually need to use the <code>active_item</code> list to draw a selection box. Back to the <code>draw()</code>
method, we can do something similar to drawing the tiles for each item rectangle from before.
We want it to have the same size and start from the same <code>x, y</code> coordinates, but this
box will have a certain thickness. One way we can design the selection box is by making it
a frame, so that the frame encloses the selected object.</p>
<p>We can pick some arbitrary constant thickness that's less than half the width of the box, so less
than or equal to 75. I'll pick 20, and add it to <code>constants.py</code> as <code>SELECTION_BOX_THICKNESS = 20</code>.</p>
<p><code>inventory.py</code>:</p>
<div class="highlight"><pre><span></span><code><span class="k">class</span> <span class="nc">Inventory</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
<span class="sd">""" omitted code """</span>
<span class="k">def</span> <span class="nf">draw</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">screen</span><span class="p">:</span> <span class="n">pygame</span><span class="o">.</span><span class="n">Surface</span><span class="p">):</span>
<span class="sd">""" omitted draw code """</span>
<span class="n">selection_box</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">rect</span><span class="o">.</span><span class="n">copy</span><span class="p">()</span>
<span class="n">selection_box</span><span class="o">.</span><span class="n">size</span> <span class="o">=</span> <span class="mi">150</span><span class="p">,</span> <span class="mi">150</span>
<span class="n">selection_box</span><span class="o">.</span><span class="n">x</span> <span class="o">+=</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">active_item</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">*</span> <span class="mi">150</span><span class="p">)</span> <span class="o">+</span> <span class="p">(</span>
<span class="n">c</span><span class="o">.</span><span class="n">SELECTION_BOX_THICKNESS</span> <span class="o">//</span> <span class="mi">2</span>
<span class="p">)</span>
<span class="n">selection_box</span><span class="o">.</span><span class="n">y</span> <span class="o">+=</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">active_item</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">*</span> <span class="mi">150</span><span class="p">)</span> <span class="o">+</span> <span class="p">(</span>
<span class="n">c</span><span class="o">.</span><span class="n">SELECTION_BOX_THICKNESS</span> <span class="o">//</span> <span class="mi">2</span>
<span class="p">)</span>
<span class="n">selection_box</span><span class="o">.</span><span class="n">width</span> <span class="o">-=</span> <span class="n">c</span><span class="o">.</span><span class="n">SELECTION_BOX_THICKNESS</span>
<span class="n">selection_box</span><span class="o">.</span><span class="n">height</span> <span class="o">-=</span> <span class="n">c</span><span class="o">.</span><span class="n">SELECTION_BOX_THICKNESS</span>
<span class="n">pygame</span><span class="o">.</span><span class="n">draw</span><span class="o">.</span><span class="n">rect</span><span class="p">(</span>
<span class="n">screen</span><span class="p">,</span> <span class="p">(</span><span class="mi">255</span><span class="p">,</span> <span class="mi">255</span><span class="p">,</span> <span class="mi">255</span><span class="p">),</span> <span class="n">selection_box</span><span class="p">,</span> <span class="n">c</span><span class="o">.</span><span class="n">SELECTION_BOX_THICKNESS</span>
<span class="p">)</span>
</code></pre></div>
<p>Here's the extra code added in the <code>draw()</code> method. <code>pygame</code> draws the thickness of the box
outwards, so we need to adjust the <code>x, y</code> coordinates to
start closer to actual size of the box and then adjust the <code>width</code> and <code>height</code> to constrain
the selection box to be the size of an individual item rectangle. Then, we draw
the white box onto the screen with our specified thickness.</p>
<p>So now our inventory code is complete, and we can go back to our main game loop in <code>game.py</code>
and configure it so that everytime a <code>KEYDOWN</code> event is encountered, we update the inventory,
and on each iteration of the loop, we draw to the screen. I made a choice to include
the inventory as part of the <code>Player</code> class, because each player has an inventory, so
to draw the inventory, we access it through our player and call the draw method with our
screen surface.</p>
<p><code>game.py</code>:</p>
<div class="highlight"><pre><span></span><code><span class="k">class</span> <span class="nc">Game</span><span class="p">:</span>
<span class="sd">""" omitted code """</span>
<span class="k">def</span> <span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="sd">""" omitted code """</span>
<span class="n">running</span> <span class="o">=</span> <span class="kc">True</span>
<span class="k">while</span> <span class="n">running</span><span class="p">:</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="k">if</span> <span class="n">event</span><span class="o">.</span><span class="n">type</span> <span class="o">==</span> <span class="n">QUIT</span> <span class="ow">or</span> <span class="p">(</span><span class="n">event</span><span class="o">.</span><span class="n">type</span> <span class="o">==</span> <span class="n">KEYDOWN</span> <span class="ow">and</span> <span class="n">event</span><span class="o">.</span><span class="n">key</span> <span class="o">==</span> <span class="n">K_q</span><span class="p">):</span>
<span class="n">running</span> <span class="o">=</span> <span class="kc">False</span>
<span class="k">elif</span> <span class="n">event</span><span class="o">.</span><span class="n">type</span> <span class="o">==</span> <span class="n">KEYDOWN</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">player</span><span class="o">.</span><span class="n">inventory</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">event</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">player</span><span class="o">.</span><span class="n">inventory</span><span class="o">.</span><span class="n">draw</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">screen</span><span class="p">)</span>
<span class="n">pygame</span><span class="o">.</span><span class="n">display</span><span class="o">.</span><span class="n">flip</span><span class="p">()</span>
</code></pre></div>
<p>What if the player is just interacting
with the other parts of the game, not the inventory? Then we shouldn't be updating the selection
box's location or seeing the inventory at all. We can add another local variable in <code>run()</code> named
<code>inventory_active</code> which will have the initial value <code>False</code>,
and on iteration of the game loop, we watch for a certain keypress, maybe the <code>I</code> key, to
activate/deactivate the inventory screen. So we only update and draw the inventory when it is
active.</p>
<p><code>game.py</code>:</p>
<div class="highlight"><pre><span></span><code><span class="k">class</span> <span class="nc">Game</span><span class="p">:</span>
<span class="k">def</span> <span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">inventory_active</span> <span class="o">=</span> <span class="kc">False</span>
<span class="n">running</span> <span class="o">=</span> <span class="kc">True</span>
<span class="k">while</span> <span class="n">running</span><span class="p">:</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="k">if</span> <span class="n">event</span><span class="o">.</span><span class="n">type</span> <span class="o">==</span> <span class="n">QUIT</span> <span class="ow">or</span> <span class="p">(</span><span class="n">event</span><span class="o">.</span><span class="n">type</span> <span class="o">==</span> <span class="n">KEYDOWN</span> <span class="ow">and</span> <span class="n">event</span><span class="o">.</span><span class="n">key</span> <span class="o">==</span> <span class="n">K_q</span><span class="p">):</span>
<span class="n">running</span> <span class="o">=</span> <span class="kc">False</span>
<span class="k">elif</span> <span class="n">event</span><span class="o">.</span><span class="n">type</span> <span class="o">==</span> <span class="n">KEYDOWN</span><span class="p">:</span>
<span class="k">if</span> <span class="n">event</span><span class="o">.</span><span class="n">key</span> <span class="o">==</span> <span class="n">K_i</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">inventory_active</span> <span class="o">=</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">inventory_active</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">inventory_active</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">player</span><span class="o">.</span><span class="n">inventory</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">event</span><span class="p">)</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="bp">self</span><span class="o">.</span><span class="n">player</span><span class="o">.</span><span class="n">draw</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">screen</span><span class="p">)</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">inventory_active</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">player</span><span class="o">.</span><span class="n">inventory</span><span class="o">.</span><span class="n">draw</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">screen</span><span class="p">)</span>
<span class="n">pygame</span><span class="o">.</span><span class="n">display</span><span class="o">.</span><span class="n">flip</span><span class="p">()</span>
</code></pre></div>
<p>The <code>player</code> sprite has an inventory, and we update and draw that one. </p>
<p>All the code I used can be found on <a href="https://github.com/yashaslokesh/pyadventure">my GitHub</a>.
If you have any questions, you can easily contact me on Twitter. </p>
<p>Thanks for reading!</p>
</div><!-- /.entry-content -->
</article>
</section>
<section id="extras" class="body">
<div class="blogroll">
<h2>links</h2>
<ul>
<li><a href="http://getpelican.com/">Pelican</a></li>
<li><a href="http://python.org/">Python.org</a></li>
<li><a href="http://jinja.pocoo.org/">Jinja2</a></li>
<li><a href="http://tutorial.math.lamar.edu/">Paul's Calc Notes</a></li>
<li><a href="https://www.pygame.org/news">Pygame</a></li>
</ul>
</div><!-- /.blogroll -->
<div class="social">
<h2>social</h2>
<ul>
<li><a href="https://yashaslokesh.github.io/feeds/all.atom.xml" type="application/atom+xml" rel="alternate">atom feed</a></li>
<li><a href="https://twitter.com/yashaslokesh_">My Twitter</a></li>
<li><a href="https://www.linkedin.com/in/yashaslokesh/">My LinkedIn</a></li>
<li><a href="https://github.com/yashaslokesh">My GitHub</a></li>
</ul>
</div><!-- /.social -->
</section><!-- /#extras -->
<footer id="contentinfo" class="body">
<address id="about" class="vcard body">
Proudly powered by <a href="https://getpelican.com/">Pelican</a>, which takes great advantage of <a href="https://www.python.org/">Python</a>.
</address><!-- /#about -->
<p>The theme is by <a href="https://www.smashingmagazine.com/2009/08/designing-a-html-5-layout-from-scratch/">Smashing Magazine</a>, thanks!</p>
</footer><!-- /#contentinfo -->
<script type="text/javascript">
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-123139556-3', 'auto');
ga('send', 'pageview');
</script>
</body>
</html>