Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Added get_next_piece sub and fixed font orientation for tetris code

  • Loading branch information...
commit 8744f560e240d65b40a75e566a81b2c47a04a5c5 1 parent c7356aa
@kthakore kthakore authored
View
8 code_listings/tetris.pl
@@ -21,7 +21,7 @@
);
# create our game objects
-my $score_text = SDLx::Text->new( font => 'font.ttf', h_align => 'center', color => [255,255,255,255] );
+my $score_text = SDLx::Text->new( font => 'font.ttf', h_align => 'left', color => [255,255,255,255] );
my $score = 0;
my $back = SDLx::Surface->load( 'data/tetris_back.png' );
my @piece = (undef);
@@ -62,10 +62,12 @@
0,0,0,0],
);
-my $next_tile = shuffle(keys %pieces);
+my $next_tile = get_next_tile();
my $curr_tile = [undef, 4, 0];
@{$curr_tile->[0]} = @{$pieces{$next_tile}};
- $next_tile = shuffle(keys %pieces);
+ $next_tile = get_next_tile();
+
+sub get_next_tile { shuffle(keys %pieces) }
sub rotate_piece {
my $_piece = shift;
View
644 dist/SDL_Manual.html
@@ -2046,24 +2046,25 @@
<h1>Tetris</h1>
+<p>Pong is an important milestone in gaming history. If you can write it,
+you understand the basics of game programming. The next step in mastery
+comes from writing something like Tetris, with better animation and more
+complex scoring.</p>
+
<p>\includegraphics[width=0.5\textwidth]{../src/images/tetris.png}
\caption{Tetris using SDLx Perl} \label{fig:tetris}</p>
-<h2>Eye Candy and Code</h2>
-
-<p>In this chapter we work on creating the classic Tetris game using what
-we have learned so far. Get the tetris code from
-HTTPS://GitHub.Com/PerlGameDev/SDL_Manual/raw/master/games/tetris.zip. To
-run the game invoke in the extracted folder.</p>
+<p>To follow along, download the sample code from
+https://github.com/PerlGameDev/SDL_Manual/raw/master/games/tetris.zip. To
+start the game, extract this Zip file and run:</p>
-<pre><code> perl tetris.pl</code></pre>
+<pre><code> $ <b>perl tetris.pl</b></code></pre>
<h2>The Game Window</h2>
-<p>First we will make our window with a fixed size so we can place our art
-work in a fixed format.</p>
+<p>The game starts out as you should expect by now:</p>
<pre><code> use strict;
use warnings;
@@ -2073,7 +2074,7 @@
use SDL::Events;
use SDLx::App;
- # create our main screen
+ # create the main screen
my $app = SDLx::App-&gt;new(
w =&gt; 400,
h =&gt; 512,
@@ -2082,84 +2083,72 @@
title =&gt; &#39;SDLx Tetris&#39;
);</code></pre>
-<h2>Loading Artwork</h2>
-
-<p>We can load our artwork simply by storing an array of
-<code>SDLx::Surface</code>s.</p>
+<p>This game requires several pieces of artwork, and so the program must
+manage and store them somehow. The <code>SDLx::Surface</code> module
+handles the conversion of files from their storage on disk into a format
+SDL can use, and an array will hold them:</p>
<pre><code> use SDL;
- +use SDLx::Surface;
- </code></pre>
-
-<p>Next we load up the artwork into an array.</p>
-
-<pre><code> +my $back = SDLx::Surface-&gt;load( &#39;data/tetris_back.png&#39; );
- +my @piece = (undef);
- +push(@piece, SDLx::Surface-&gt;load( &quot;data/tetris_$_.png&quot; )) for(1..7);</code></pre>
+ <b>use SDLx::Surface;</b>
+ <b>my $back = SDLx::Surface-&gt;load( &#39;data/tetris_back.png&#39; );</b>
+ <b>my @piece = (undef);</b>
+ <b>push @piece, SDLx::Surface-&gt;load( &quot;data/tetris_$_.png&quot; ) for 1..7;</b></code></pre>
-<p>The background is held in the <code>$back</code> surface, and the pieces
-are held in the <code>@piece</code> array. Later on we will blit these onto
-our main screen as we need.</p>
+<p>The <code>$back</code> variable holds one special surface: the
+background image. Everything else is in the <code>@piece</code> array.</p>
-<h2>Data Structures</h2>
+<h2>Managing Blocks</h2>
-<p>In Tetris the blocks are critical pieces of data that must be
-represented in code such that it is easy to access, and quick to perform
-calculations on. A hash will allow us to quickly access our pieces, based
-on their keys.</p>
+<p>Blocks are critical to the success of a Tetris game. The program must
+represent them in a sensible way: they must be easy to access and they must
+be easy to manipulate and calculate. A hash fulfills the ease of
+access:</p>
<pre><code> my %pieces = (
- I =&gt; [0,5,0,0,
- 0,5,0,0,
- 0,5,0,0,
- 0,5,0,0],
- J =&gt; [0,0,0,0,
- 0,0,6,0,
- 0,0,6,0,
- 0,6,6,0],
- L =&gt; [0,0,0,0,
- 0,2,0,0,
- 0,2,0,0,
- 0,2,2,0],
- O =&gt; [0,0,0,0,
- 0,3,3,0,
- 0,3,3,0,
- 0,0,0,0],
- S =&gt; [0,0,0,0,
- 0,4,4,0,
- 4,4,0,0,
- 0,0,0,0],
- T =&gt; [0,0,0,0,
- 0,7,0,0,
- 7,7,7,0,
- 0,0,0,0],
- Z =&gt; [0,0,0,0,
- 1,1,0,0,
- 0,1,1,0,
- 0,0,0,0],
+ I =&gt; [0, 5, 0, 0,
+ 0, 5, 0, 0,
+ 0, 5, 0, 0,
+ 0, 5, 0, 0],
+ J =&gt; [0, 0, 0, 0,
+ 0, 0, 6, 0,
+ 0, 0, 6, 0,
+ 0, 6, 6, 0],
+ L =&gt; [0, 0, 0, 0,
+ 0, 2, 0, 0,
+ 0, 2, 0, 0,
+ 0, 2, 2, 0],
+ O =&gt; [0, 0, 0, 0,
+ 0, 3, 3, 0,
+ 0, 3, 3, 0,
+ 0, 0, 0, 0],
+ S =&gt; [0, 0, 0, 0,
+ 0, 4, 4, 0,
+ 4, 4, 0, 0,
+ 0, 0, 0, 0],
+ T =&gt; [0, 0, 0, 0,
+ 0, 7, 0, 0,
+ 7, 7, 7, 0,
+ 0, 0, 0, 0],
+ Z =&gt; [0, 0, 0, 0,
+ 1, 1, 0, 0,
+ 0, 1, 1, 0,
+ 0, 0, 0, 0],
);</code></pre>
-<p>Further more we have a 1-dimensional array for each piece that
-represents a grid of the piece.</p>
-
-<p>The grid of each piece is filled with empty spaces and a number from 1
-to 7. When this grid is imposed on the game grid, we can use the non zero
-number to draw the right piece block on to it.</p>
-
-<p>The non zero number corresponds to the images file that we loaded
-ealier.</p>
-
-<pre><code> push(@piece, SDLx::Surface-&gt;load( &quot;data/tetris_$_.png&quot; )) for(1..7);</code></pre>
-
-<h2>Selecting Pieces</h2>
+<p>Each hash entry holds a four-element array reference which represents a
+grid of the piece. Each item in the array corresponds to an image in the
+<code>@piece</code> array. Drawing a piece means blitting one element of
+<code>@piece</code> for each non-zero entry in the piece's array.</p>
<pre><code> use strict;
use warnings;
- +use List::Util qw(shuffle min max);</code></pre>
+ <b>use List::Util qw(shuffle min max);</b></code></pre>
-<p>We will use the List::Util module to provide us with some neeeded
-functions.</p>
+<p></p>
+
+<p>Selecting pieces needs some randomness. The core <code>List::Util</code>
+module can help:</p>
<pre><code> Z =&gt; [0,0,0,0,
1,1,0,0,
@@ -2167,247 +2156,294 @@
0,0,0,0],
);
- +my $next_tile = shuffle(keys %pieces);
- +my $curr_tile = [undef, 4, 0];
- + @{$curr_tile-&gt;[0]} = @{$pieces{$next_tile}};
- + $next_tile = shuffle(keys %pieces); </code></pre>
+ <b>my $next_tile = shuffle keys %pieces;</b>
+ <b>my $curr_tile = [ undef, 4, 0 ];</b>
+ <b>@{ $curr_tile-&gt;[0] } = @{ $pieces{$next_tile} };</b>
+ <b>$next_tile = shuffle keys %pieces;</b></code></pre>
+
+<p>Seems like a function to choose the next tile would be more useful.</p>
-<p>We will randomly pick a <code>$next_tile</code> and then set the piece
-data for our first piece in <code>$curr_tile</code>. Then we will pick
-another tile for our <code>$next_tile</code>.</p>
+<p>This code randomly chooses a <code>$next_tile</code>, then sets the
+piece data for the first piece in <code>$curr_tile</code>.</p>
-<h2>Moving Pieces</h2>
+<h2>Piece Collisions</h2>
-<pre><code> push(@piece, SDLx::Surface-&gt;load( &quot;data/tetris_$_.png&quot; )) for(1..7);
+<p>Collision detection is both easier (because only one piece at a time
+moves) and more difficult (because the screen continues to fill up with
+pieces). One solution is to treat the screen as two overlapping grids. The
+first grid represents the moving piece. The second grid represents the
+pieces already in place. When a moving piece collides with a piece in the
+fixed grid, the moving piece becomes stationary and joins the fixed grid.
+When that action clears one or more lines, the stationary grid changes.</p>
+
+<p>Start by defining these grids:</p>
+
+<pre><code> push @piece, SDLx::Surface-&gt;load( &quot;data/tetris_$_.png&quot; ) for 1..7;
+
+ <b># compare the position of the moving piece with non-moving pieces</b>
+ <b>my $grid = []; # moving piece</b>
+ <b>my $store = []; # non-moving pieces</b>
- +# to check for collisions we compare the position of the moving piece with the non-movin pieces
- +my $grid = []; # moving piece
- +my $store = []; # non-moving pieces
my %pieces = (
I =&gt; [0,5,0,0,</code></pre>
-<p>In our conceptual model of Tetris we have two grids that overlap each
-other. First we have the <code>$grid</code> where the piece that is moving
-is stored. Once a piece has collided with sometime we move it to
-<code>$store</code> grid and hold it there until a line is cleared.</p>
-
-<pre><code> $next_tile = shuffle(keys %pieces); </code></pre>
-
-<p>To rotate a piece we apply a transformation on each element of the
-piece.</p>
-
-<pre><code> + sub rotate_piece {
- + my $_piece = shift;
- + my $_rotated = [];
- + my $_i = 0;
- + for(@{$_piece}) {
- + $_rotated-&gt;[$_i + (($_i%4+1)*3) - (5*int($_i/4))] = $_;
- + $_i++;
- + }
- + return $_rotated;
- + }</code></pre>
-
-<p>Additionally we do a simple collision checking between the non zero
-elements in the pieces with the direction the user wants to move.</p>
-
-<pre><code> + sub can_move_piece {
- + my $direction = shift;
- + my $amount = shift || 1;
- + for my $y (0..3) {
- + for my $x (0..3) {
- + if($curr_tile-&gt;[0]-&gt;[$x + 4 * $y]) {
- + return if $direction eq &#39;left&#39;
- + &amp;&amp; $x - $amount + $curr_tile-&gt;[1] &lt; 0;
- + return if $direction eq &#39;right&#39;
- + &amp;&amp; $x + $amount + $curr_tile-&gt;[1] &gt; 9;
- + return if $direction eq &#39;down&#39;
- + &amp;&amp; int($y + $amount + $curr_tile-&gt;[2]) &gt; 22;
- +
- + return if $direction eq &#39;right&#39;
- + &amp;&amp; $store-&gt;[ $x + $amount +
- + $curr_tile-&gt;[1] +
- + 10 * int($y + $curr_tile-&gt;[2]) ];
- + return if $direction eq &#39;left&#39;
- + &amp;&amp; $store-&gt;[ $x - $amount +
- + $curr_tile-&gt;[1] +
- + 10 * int($y + $curr_tile-&gt;[2]) ];
- + return if $direction eq &#39;down&#39;
- + &amp;&amp; $store-&gt;[ $x +
- + $curr_tile-&gt;[1]
- + + 10 * int($y + $amount + $curr_tile-&gt;[2]) ];
- + }
- + }
- + }
- + return 1;
- + }</code></pre>
-
-<p>Finally we move the move piece by using the collision check and
-overlaying the piece array into the <code>@grid</code> for each next
-position.</p>
-
-<pre><code> + sub move_piece {
- + my $direction = shift;
- + my $amount = shift || 1;
- + if($direction eq &#39;right&#39;) {
- + $curr_tile-&gt;[1] += $amount;
- + }
- + elsif($direction eq &#39;left&#39;) {
- + $curr_tile-&gt;[1] -= $amount;
- + }
- + elsif($direction eq &#39;down&#39;) {
- + $curr_tile-&gt;[2] += $amount;
- + }
- +
- + @{$grid} = ();
- + for my $y (0..3) {
- + for my $x (0..3) {
- + if($curr_tile-&gt;[0]-&gt;[$x + 4 * $y]) {
- + $grid-&gt;[ $x + $curr_tile-&gt;[1] + 10 * ($y + int($curr_tile-&gt;[2])) ]
- + = $curr_tile-&gt;[0]-&gt;[$x + 4 * $y];
- + }
- + }
- + }
- + }
-
- + sub store_piece {
- + for my $y (0..3) {
- + for my $x (0..3) {
- + if($curr_tile-&gt;[0]-&gt;[$x + 4 * $y]) {
- + $store-&gt;[ $x + $curr_tile-&gt;[1] + 10 * ($y + int($curr_tile-&gt;[2])) ]
- + = $curr_tile-&gt;[0]-&gt;[$x + 4 * $y];
- + }
- + }
- + }
- + }</code></pre>
-
-<p>Finally we hook it into the event handler where we use the events to
-move the pieces in the right direction.</p>
-
-<pre><code> + sub trigger_move_event_handler {
- + my ( $event, $app ) = @_;
- + if( $event-&gt;type == SDL_KEYDOWN ) {
- + my $key = $event-&gt;key_sym;
- + if( $event-&gt;key_sym &amp; (SDLK_LEFT|SDLK_RIGHT|SDLK_UP|SDLK_DOWN) ) {
- + if($key == SDLK_LEFT &amp;&amp; can_move_piece(&#39;left&#39;)) {
- + move_piece(&#39;left&#39;);
- + }
- + elsif($key == SDLK_RIGHT &amp;&amp; can_move_piece(&#39;right&#39;)) {
- + move_piece(&#39;right&#39;);
- + }
- + elsif($key == SDLK_DOWN &amp;&amp; can_move_piece(&#39;down&#39;)) {
- + move_piece(&#39;down&#39;)
- + }
- + elsif($key == SDLK_UP) {
- + $curr_tile-&gt;[0] = rotate_piece($curr_tile-&gt;[0]);
- + }
- + }
- + }
- + }
-
- + $app-&gt;add_event_handler( \&amp;trigger_move_event_handler );</code></pre>
+<p>Rotating a piece means transforming each of its elements:</p>
+
+<p>This math needs some explanation for everyone who hasn't done linear
+algebra in a while.</p>
+
+<pre><code> sub rotate_piece {
+ my $_piece = shift;
+ my $_rotated = [];
+ my $_i = 0;
+
+ for (@{$_piece}) {
+ $_rotated-&gt;[ $_i + (($_i % 4 + 1 ) * 3)
+ - ( 5 * int( $_i / 4 ))] = $_;
+ $_i++;
+ }
+
+ return $_rotated;
+ }</code></pre>
+
+<p>Collision detection requires checking both grids for a piece overlap in
+the direction the user wants to move the piece:</p>
+
+<p>The math concern applies here too. A diagram might help.</p>
+
+<pre><code> sub can_move_piece {
+ my $direction = shift;
+ my $amount = shift || 1;
+
+ for my $y (0 .. 3) {
+
+ for my $x (0 . .3) {
+ if ($curr_tile-&gt;[0]-&gt;[ $x + 4 * $y ]) {
+ return if $direction eq &#39;left&#39;
+ &amp;&amp; $x - $amount + $curr_tile-&gt;[1] &lt; 0;
+ return if $direction eq &#39;right&#39;
+ &amp;&amp; $x + $amount + $curr_tile-&gt;[1] &gt; 9;
+ return if $direction eq &#39;down&#39;
+ &amp;&amp; int($y + $amount + $curr_tile-&gt;[2]) &gt; 22;
+
+ return if $direction eq &#39;right&#39;
+ &amp;&amp; $store-&gt;[ $x + $amount +
+ $curr_tile-&gt;[1] +
+ 10 * int($y + $curr_tile-&gt;[2]) ];
+ return if $direction eq &#39;left&#39;
+ &amp;&amp; $store-&gt;[ $x - $amount +
+ $curr_tile-&gt;[1] +
+ 10 * int($y + $curr_tile-&gt;[2]) ];
+ return if $direction eq &#39;down&#39;
+ &amp;&amp; $store-&gt;[ $x +
+ $curr_tile-&gt;[1]
+ + 10 * int($y + $amount +
+ $curr_tile-&gt;[2]) ];
+ }
+ }
+ }
+
+ return 1;
+ }</code></pre>
+
+<p>All of the pieces are in place to move the piece: make the collision
+check, then place the piece into the appropriate grid for its next
+position:</p>
+
+<pre><code> sub move_piece {
+ my $direction = shift;
+ my $amount = shift || 1;
+
+ if ($direction eq &#39;right&#39;) {
+ $curr_tile-&gt;[1] += $amount;
+ }
+ elsif ($direction eq &#39;left&#39;) {
+ $curr_tile-&gt;[1] -= $amount;
+ }
+ elsif ($direction eq &#39;down&#39;) {
+ $curr_tile-&gt;[2] += $amount;
+ }
+
+ @{$grid} = ();
+
+ for my $y (0..3) {
+ for my $x (0..3) {
+ if ($curr_tile-&gt;[0]-&gt;[$x + 4 * $y]) {
+ $grid-&gt;[ $x + $curr_tile-&gt;[1] +
+ 10 * ($y + int($curr_tile-&gt;[2])) ]
+ = $curr_tile-&gt;[0]-&gt;[$x + 4 * $y];
+ }
+ }
+ }
+ }
+
+ sub store_piece {
+ for my $y (0..3) {
+ for my $x (0..3) {
+ if ($curr_tile-&gt;[0]-&gt;[$x + 4 * $y]) {
+ $store-&gt;[ $x + $curr_tile-&gt;[1] + 10 *
+ ($y + int($curr_tile-&gt;[2])) ]
+ = $curr_tile-&gt;[0]-&gt;[$x + 4 * $y];
+ }
+ }
+ }
+ }</code></pre>
+
+<p>Of course this all needs an event handler to attempt to move the pieces
+appropriately:</p>
+
+<pre><code> sub trigger_move_event_handler {
+ my ( $event, $app ) = @_;
+
+ if ( $event-&gt;type == SDL_KEYDOWN ) {
+ my $key = $event-&gt;key_sym;
+
+ if ( $event-&gt;key_sym &amp; (SDLK_LEFT|SDLK_RIGHT|SDLK_UP|SDLK_DOWN) ) {
+ if ($key == SDLK_LEFT &amp;&amp; can_move_piece(&#39;left&#39;)) {
+ move_piece(&#39;left&#39;);
+ }
+ elsif ($key == SDLK_RIGHT &amp;&amp; can_move_piece(&#39;right&#39;)) {
+ move_piece(&#39;right&#39;);
+ }
+ elsif ($key == SDLK_DOWN &amp;&amp; can_move_piece(&#39;down&#39;)) {
+ move_piece(&#39;down&#39;)
+ }
+ elsif ($key == SDLK_UP) {
+ $curr_tile-&gt;[0] = rotate_piece($curr_tile-&gt;[0]);
+ }
+ }
+ }
+ }
+
+ $app-&gt;add_event_handler( \&amp;trigger_move_event_handler );</code></pre>
<h3>Score and Game State</h3>
-<p>Next we add the move handler to update the game state. In tetris the
-game state can be summarized as the grid, current piece and the score. In
-this move handler we update all these things .</p>
+<p>The game state in Tetris is the combination of the fixed placement grid,
+the current piece, and the current score. The move handler can update all
+of these:</p>
-<pre><code> + $app-&gt;add_move_handler( sub {
- + my ( $step, $app ) = @_;</code></pre>
-
-<p>We update the current piece's state as movable or fixed.</p>
-
-<pre><code> + if(can_move_piece(&#39;down&#39;, $step / 2)) {
- + move_piece(&#39;down&#39;, $step / 2);
- + }
- + else {
- + store_piece($curr_tile); # placing the tile
- + </code></pre>
-
-<p>We update the status of the grid and see if there are lines to remove. +
-# checking for lines to delete + my $y; + my @to_delete = (); + for($y =
-22; $y >= 0; $y--) { + # there is no space if min of this row is true
-(greater than zero) + if(min(@{$store}[($y*10)..((($y+1)*10)-1)])) { +
-push(@to_delete, $y); + } + }</p>
-
-<p>When we delete lines increment the score of the user.</p>
-
-<pre><code> + # deleting lines
- + foreach(@to_delete) {
- + splice(@{$store}, $_*10, 10);
- + $score++;
- + }
- +
-Next for each deleted line we clear the grid.
- + # adding blank rows to the top
- + foreach(@to_delete) {
- + splice(@{$store}, 0, 0, (0,0,0,0,0,0,0,0,0,0));
- + }
- +
-Finally we lauch a new current tile if needed.
- + # launching new tile
- + @{$curr_tile-&gt;[0]} = @{$pieces{$next_tile}};
- + $curr_tile-&gt;[1] = 4;
- + $curr_tile-&gt;[2] = 0;
- + $next_tile = shuffle(keys %pieces);
- + }
- + });</code></pre>
-
-<h3>Showing the Game</h3>
-
-<p>In the show handler we iterate through each element in the store and
-grid array and place the right colored tile where needed (using the
-numbers).</p>
-
-<pre><code> + # renders game objects on the screen
- + $app-&gt;add_show_handler(
- + sub {
- + # first, we clear the screen
- + $app-&gt;draw_rect( [ 0, 0, $app-&gt;w, $app-&gt;h ], 0x000000 );
- + # and draw the background image
- + $back-&gt;blit( $app );
- + my $x = 0;
- + my $y = 0;
- + # draw the not moving tiles
- + foreach(@{$store}) {
- + $piece[$_]-&gt;blit( $app,
- + undef,
- + [ 28 + $x%10 * 20, 28 + $y * 20 ]
- + ) if $_;
- + $x++;
- + $y++ unless $x % 10;
- + }
- + $x = 0;
- + $y = 0;
- + # draw the moving tile
- + foreach(@{$grid}) {
- + $piece[$_]-&gt;blit( $app, undef, [ 28 + $x%10 * 20, 28 + $y * 20 ] ) if $_;
- + $x++;
- + $y++ unless $x % 10;
- + }
- + # the next tile will be...
- + my $next_tile_index = max(@{$pieces{$next_tile}});
- + for $y (0..3) {
- + for $x (0..3) {
- + if($pieces{$next_tile}-&gt;[$x + 4 * $y]) {
- + $piece[$next_tile_index]-&gt;blit( $app, undef,
- + [ 264 + $x * 20, 48 + $y * 20 ]
- + );
- + }
- + }
- + }</code></pre>
-
-<p>Lastly we draw texts needed.</p>
-
-<pre><code> + $score_text-&gt;write_xy( $app, 248, 20, &quot;Next Piece&quot; );
- + $score_text-&gt;write_xy( $app, 248, 240, &quot;Score: $score&quot; );
- + # finally, we update the screen
- + $app-&gt;update;
- + }
- + );
-
- + # all is set, run the app!
- + $app-&gt;run();</code></pre>
+<pre><code> $app-&gt;add_move_handler( sub {
+ my ( $step, $app ) = @_;</code></pre>
+
+<p>Start by updating the current piece's state as movable or fixed:</p>
+
+<pre><code> if (can_move_piece(&#39;down&#39;, $step / 2)) {
+ # still movable
+ move_piece(&#39;down&#39;, $step / 2);
+ }
+ else {
+ # place the tile
+ store_piece($curr_tile);</code></pre>
+
+<p>Then update the state of the grid and check for lines to remove:</p>
+
+<p>Why count backwards? This seems like it could be <code>for my $y (0 ..
+22)</code>. Maybe the question is whether to remove rows from the bottom up
+or the top down.</p>
+
+<pre><code> # checking for lines to delete
+ my $y;
+ my @to_delete);
+
+ for($y = 22; $y &gt;= 0; $y--) {
+ # if the min value of this row is 0,
+ # it contains at least one open space
+ if (min( @{$store}[ ($y * 10)..((( $y + 1) *10 ) -1 )])) {
+ push @to_delete, $y;
+ }
+ }</code></pre>
+
+<p>Deleting a line should increment the user's score:</p>
+
+<pre><code> # deleting lines
+ foreach (@to_delete) {
+ splice @{$store}, $_ * 10, 10;
+ $score++;
+ }</code></pre>
+
+<p>... and should clear that line off of the fixed grid:</p>
+
+<p>These loops should merge.</p>
+
+<pre><code> # adding blank rows to the top
+ foreach (@to_delete) {
+ splice @{$store}, 0, 0, (0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+ }
+ </code></pre>
+
+<p>... and the game should launch a new tile.</p>
+
+<pre><code> # launching new tile
+ @{$curr_tile-&gt;[0]} = @{ $pieces{$next_tile} };
+ $curr_tile-&gt;[1] = 4;
+ $curr_tile-&gt;[2] = 0;
+ $next_tile = shuffle keys %pieces;
+ }
+ });</code></pre>
+
+<h3>Drawing the Game</h3>
+
+<p>Those are the mechanics. How about displaying the game? The show handler
+needs to iterate through all of the elements in both grids and draw the
+appropriate tile:</p>
+
+<pre><code> $app-&gt;add_show_handler(
+ sub {
+ # first clear the screen
+ $app-&gt;draw_rect( [ 0, 0, $app-&gt;w, $app-&gt;h ], 0x000000 );
+
+ # and draw the background image
+ $back-&gt;blit( $app );
+ my $x = 0;
+ my $y = 0;
+
+ # draw the fixed tiles
+ foreach (@{$store}) {
+ $piece[$_]-&gt;blit( $app,
+ undef,
+ [ 28 + $x%10 * 20, 28 + $y * 20 ]
+ ) if $_;
+ $x++;
+ $y++ unless $x % 10;
+ }
+
+ $x = 0;
+ $y = 0;
+
+ # draw the moving tile
+ foreach (@{$grid}) {
+ $piece[$_]-&gt;blit( $app, undef,
+ [ 28 + $x % 10 * 20, 28 + $y * 20 ] ) if $_;
+ $x++;
+ $y++ unless $x % 10;
+ }
+
+ # the next tile will be...
+ my $next_tile_index = max( @{$pieces{$next_tile}} );
+ for $y (0..3) {
+ for $x (0..3) {
+ if ($pieces{$next_tile}-&gt;[$x + 4 * $y]) {
+ $piece[$next_tile_index]-&gt;blit( $app, undef,
+ [ 264 + $x * 20,
+ 48 + $y * 20 ]
+ );
+ }
+ }
+ }</code></pre>
+
+<p>... and should draw the score:</p>
+
+<pre><code> $score_text-&gt;write_xy( $app, 248, 20, &quot;Next Piece&quot; );
+ $score_text-&gt;write_xy( $app, 248, 240, &quot;Score: $score&quot; );
+
+ # finally, update the screen
+ $app-&gt;update;
+ }
+ );
+
+ # all is set, run the app!
+ $app-&gt;run();</code></pre>
<h2>Author</h2>
View
BIN  dist/SDL_Manual.pdf
Binary file not shown
Please sign in to comment.
Something went wrong with that request. Please try again.