Explore MIT App Inventor - Game http://dev-explore.appinventor.mit.edu/tutorial-type/game en Mini Golf: Fling, TouchUp, TouchDown Gestures for App Inventor 2 http://dev-explore.appinventor.mit.edu/ai2/minigolf <div class="field field-name-body field-type-text-with-summary field-label-hidden view-mode-rss"><div class="field-items"><div class="field-item even" property="content:encoded"><p>This Mini Golf App demonstrates how to use the Fling, TouchUp, and TouchDown gestures for Sprites<br />Note that these event handlers are also available for the Canvas.</p> <p><img src="/sites/all/files/ai2tutorials/miniGolf/minigolfscreen.png" style="float: right;border:none" width="250" /></p> <p>To play this mini golf app, the player first positions his/her ball within the confines of the tee, and then flings the ball toward the hole. The ball will bounce off of the rectangular obstacle and the sides of the course. For each fling of the ball, the stroke count goes up by one. The total score is the number of strokes it takes to complete the entire course. </p> <p>This tutorial covers:</p> <ul><li>Using the <b>Sprite</b> component and the TouchUp, TouchDown, and Flung events</li> <li>Using a <b>Clock</b> component</li> <li>Dynamic Positioning of sprites on a canvas, based on the size of the screen</li> <li>Sprite Collisions</li> </ul><p>This tutorial assumes you are familiar with the basics of App Inventor-- using the Component Designer to build a user interface, and using the Blocks Editor to specify the app's behavior. If you are not familiar with the basics, try stepping through some of the <a href="http://appinventor.mit.edu/explore/ai2/tutorials.html">basic tutorials</a> before continuing.</p> <p><a href="/sites/all/files/ai2tutorials/miniGolf/MiniGolf_MIT.aia"><img src="/sites/all/files/tutorials/miniGolf/downloadSourcebutton.png" style="float: right; border:none" width="250" /></a><br /><br /><br /><br /></p> <hr /><h3>Part I: Start a new app and make a ball that responds to fling events</h3> <p>We'll build this app in stages, adding a little bit of the game at a time. Log into App Inventor and start a new project. Name it "MiniGolf". When the Design window opens notice that App Inventor automatically names the screen "Screen1", but you can set the Title of the screen, which will show up in the top bar of the app. Think of a title related to Mini Golf, or feel free to use the suggested title "Fling It Mini Golf", and type it into the Properties pane on the right side of the Designer.</p> <p>In the Screen Properties (shown in right-hand pane): Uncheck the checkbox labeled "Scrollable" so that the screen will not scroll when the app is running. Screens that are set to scroll do not have a height. We’ll need our screen to have a defined height in order to set up the golf course properly.</p> <p><strong>Add the following components in the Designer:</strong></p> <table cellpadding="0" cellspacing="0"><tbody><tr style="background-color: #EFEFEF; font-weight: bold;"><td> <p><strong>Component Type</strong></p> </td> <td> <p><strong>Palette Group</strong></p> </td> <td> <p><strong>What You'll Name It</strong></p> </td> <td> <p><strong>Purpose</strong></p> </td> <td> <p><strong>Properties</strong></p> </td> </tr><tr><td> <p>Canvas</p> </td> <td> <p>Basic</p> </td> <td> <p>Canvas1</p> </td> <td> <p>The canvas serves as the golf course</p> </td> <td> <p>Height: 300<br />Width: FillParent<br />BackgroundColor: Green (or whatever you like!)</p> </td> </tr><tr><td> <p>BallSprite</p> </td> <td> <p>Animation</p> </td> <td> <p>GolfBall</p> </td> <td> <p>This is the ball the player will fling to try to hit the Hole</p> </td> <td> <p>Radius = 10<br />Color: White (or your choice!)<br />Speed: 0<br />Interval: 1 (ms)</p> <p>Z = 2 (when sprites are overlapping, the one with the higher z will appear on top)</p> </td> </tr><tr><td> <p>BallSprite</p> </td> <td> <p>Animation</p> </td> <td> <p>Hole</p> </td> <td> <p>This will be the target for the GolfBall</p> </td> <td> <p>Radius = 15<br />Color: Black<br />Speed: 0</p> </td> </tr><tr><td> <p>Clock</p> </td> <td> <p>Basic</p> </td> <td> <p>Clock1</p> </td> <td> <p>The clock will fire continuously to control the movement of the ball</p> </td> <td> <p>Timer Always Fires</p> <p>Timer Enabled</p> <p>TimerInterval: 100</p> </td> </tr></tbody></table><p><strong>Open the Blocks Editor</strong></p> <p><strong>Program the behavior of the Ball:</strong></p> <p>First, use the <span class="eventblock">GolfBall.Flung</span> event handler to move the golf ball when it is flung. Notice how this event handler takes in 6 different arguments: </p> <ul><li><em>x</em>, the x position on the Canvas grid of the user's finger </li> <li><em>y</em>, the y position on the Canvas grid of the user's finger</li> <li><em>speed</em>, the speed of the user's flinging gesture</li> <li><em>heading</em>, the direction (in degrees) of the user's fling gesture</li> <li><em>xvel</em>, the speed in the x direction of the user's fling</li> <li><em>yvel</em>, the speed in the y direction of the user's fling</li> </ul><p>Essentially, you want to set the GolfBall sprite’s speed and heading to match the speed and heading of the player’s fling gesture. You may want to scale up the speed a little bit because the speed of the fling is a little slower than how a golf ball would move. You can play with this "scaling factor" to make the ball more or less responsive to a fling.</p> <p> <img src="/sites/all/files/ai2tutorials/miniGolf/golfBall.flung.png" /></p> <p><strong>Program the behavior of the clock:</strong></p> <p> Use timer event to slow ball down so it doesn’t bounce around forever.</p> <p>Each time the clock fires, it will reduce the speed of the ball slightly. Notice that if the ball is not moving then these blocks will do nothing. If you don’t have this then the ball will just bounce forever.</p> <p>You'll need to use the if mutator function to change the if block into an if-else block. For a summary of mutators, check out the <a href="http://appinventor.mit.edu/explore/ai2/support/concepts/mutators">Mutators page</a></p> <p><img src="/sites/all/files/ai2tutorials/miniGolf/clock1.timer.png" /></p> <p><strong>Program a new procedure called SetupNewHole:</strong></p> <p>This procedure will be called when a hole is scored and the ball has to be placed back at the starting point. Note that the <span class="callblock">Hole.MoveTo</span> block sets the hole up in a new random location for the next play.</p> <p><img src="/sites/all/files/ai2tutorials/miniGolf/setupNewHole.png" /></p> <p><strong>Program the Behavior of the Hole: </strong><span>When the ball collides with the hole, the ball disappears and resets at the bottom of the screen.</span></p> <p>Note: When you first drag out the <span class="eventblock">GolfBall.CollidedWith</span> event handler, the named parameter is called "other". Notice that the <span class="controlblock-ai2">if then</span> block tests to see if the object involved in the collision with the golf ball (<span class="variableblock">other</span>) is the black ball sprite representing the hole. You can't just put a text block with the word "Hole" in it, you must use the <span class="componentsetblock">component Hole</span><span> block, that can be found in the drawer for the Hole image sprite. Do not use a <span class="textblock-ai2">text block</span> here.</span></p> <p><img src="/sites/all/files/ai2tutorials/miniGolf/golfball.collidedwith.png" /></p> <pre class="ai-testing"><strong>Test this Behavior.</strong> Connect your device to AppInventor, or start the emulator to load your app. When you fling the ball it should move in the direction of your fling, with a speed similar to the strength of your fling. The ball should slow down as it moves, eventually stopping. When the ball hits the hole, the ball should reset at the bottom of the screen and the hole should move to a new random location.</pre><p> </p> <p><strong>Does your ball get stuck if it hits the edge? </strong></p> <p>This is easy to fix with the when <span class="eventblock">EdgeReached</span> event. Note that you can find the "edge" value block by using a <span class="variableblock">get</span> block and selecting "edge" from the dropdown.</p> <p><img src="/sites/all/files/ai2tutorials/miniGolf/golfBall.edgeReached.png" /></p> <p>Double check to make sure your code is right: fling the ball a few times and see that that ball now bounces off the edges of the course.</p> <h3>Part II: Keeping Score</h3> <p>Games are more fun if you have a way to see how you’re doing. Let’s add a stroke counter. In mini golf your score goes up as you take more strokes. The goal is to have the lowest score possible. Let’s show the player how many strokes she or he has taken on this hole. Let’s also show the number of strokes taken during the whole game.</p> <p> </p> <p>Go back to the Designer and set up the following components:</p> <p><a href="#" name="84f417a34cd2d904669a10a8f96b32bf41ae274b" id="84f417a34cd2d904669a10a8f96b32bf41ae274b"></a><a href="#" name="2" id="2"></a><br /></p><table cellpadding="0" cellspacing="0"><tbody><tr style="background-color: #EFEFEF; font-weight: bold;"><td> <p><strong>Component Type</strong></p> </td> <td> <p><strong>Palette Group</strong></p> </td> <td> <p><strong>What You’ll Name It</strong></p> </td> <td> <p><strong>Purpose</strong></p> </td> <td> <p><strong>Properties</strong></p> </td> </tr><tr><td> <p>Horizontal Arrangement</p> </td> <td> <p>Screen Arrangement</p> </td> <td> <p>HorizontalArrangement1</p> </td> <td> <p>Contains LabelScore and LabelStroke</p> </td> <td> <p>Place at top of screen</p> </td> </tr><tr><td> <p>Label1</p> </td> <td> <p>Basic</p> </td> <td> <p>LabelScore</p> </td> <td> <p>Displays the total stroke count for the entire game</p> </td> <td></td> </tr><tr><td> <p>Label2</p> </td> <td> <p>Basic</p> </td> <td> <p>LabelStroke</p> </td> <td> <p>Displays the stroke count for the hole the player is currently on</p> </td> <td></td> </tr></tbody></table><p>In the Blocks Editor, you can program updates to the Score and Stroke labels. First, set two new global variables called <span class="variableblock">StrokeCount</span> and <span class="variableblock">Score</span>, and set their initial values to 0.</p> <p><img src="/sites/all/files/ai2tutorials/miniGolf/scoreto0.png" /></p> <p>Then add the following blocks to the <span class="eventblock">GolfBall.Flung</span> event (red rectangle indicates new blocks):</p> <p><img src="/sites/all/files/ai2tutorials/miniGolf/golfball.flung_final.png" /></p> <p>Next add the following blocks to the Event that handles the ball hitting the hole:</p> <p><img src="/sites/all/files/ai2tutorials/miniGolf/golfball_collidewith.png" /></p> <pre class="ai-testing"><strong>Test the behavior.</strong> With these new changes, you should have a "Total Strokes" count and "This Hole" count at the top of the screen. When you fling the ball, the "This Hole" count  and "Total Strokes" count should both increase by one, and when you make the ball go into the hole the "This Hole" count should reset to 0.</pre><h3>Part III: Positioning Ball on Tee using TouchUp and TouchDown events</h3> <p>Ok, so now you’ve got a working game! Now let’s make it a little more interesting and fun. First we’ll add a Tee and let the player position the golf ball on the tee before they fling the ball.</p> <p><strong>Go back to the Designer and add three new image sprite components:</strong></p> <p><a href="#" name="f32e9ebd8bb0c367ac6b009ebba0af05e4eb1b4e" id="f32e9ebd8bb0c367ac6b009ebba0af05e4eb1b4e"></a><a href="#" name="1" id="1"></a><br /></p><table cellpadding="0" cellspacing="0"><tbody><tr style="background-color: #EFEFEF; font-weight: bold;"><td> <p><strong>Component Type</strong></p> </td> <td> <p><strong>Palette Group</strong></p> </td> <td> <p><strong>What You’ll Name It</strong></p> </td> <td> <p><strong>Purpose</strong></p> </td> <td> <p><strong>Properties</strong></p> </td> </tr><tr><td> <p>ImageSprite</p> </td> <td> <p>Animation</p> </td> <td> <p>Tee</p> </td> <td> <p>A rectangular area in which the player can position their ball before teeing off.</p> </td> <td> <p>Upload the Tee image (<a href="/sites/all/files/tutorials/miniGolf/tee_graphic.png">right click on this link</a>, or see below).</p> </td> </tr><tr><td> <p>ImageSprite</p> </td> <td> <p>Animation</p> </td> <td> <p>LeftSprite</p> </td> <td> <p>This is a left pointing arrow that the player will use to move the ball to the left on the tee</p> </td> <td> <p>Upload the left arrow graphic (<a href="/sites/all/files/tutorials/miniGolf/left_arrow.jpg">right click on this link</a></p> </td> </tr><tr><td> <p>ImageSprite</p> </td> <td> <p>Animation</p> </td> <td> <p>RightSprite</p> </td> <td> <p>This is a right pointing arrow that the player will use to move the ball to the left on the tee</p> </td> <td> <p>Upload the right arrow graphic (<a href="/sites/all/files/tutorials/miniGolf/right_arrow.jpg">right click on this link</a></p> </td> </tr></tbody></table><p><strong>Program the size of the canvas, and the placement of the ball and image sprites on the canvas:</strong></p> <p>First, program the setup of these components on the screen. It’s best to accommodate all different screen sizes by placing the sprites on the screen relative to the size of the screen. The blocks below show how to set up the screen <em>dynamically</em><span> so that everything fits the right way. We start off by making the canvas size based on the screen size, and then we place each sprite in relation to the width and height of the canvas. We'll make a procedure to do this for us. Try to understand all of these blocks before you move on.</span></p> <p><img src="/sites/all/files/ai2tutorials/miniGolf/preparescreen.png" /></p> <p><img src="/sites/all/files/ai2tutorials/miniGolf/golf_screen_init.png" /></p> <p><strong>Position the Golf Ball on the Tee using TouchUp and TouchDown on the Arrow sprites:</strong></p> <p>To handle this, first set up two global variables that are toggled each time an arrow is pressed.</p> <p><img src="/sites/all/files/ai2tutorials/miniGolf/global.png" /></p> <p><strong>Program the behavior of the Right and Left Arrows</strong></p> <p>The left and right arrows are image sprites, so they come equipped with the ability to know when the player is is holding his/her finger down on them. The following blocks toggle the global variables based on whether the user is pressing either of these arrows.</p> <p><img src="/sites/all/files/ai2tutorials/miniGolf/spriteTouchDown.png" /></p> <p><strong>Procedure MoveBallOnTee:</strong></p> <p>Make a new procedure <span class="callblock-ai2">MoveBallOnTee</span> that makes the golf ball move left or right on the tee depending on the global variables. Although the math here looks complicated, it’s pretty simple. If the ball is supposed to move left, you first check to make sure that moving the ball 2 pixels left will not exceed the left-most coordinate of the Tee. If moving the golf ball to the right, you first check that moving the ball right 2 pixels will not move it past the right-most coordinate of the Tee.</p> <p><em>Note: if blocks look different in this image than on your own screen, this is because they were aligned differently. If you right click on the blocks, a list of options will appear and one of them is external inputs. When you select this, it will change how the blocks are configured. It does not change how the blocks function. If you want to change this, right click again and select internal inputs.</em></p> <p><img src="/sites/all/files/ai2tutorials/miniGolf/moveBallOnTee.png" /></p> <p><strong>MoveBallOnCourse Procedure</strong></p> <p>Note that the blocks that we had inside the <span class="basicblock">Clock1.Timer</span> event are now moved over to a new procedure called <span class="callblock-ai2"> MoveBallOnCourse: </span></p> <p><img src="/sites/all/files/ai2tutorials/miniGolf/moveBallOnCourse.png" /></p> <p>On each new course, players can position the ball on the tee before attempting to fling the ball toward the hole. To program this, you first have to check to make sure this is a new course and the ball has not been flung yet. If <span class="variableblock">StrokeCount</span> = 0 then we know this course is brand new and the player has not yet attempted to get the ball into the hole.</p> <p><img src="/sites/all/files/ai2tutorials/miniGolf/timer_final.png" /></p> <p>As the blocks above show, after verifying that the StrokeCount is 0, you then want to proceed to move the golf ball left or right depending on which arrow is being pressed. </p> <pre class="ai-testing"><strong>Test the behavior.</strong> Make sure your app is doing what you expect: play the game on your device or emulator. Before you tee off, are you able to move the ball left and right on the tee by using the left and right arrows? After you tee off, you should no longer be able to use the left and right arrows (pressing them will do nothing). After the ball goes into the hole and the screen resets, you should then be able to move the ball left and right on the tee before teeing off again.</pre><p><strong>Keep track of the number of holes played, and allow a game reset</strong></p> <p>The game is working pretty well now, but what about giving the player a way to reset the game? Also, it would be nice to give the player some instructions so they know how to play the game. While we’re at it, let’s also give an indication of how many holes the player has completed. Add the following components in the Designer:</p> <p><a href="#" name="0899df2ccc45cb7f22bfe41d004593ed854f9f2c" id="0899df2ccc45cb7f22bfe41d004593ed854f9f2c"></a><a href="#" name="3" id="3"></a><br /></p><table cellpadding="0" cellspacing="0"><tbody><tr style="background-color: #EFEFEF; font-weight: bold;"><td> <p><strong>Component Type</strong></p> </td> <td> <p><strong>Palette Group</strong></p> </td> <td> <p><strong>What You’ll Name It</strong></p> </td> <td> <p><strong>Purpose</strong></p> </td> <td> <p><strong>Properties</strong></p> </td> </tr><tr><td> <p>Horizontal Arrangement2</p> </td> <td> <p>Screen Arrangement</p> </td> <td> <p>Horizontal Arrangement2</p> </td> <td> <p>Contains the NewGame button and the HoleNum label</p> </td> <td></td> </tr><tr><td> <p>Button</p> </td> <td> <p>Basic</p> </td> <td> <p>ButtonNewGame</p> </td> <td> <p>Resets the game to Hole #1 with a score of 0.</p> </td> <td> <p>Text: "New Game"</p> </td> </tr><tr><td> <p>Label3</p> </td> <td> <p>Basic</p> </td> <td> <p>LabelHoleNum</p> </td> <td> <p>Displays the current hole number, increments by one each time a hole is completed.</p> </td> <td> <p>Text = "Hole # 1"<br />Font: bold, 28, blue<br /></p> </td> </tr><tr><td> <p>Label4</p> </td> <td> <p>Basic</p> </td> <td> <p>LabelInstruct</p> </td> <td> <p>Displays instructions</p> </td> <td> <p>Text = "Use arrows to position ball on tee. Hit the ball by flinging it with your finger."</p> </td> </tr></tbody></table><p>Define a new global variable to keep track of the Hole Number:</p> <p><img src="/sites/all/files/ai2tutorials/miniGolf/holecount.png" /></p> <p>Add the following blocks to the <span class="callblock-ai2">SetupNewHole</span> procedure: set <span class="setblock">global HoleCount</span> and set <span class="setblock">LabelHoleNum.Text</span>...</p> <p><img src="/sites/all/files/ai2tutorials/miniGolf/setup_final.png" /></p> <p>Program the "New Game" button’s behavior, which is pretty simple. When the button is pressed, set up a new course and reset both the hole stroke counter and total stroke counter to zero. Also set the hole number back to 1, by displaying "Hole #1" in LabelHoleNum. The blocks look like this:</p> <p><img src="/sites/all/files/ai2tutorials/miniGolf/buttonNewGame.png" /></p> <pre class="ai-testing"><strong>Test the behavior.</strong><p> Go back to your device or emulator and play the game some more. Now you should see the Hole # displayed in the lower right. Hitting "New Game" button should reset the game, returning both scores to 0, resetting the screen, and setting the Hole number to #1.</p></pre><h3>Part IV: Introduce an Obstacle</h3> <p>Most mini golf courses have obstacles on them. Let’s add a simple rectangular obstacle that will randomly position itself on the course somewhere between the Tee and the Hole. Each time a new course is presented, the obstacle will move, just the same way the Hole moves each time a new course is set up.</p> <p><strong>Add the following component in the Designer:</strong></p> <p><a href="#" name="981d9864ae92d2e44bbc01311278b4463bf01a1e" id="981d9864ae92d2e44bbc01311278b4463bf01a1e"></a><a href="#" name="4" id="4"></a></p> <table cellpadding="0" cellspacing="0"><tbody><tr style="background-color: #EFEFEF; font-weight: bold;"><td> <p><strong>Component Type</strong></p> </td> <td> <p><strong>Palette Group</strong></p> </td> <td> <p><strong>What You’ll Name It</strong></p> </td> <td> <p><strong>Purpose</strong></p> </td> <td> <p><strong>Properties</strong></p> </td> </tr><tr><td> <p>ImageSprite</p> </td> <td> <p>Animation</p> </td> <td> <p>ObstacleSprite1</p> </td> <td> <p>This sprite will be somewhere between the golf ball and hole and will make it harder to get the ball into the hole</p> </td> <td> <p>Upload the obstacle (rectangle) graphic (<a href="/sites/all/files/tutorials/miniGolf/golf_obstacle1.png">right click on this link</a>, or see below).</p> </td> </tr></tbody></table><p>Program the behavior of the obstacle in the blocks editor. First, set the behavior for when the ball hits the obstacle.  *Note: Using Heading = 0 - heading works because we are dealing with bouncing off of horizonal surfaces, this will not work for bouncing off of vertical or inclined surfaces. For our purposes, it works all right. See Challenge #2 below for more information.</p> <p><img src="/sites/all/files/ai2tutorials/miniGolf/obstaclecollide.png" /></p> <p>Each time the course is reset, position the obstacle will be positioned randomly. Add these blocks to the <span class="callblock-ai2">SetupNewHole</span> procedure:</p> <p><img src="/sites/all/files/ai2tutorials/miniGolf/addtosetup.png" /></p> <pre class="ai-testing"><strong>Test the behavior.</strong> Play the game again. Notice that the ball bounces off when it hits the obstacle. When the ball goes into the hole, or when the New Game button is pressed, the obstacle appears in a new location somewhere between the tee and the hole.</pre><p>That’s it! Share your game with friends by building an APK or by downloading the source and sharing the zip file with other App Inventors!<br /></p> <h3>Part V: Challenges</h3> <p>Here are some extra challenges to make your game better.</p> <p><strong>Challenge 1:</strong> Program the Ball to Hole collision so that the ball only goes into the hole if the golf ball’s speed is not too fast. In real mini golf, the ball will bounce right over the hole if you hit the ball too hard.</p> <p><strong>Challenge 2:</strong> There is a slight bug when the ball hits the vertical sides of obstacle. Figure out how to program the ball to obstacle collision so that it bounces the way you would expect when the ball hits the vertical sides.</p> <p><strong>Challenge 3:</strong> Limit the number of holes per game. Keep track of the number of holes and end the game after a set number. (A typical mini golf course has 18 holes.)</p> <p>Below is a summary of all of the components:</p> <p><img src="/sites/all/files/ai2tutorials/miniGolf/components.png" /></p> <p>Scan the following barcode onto your phone to install and run the sample app. </p><p><img src="http://explore.appinventor.mit.edu/sites/all/files/ai2tutorials/miniGolf/MiniGolfBarcode.png" /></p> <h4 class="ai-header">Download Source Code</h4> <p>If you'd like to work with this sample in App Inventor, download the <a href="http://explore.appinventor.mit.edu/sites/all/files/ai2tutorials/miniGolf/MiniGolf_MIT.aia">source code</a> to your computer, then open App Inventor, go to the My Projects page, and choose <b>More Actions | Upload Source</b>.</p> <pre class="ai-box"><span style="color:black;">Done with Mini Golf?</span> <a href="http://explore.appinventor.mit.edu/ai2/tutorials">Return to the other tutorials</a>.</pre></div></div></div><section class="field field-name-field-version field-type-taxonomy-term-reference field-label-above view-mode-rss clearfix"> <h2 class="field-label">Tutorial Version:&nbsp;</h2> <ul class="field-items"> <li class="field-item even"> <a href="/tutorial-version/app-inventor-2" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">App Inventor 2</a> </li> </ul> </section> <section class="field field-name-field-tutorial-difficulty field-type-taxonomy-term-reference field-label-above view-mode-rss clearfix"> <h2 class="field-label">Tutorial Difficulty:&nbsp;</h2> <ul class="field-items"> <li class="field-item even"> <a href="/tutorial-difficulty/advanced" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">Advanced</a> </li> </ul> </section> <section class="field field-name-field-tutorial-type field-type-taxonomy-term-reference field-label-above view-mode-rss clearfix"> <h2 class="field-label">Tutorial Type:&nbsp;</h2> <ul class="field-items"> <li class="field-item even"> <a href="/tutorial-type/clock-timer" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">Clock Timer</a> </li> <li class="field-item odd"> <a href="/tutorial-type/game" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">Game</a> </li> <li class="field-item even"> <a href="/tutorial-type/sprites" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">Sprites</a> </li> </ul> </section> Wed, 07 Aug 2013 14:13:24 +0000 joanie 379 at http://dev-explore.appinventor.mit.edu http://dev-explore.appinventor.mit.edu/ai2/minigolf#comments MoleMash for App Inventor 2 http://dev-explore.appinventor.mit.edu/ai2/molemash <div class="field field-name-body field-type-text-with-summary field-label-hidden view-mode-rss"><div class="field-items"><div class="field-item even" property="content:encoded"><p><img style="float:right;" src="/sites/all/files/ai2tutorials/moleMash/MoleOnEmulator.png" /></p> <p>In the game <span style="color:green;">MoleMash</span>, a mole pops up at random positions on a playing field, and the player scores points by hitting the mole before it jumps away. This tutorial shows how to build <span style="color:green;">MoleMash</span> as an example of a simple game that uses animation.</p> <p>The tutorial assumes that you have completed the <a href="http://explore.appinventor.mit.edu/ai2/hellopurr">HelloPurr</a> and <a href="/ai2/paintpot-part1">PaintPot</a> tutorials.</p> <p><a href="http://cs.usfca.edu/~wolber/appinventor/bookSplits/ch3MoleMash.pdf">Download Book Chapter (PDF)</a></p> <h4 class="ai-header">Getting Started</h4> <p>Connect to the App Inventor web site and start a new project. Name it "MoleMash", and also set the screen's <strong style="color:green;">Title</strong> to "MoleMash". Open the Blocks Editor and connect to the phone.</p> <p>Also download this <a href="/sites/all/files/ai2tutorials/moleMash/mole.png">picture of a mole</a> and save it on your computer.</p> <h4 class="ai-header">Introduction</h4> <p>You'll design the game so that the mole moves once every half-second. If it is touched, the score increases by one, and the phone vibrates. Pressing restart resets the score to zero.</p> <p>This tutorial introduces:</p> <ul><li>image sprites</li> <li>timers and the <strong>Clock</strong> component</li> <li>procedures</li> <li>picking random numbers between 0 and 1</li> <li>text blocks</li> <li>typeblocking</li> </ul><h4 class="ai-header">The first components</h4> <p>Several components should be familiar from previous tutorials:</p> <ul><li>A <strong>Canvas</strong> named "MyCanvas". This is the area where the mole moves.</li> <li>A <strong>Label</strong> named "ScoreLabel" that shows the score, i.e., the number of times the player has hit the mole.</li> <li>A <strong>Button</strong> named "ResetButton".</li> </ul><p>Drag these components from the Palette onto the Viewer and assign their names. Put <span style="color:green;">MyCanvas</span> on top and set its dimensions to 300 pixels wide by 300 pixels high. Set the <strong style="color:green;">Text</strong> of ScoreLabel to "Score: ---". Set the <strong style="color:green;">Text</strong> of ResetButton to "Reset". Also add a <strong>Sound</strong> component and name it "Noise". You'll use <span style="color:green;">Noise</span> to make the phone vibrate when the mole is hit, similar to the way you made the kitty purr in <span style="color:green;">HelloPurr</span>.</p> <h4 class="ai-header">Timers and the Clock component</h4> <p>You need to arrange for the mole to jump periodically, and you'll do this with the aid of a <strong>Clock</strong> component. The Clock component provides various operations dealing with time, like telling you what the date is. Here, you'll use the component as a timer that fires at regular internals. The firing interval is determined by the Clock 's <strong style="color:green;">TimerInterval</strong> property. Drag out a Clock component; it will go into the non-visible components area. Name it "MoleTimer". Set its TimeInterval to 500 milliseconds to make the mole move every half second. Make sure that <strong style="color:green;">Enabled</strong> is checked.</p> <h4 class="ai-header">Adding an Image Sprite</h4> <p>To add the moving mole we'll use a <em>sprite</em>.</p> <p>Sprites are images that can move on the screen within a Canvas. Each sprite has a <strong style="color:green;">Speed</strong> and a <strong style="color:green;">Heading</strong>, and also an <strong style="color:green;">Interval</strong> that determines how often the sprite moves at its designated speed. Sprites can also detect when they are touched. In <span style="color:green;">MoleMash</span>, the mole has a speed zero, so it won't move by itself. Instead, you'll be setting the mole's position each time the timer fires. Drag an <strong>ImageSprite</strong> component onto the Viewer. You'll find this component in the Animation category of the Palette. Place it within <span style="color:green;">MyCanvas</span> area. Set these properties for the Mole sprite:</p> <ul><li><strong style="color:green;">Picture</strong>: Use mole.png, which you downloaded to your computer at the beginning of this tutorial.</li> <li><strong style="color:green;">Enabled</strong>: checked</li> <li><strong style="color:green;">Interval</strong>: 500 (The interval doesn't matter here, because the mole's speed is zero: it's not moving by itself.)</li> <li><strong style="color:green;">Heading</strong>: 0 The heading doesn't matter here either, because the speed is 0.</li> <li><strong style="color:green;">Speed</strong>: 0.0</li> <li><strong style="color:green;">Visible</strong>: checked</li> <li><strong style="color:green;">Width</strong>: Automatic</li> <li><strong style="color:green;">Height</strong>: Automatic</li> </ul><p>You should see the <strong style="color:green;">x</strong> and <strong style="color:green;">y</strong> properties already filled in. They were determined by where you placed the mole when you dragged it onto <span style="color:green;">MyCanvas</span>. Go ahead and drag the mole some more. You should see <strong style="color:green;">x</strong> and <strong style="color:green;">y</strong> change. You should also see the mole on your connected phone, and the mole moving around on the phone as you drag it around in the Designer. You've now specified all the components. The Designer should look like this. Notice how <span style="color:green;">Mole</span> is indented under <span style="color:green;">MyCanvas</span> in the component structure list, indicating that the sprite is a sub-component of the canvas.</p> <p><img src="/sites/all/files/ai2tutorials/moleMash/MoleMashDesigner.png" /></p> <h4 class="ai-header">Component Behavior and Event Handlers</h4> <p>Now you'll specify the component behavior. This introduces some new App Inventor ideas. The first is the idea of a <em>procedure</em>. For an overview and explanation of procedures, check out the <a href="/ai2/support/concepts/procedures">Procedures page</a>.</p> <p>A procedure is a sequence of statements that you can refer to all at once as single command. If you have a sequence that you need to use more than once in a program, you can define that as a procedure, and then you don't have to repeat the sequence each time you use it. Procedures in App Inventor can take arguments and return values. This tutorial covers only the simplest case: procedures that take no arguments and return no values.</p> <h4 class="ai-header">Define Procedures</h4> <p>Define two procedures:</p> <ul><li><span class="callblock-ai2">MoveMole</span> moves the <span style="color:green;">Mole</span> sprite to a new random position on the canvas.</li> <li><span class="callblock-ai2">UpdateScore</span> shows the score, by changing the text of the <strong style="color:green;">ScoreLabel</strong></li> </ul><p>Start with MoveMole:</p> <ul><li>In the Blocks Editor, under Built-In, open the Procedures drawer. Drag out a <span class="callblock-ai2">to procedure</span> block and change the label "procedure" to "MoveMole".<br /><pre class="box">Note: There are two similar blocks: <span class="callblock-ai2">procedure then do</span> and <span class="callblock-ai2">procedure then resu;t</span>. Here you should use <span class="callblock-ai2">procedure then do</span>.</pre><p>The <span class="callblock-ai2">to MoveMole</span> block has a slot labeled "do". That's where you put the statements for the procedure. In this case there will be two statements: one to set the mole's x position and one to set its y position. In each case, you'll set the position to be a random fraction, between 0 and 1, of the difference between the size of the canvas and the size of the mole. You create that value using blocks for <span class="mathblock-ai2">random fraction</span> and multiplication and subtraction. You can find these in the Math drawer.</p></li> <li>Build the <span style="color:green;">MoveMole</span> procedure. The completed definition should look like this:<br /><img src="/sites/all/files/ai2tutorials/moleMash/MoveMole.png" /><br /><span style="color:green;">MoveMole</span> does not take any arguments so you don't have to use the <a href="/ai2/support/concepts/mutators">mutator</a> function of the procedure block. Observe how the blocks connect together: the first statement uses the <span class="setblock">Mole.X set</span> block to set mole's horizontal position. The value plugged into the block's socket is the result of multiplying: <ol><li>The result of the <span class="mathblock-ai2">call random fraction</span> block, which a value between 0 and 1</li> <li>The result of subtracting the mole's width from the canvas width</li> </ol><p>The vertical position is handled similarly.</p></li> </ul><p>With <span style="color:green;">MoveMole</span> done, the next step is to define a variable called <span style="color:green;">score</span> to hold the score (number of hits) and give it initial value 0. Also define a procedure <span class="callblock-ai2">UpdateScore</span> that shows the score in <span style="color:green;">ScoreLabel</span>. The actual contents to be shown in <span style="color:green;">ScoreLabel</span> will be the text "Score: " joined to the value of <span style="color:green;">score</span>.</p> <ul><li>To create the "Score: " part of the label, drag out a text block from the Text drawer. Change the block to read "Score: " rather than "text".</li> <li>Use a join block to attach this to a block that gives the value of the score variable. You can find the join block in the Text drawer.</li> </ul><p>Here's how <span style="color:green;">score</span> and <span class="callblock-ai2">UpdateScore</span> should look:</p> <p><img src="/sites/all/files/ai2tutorials/moleMash/UpdateScore.png" /></p> <h4 class="ai-header">Add a Timer</h4> <p>The next step is to make the mole keep moving. Here's where you'll use <span style="color:green;">MoleTimer</span>. Clock components have an event handler called <span class="eventblock">when ... Timer</span> that triggers repeatedly at a rate determined by the <strong style="color:green;">TimerInterval</strong>.</p> <p>Set up <span style="color:green;">MoleTimer</span> to call <span class="callblock-ai2">MoveMole</span> each time the timer fires, by building the event handler like this:</p> <p><img src="/sites/all/files/ai2tutorials/moleMash/MoleMashTimerEventHandler.png" /></p> <pre class="ai-box">Notice how the mole starts jumping around on the phone as soon as you define the event handler. This is an example of how things in App Inventor start happening instantaneously, as soon as you define them.</pre><h4 class="ai-header">Add a Mole Touch Handler</h4> <p>The program should increment the score each time the mole is touched. Sprites, like canvases, respond to touch events. So create a touch event handler for <span style="color:green;">Mole</span> that:</p> <ol><li>Increments the score.</li> <li>Calls <span class="callblock-ai2">UpdateScore</span> to show the new score.</li> <li>Makes the phone vibrate for 1/10 second (100 milliseconds).</li> <li>Calls <span class="callblock-ai2">MoveMole</span> so that the mole moves right away, rather than waiting for the timer.</li> </ol><p>Here's what this looks like in blocks. Go ahead and assemble the <span class="eventblock">when Mole.Touched</span> blocks as shown.</p> <p><img src="/sites/all/files/ai2tutorials/moleMash/MoleMashTouchEventHandler.png" /></p> <p>Here's a tip: You can use <a href="/tips/typeblocking">typeblocking</a>: typing to quickly create blocks.</p> <ul><li>To create a value block containing 100, just type 100 and press return.</li> <li>To create a <span class="callblock-ai2">MoveMole</span> block, just type <span class="callblock-ai2">MoveMole</span> and select the block you want from the list</li> </ul><h4 class="ai-header">Reset the Score</h4> <p>One final detail is resetting the score. That's simply a matter of making the <span style="color:green;">ResetButton</span> change the score to 0 and calling <span class="callblock-ai2">UpdateScore</span>.</p> <h4 class="ai-header">Complete Program</h4> <p>Here's the complete <span style="color:green;">MoleMash</span> program:</p> <p><img src="/sites/all/files/ai2tutorials/moleMash/MoleMashComplete.png" /></p> <h4 class="ai-header">Variations</h4> <p>Once you get the game working, you might want to explore some variations. For example:</p> <ul><li>Make the game vary the speed of the mole in response to how well the player is doing. To vary how quickly the mole moves, you'll need to change the <span style="color:green;">MoleTimer</span>'s <strong style="color:green;">Interval</strong> property.</li> <li>Keep track of when the player hits the mole and when the player misses the mole, and show a score with both hits and misses. To do this, you'll need do define touched handlers both for <span style="color:green;">Mole</span>, same as now, and for <span style="color:green;">MyCanvas</span>. One subtle issue, if the player touches the mole, does that also count as a touch for <span style="color:green;">MyCanvas</span>? The answer is yes. Both touch events will register.</li> </ul><h4 class="ai-header">Review</h4> <p>Here are some of the ideas covered in this project:</p> <ul><li>Sprites are touch-sensitive shapes that you can program to move around on a <strong>Canvas</strong>.</li> <li>The <strong>Clock</strong> component can be used as a timer to make events that happen at regular intervals.</li> <li>Procedures are defined using <span class="callblock-ai2">to</span> blocks.</li> <li>For each procedure you define, App Inventor automatically creates an associated call block and places it in the My Definitions drawer.</li> <li>Making a <span class="mathblock-ai2">random-fraction</span> block produces a number between 0 and 1.</li> <li>Text blocks specify literal text, similar to the way that number blocks specify literal numbers.</li> <li><a href="/tips/typeblocking">Typeblocking</a> is a way to create blocks quickly, by typing a block's name.</li> </ul><h4 class="ai-header">Scan the Sample App to your Phone</h4> <p>Scan the following barcode onto your phone to install and run the sample app. </p><p><img src="/sites/all/files/ai2tutorials/moleMash/MoleMashBarcode.png" /></p> <h4 class="ai-header">Download Source Code</h4> <p>If you'd like to work with this sample in App Inventor, download the <a href="/sites/all/files/ai2tutorials/moleMash/MoleMash.aia">source code</a> to your computer, then open App Inventor, go to the My Projects page, and choose <b>More Actions | Upload Source</b>.</p> <pre class="ai-box">Done with <span style="color:black;">MoleMash</span>? Return to the other tutorials <a href="/ai2/tutorials">here</a>.</pre></div></div></div><section class="field field-name-field-version field-type-taxonomy-term-reference field-label-above view-mode-rss clearfix"> <h2 class="field-label">Tutorial Version:&nbsp;</h2> <ul class="field-items"> <li class="field-item even"> <a href="/tutorial-version/app-inventor-2" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">App Inventor 2</a> </li> </ul> </section> <section class="field field-name-field-tutorial-difficulty field-type-taxonomy-term-reference field-label-above view-mode-rss clearfix"> <h2 class="field-label">Tutorial Difficulty:&nbsp;</h2> <ul class="field-items"> <li class="field-item even"> <a href="/tutorial-difficulty/basic" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">Basic</a> </li> </ul> </section> <section class="field field-name-field-tutorial-type field-type-taxonomy-term-reference field-label-above view-mode-rss clearfix"> <h2 class="field-label">Tutorial Type:&nbsp;</h2> <ul class="field-items"> <li class="field-item even"> <a href="/tutorial-type/clock-timer" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">Clock Timer</a> </li> <li class="field-item odd"> <a href="/tutorial-type/game" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">Game</a> </li> <li class="field-item even"> <a href="/tutorial-type/sprites" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">Sprites</a> </li> </ul> </section> Wed, 03 Jul 2013 14:29:42 +0000 aaron 356 at http://dev-explore.appinventor.mit.edu http://dev-explore.appinventor.mit.edu/ai2/molemash#comments MoleMash 2 for App Inventor 2 http://dev-explore.appinventor.mit.edu/ai2/molemash-2 <div class="field field-name-body field-type-text-with-summary field-label-hidden view-mode-rss"><div class="field-items"><div class="field-item even" property="content:encoded"><style> <!--/*--><![CDATA[/* ><!--*/ li { padding-bottom: 7px; } .basicblock { border: 1px dashed #7AA81C; padding-left: 4px; padding-right: 4px; padding-top: 1px; padding-bottom: 1px; background-color: #E7F2CB; font-size: 9pt; text-wrap: suppress; } .callblock { border: 1px dashed #000000; padding-left: 4px; padding-right: 4px; padding-top: 1px; padding-bottom: 1px; background-color: #E0D1FF; font-size: 9pt; text-wrap: suppress; } .argblock { border: 1px dashed #000000; padding-left: 4px; padding-right: 4px; padding-top: 1px; padding-bottom: 1px; background-color: #E5E5FF; font-size: 9pt; text-wrap: suppress; } .textblock { border: 1px dashed #000000; padding-left: 4px; padding-right: 4px; padding-top: 1px; padding-bottom: 1px; background-color: #FADAA0; font-size: 9pt; text-wrap: suppress; } .setblock { border: 1px dashed #000000; padding-left: 4px; padding-right: 4px; padding-top: 1px; padding-bottom: 1px; background-color: #C1D5F8; font-size: 9pt; text-wrap: suppress; } .controlblock { border: 1px dashed #000000; padding-left: 4px; padding-right: 4px; padding-top: 1px; padding-bottom: 1px; background-color: #FAEDBB; font-size: 9pt; text-wrap: suppress; } .listblock { border: 1px dashed #000000; padding-left: 4px; padding-right: 4px; padding-top: 1px; padding-bottom: 1px; background-color: #FCF5D7; font-size: 9pt; text-wrap: suppress; } /*--><!]]>*/ </style><h4 class="ai-header">What You're Building</h4> <p><img src="/sites/all/files/ai2tutorials/moleMash2/front-pic.png" style="float:right;" /></p> <p><a href="http://cs.usfca.edu/~wolber/appinventor/bookSplits/ch3MoleMash.pdf">Download Refined Version (Book Chapter PDF)</a></p> <p>This tutorial shows you how to build a game similar to the Whac-A-MoleTM arcade game. Specifically, your goal is to whack (tap) a mole that randomly pops out of one of five fixed holes. Every time you succeed, your score is increased by one point.</p> <p>In order to highlight new App Inventor features — the Advanced tab and Sprite Z-layering — this app takes a different approach than the <a href="http://explore.appinventor.mit.edu/ai2/molemash">original Mole Mash tutorial</a>, which you need not have read in order to do this one. You should, however, be familiar with the basics of App Inventor — using the Component Designer to build a user interface and using the Blocks Editor to specify event handlers. If you are not familiar with the basics, try stepping through some of the <a href="http://explore.appinventor.mit.edu/ai2/tutorials">basic tutorials</a> before continuing.</p> <h4 class="ai-header">Introduction</h4> <p>This tutorial includes:</p> <ol><li>Creating a list of components</li> <li>Using functionality from the Advanced section of the Blocks Editor to get and set properties of arbitrary components</li> <li>Having game events controlled by the <b>Clock</b> component</li> <li>Using Sprite Z-layering to ensure that one sprite (<b>ImageSprite</b> or <b>Ball</b>) appears in front of another</li> </ol><h4 class="ai-header">Getting Started</h4> <p>Connect to the App Inventor web site and start a new project. Set the screen's <b style="color:green;">Title</b> property to an appropriate name, such as "Mole Mash". Open the Blocks Editor and connect it to the phone. Download these image files (created by Yun Miao) by right-clicking on them, then add them to the project by pressing the "Add..." button in the Media pane.</p> <p><a href="/sites/all/files/ai2tutorials/moleMash2/hole.png"><img src="/sites/all/files/ai2tutorials/moleMash2/hole.png" /></a><a href="/sites/all/files/ai2tutorials/moleMash2/mole.png"><img src="/sites/all/files/ai2tutorials/moleMash2/mole.png" /></a></p> <h4 class="ai-header">Set up the Components</h4> <p>The user interface will contain a total of 6 ImageSprites: 5 unmoving holes and 1 mole, which will move on top of the holes. Use the component designer to create the user interface. When you are done, it should look something like the picture below. Don't worry about lining up the holes evenly. You will specify their locations through their <b style="color:green;">X</b> and <b style="color:green;">Y</b> properties. Additional instructions are below the picture.</p> <p><img src="/sites/all/files/ai2tutorials/moleMash2/designer1.png" /></p> <p>Create the following components by dragging them from the Palette into the Viewer.</p> <table><tr style="background-color: #EFEFEF; font-weight: bold;"><td> Component Type </td> <td> Palette Group </td> <td> What you'll name it </td> <td> Purpose of Component </td> </tr><tr><td> <b>Canvas</b> </td> <td>Basic</td> <td style="color:green;">GameCanvas</td> <td>The game field</td> </tr><tr><td> <b>ImageSprite</b> (5) </td> <td>Animation</td> <td style="color:green;">Hole1 ... Hole5</td> <td>Holes from which the mole can appear</td> </tr><tr><td> <b>ImageSprite</b> </td> <td>Animation</td> <td style="color:green;">Mole</td> <td>The mole</td> </tr><tr><td> <b>HorizontalArrangement</b> </td> <td>Screen Arrangement</td> <td style="color:green;">ScoreArrangement</td> <td>To display the score</td> </tr><tr><td> <b>Label</b> </td> <td>Basic</td> <td style="color:green;">ScoreTextLabel</td> <td>To hold "Score: "</td> </tr><tr><td> <b>Label</b> </td> <td>Basic</td> <td style="color:green;">ScoreValueLabel</td> <td>To hold the score (# of times the mole was hit)</td> </tr><tr><td> <b>Clock</b> </td> <td>Basic</td> <td style="color:green;">MoleClock</td> <td>To control the mole's movement</td> </tr><tr><td> <b>Sound</b> </td> <td>Media</td> <td style="color:green;">Buzzer</td> <td>To vibrate when the mole is touched</td> </tr></table><p>Make the following changes to the components' properties:</p> <table><tr style="background-color: #EFEFEF; font-weight: bold;"><td> Component </td> <td> Action </td> </tr><tr><td>Canvas1</td> <td>Set <b style="color:green;">BackgroundColor</b> to Green. Set <b style="color:green;">Width</b> to 320 pixels. Set <b style="color:green;">Height</b> to 320 pixels.</td> </tr><tr><td>Hole1</td> <td>Set <b style="color:green;">X</b> to 20 and <b style="color:green;">Y</b> to 60 (upper left).</td> </tr><tr><td>Hole2</td> <td>Set <b style="color:green;">X</b> to 130 and <b style="color:green;">Y</b> to 60 (upper center).</td> </tr><tr><td>Hole3</td> <td>Set <b style="color:green;">X</b> to 240 and <b style="color:green;">Y</b> to 60 (upper right)</td> </tr><tr><td>Hole4</td> <td>Set <b style="color:green;">X</b> to 75 and <b style="color:green;">Y</b> to 140 (lower left).</td> </tr><tr><td>Hole5</td> <td>Set <b style="color:green;">X</b> to 185 and <b style="color:green;">Y</b> to 140 (lower right).</td> </tr><tr><td>Mole</td> <td>Set <b style="color:green;">Picture</b> to "mole.png". Set <b style="color:green;">Z</b> to 2 so the mole appears in front of the other <b style="color:green;">ImageSprite</b> s, which have the default <b style="color:green;">Z</b> value of 1.</td> </tr><tr><td>ScoreTextLabel</td> <td>Set <b style="color:green;">Text</b> to "Score: ".</td> </tr><tr><td>ScoreTextValue</td> <td>Set <b style="color:green;">Text</b> to "0".</td> </tr></table><p>Don't worry now about setting the <b style="color:green;">Picture</b> property for the holes; we'll set the property in the Blocks Editor.</p> <h4 class="ai-header">Add Behaviors to the Components</h4> <p>Here is an overview of what we need to create blocks to do:</p> <ol><li>Create variables: <ol><li><b style="color:green;">holes</b>: a list of holes</li> <li><b style="color:green;">currentHole</b>: the hole the mole is currently coming out of</li> </ol></li> <li>When the app starts: <ol><li>Populate the list of holes.</li> <li>Set each hole's <b style="color:green;">Picture</b> property to "hole.png".</li> <li>Call procedure <span class="callblock">MoveMole</span> (below).</li> </ol></li> <li>Create a procedure <span class="callblock">MoveMole</span> to: <ol><li>Set <b style="color:green;">currentHole</b> to a random hole from the list <b style="color:green;">holes</b>.</li> <li>Move the mole to the location of <b style="color:green;">currentHole</b>.</li> </ol></li> <li>Make <b>MoleClock</b> call <span class="callblock">MoveMole</span> whenever its timer goes off (every second). </li> <li>Implement a handler that does the following when the mole is touched: <ol><li>Add one to the score.</li> <li>Make the phone briefly vibrate.</li> <li>Call <span class="callblock">MoveMole</span>.</li> </ol></li> </ol><p>To proceed, switch to the Blocks Editor.</p> <h4 class="ai-header">Creating Variables</h4> <p>Create the variables <b style="color:green;">holes</b> and <b style="color:green;">currentHole</b>. For now, we will give them "dummy" initial values; we'll set their real initial values in the <span class="basicblock">Screen1.Initialize</span> event handler, which is run when the app starts. (For technical reasons, components cannot be referred to in def blocks, which are run before the app has started.) Here is a picture and list of the blocks you will need:</p> <p><img src="/sites/all/files/ai2tutorials/moleMash2/blocks1.png" /></p> <table><tr style="background-color: #EFEFEF; font-weight: bold;"><td> Block type </td> <td> Drawer </td> <td> Purpose </td> </tr><tr><td><span class="setblock">def variable as</span> (holes)</td> <td>Definition</td> <td>Hold a list of holes.</td> </tr><tr><td><span class="listblock">make a list</span></td> <td>Lists</td> <td>Create an empty list, to be filled in when the program starts.</td> </tr><tr><td><span class="setblock">def variable as</span> (currentHole)</td> <td>Definition</td> <td>Hold the mole's current hole.</td> </tr><tr><td><span class="basicblock">number</span> (0)</td> <td>Numbers</td> <td>Provide a required initial value for <b style="color:green;">currentHole</b>.</td> </tr></table><p>As always, comments (created by right-clicking on a block) are encouraged but not required.</p> <h4 class="ai-header">Starting the App</h4> <p>The first event to occur in any program in <span class="basicblock">Screen1.Initialize</span>, so we will put start-up code in that handler. Specifically, we will add the hole components to the list holes, set each hole's <b style="color:green;">Picture</b> property to "hole.png", and call <span class="callblock">MoveMole</span>. Since we have not yet written MoveMole, we will create an empty procedure with that name, which we will fill in later.</p> <p>Below are a picture and table of the blocks you need to create. Note that the "Any ImageSprite" drawer is found under the "Advanced" tab to the right of "Built-In" and "My Blocks" in the Blocks Editor.</p> <p><img src="/sites/all/files/ai2tutorials/moleMash2/blocks2.png" /></p> <table><tr style="background-color: #EFEFEF; font-weight: bold;"><td> Block type </td> <td> Drawer </td> <td> Purpose </td> </tr><tr><td><span class="basicblock">Screen1.Initialize</span></td> <td>Screen1</td> <td>Specify what should happen when the app starts.</td> </tr><tr><td><span class="listblock">add items to list</span></td> <td>Lists</td> <td>Add the following values to...</td> </tr><tr><td><span class="argblock">holes</span></td> <td>My Definitions</td> <td>...the list of holes:</td> </tr><tr><td><span class="argblock">component Hole1</span></td> <td>Hole1</td> <td>-the upper left hole</td> </tr><tr><td><span class="argblock">component Hole2</span></td> <td>Hole2</td> <td>-the upper center hole</td> </tr><tr><td><span class="argblock">component Hole3</span></td> <td>Hole3</td> <td>-the upper right hole</td> </tr><tr><td><span class="argblock">component Hole4</span></td> <td>Hole4</td> <td>-the lower left hole</td> </tr><tr><td><span class="argblock">component Hole5</span></td> <td>Hole5</td> <td>-the lower right hole</td> </tr><tr><td><span class="controlblock">foreach</span></td> <td>Control</td> <td>Specify that we would like...</td> </tr><tr><td><span class="argblock">name</span> (hole)</td> <td>Definitions</td> <td>...a variable named "hole"...</td> </tr><tr><td><span class="argblock">holes</span></td> <td>My Definitions</td> <td>...to take on each of the values in the list holes .</td> </tr><tr><td><span class="setblock">ImageSprite.Picture</span></td> <td>Any Image Sprite</td> <td>Set the Picture property of...</td> </tr><tr><td><span class="argblock">value hole</span></td> <td>My Definitions</td> <td>...the ImageSprite referred to by the variable hole ...</td> </tr><tr><td><span class="textblock">text (hole.png)</span></td> <td>Text</td> <td>...to the picture of the empty hole.</td> </tr><tr><td><span class="callblock">to procedure</span> (MoveMole)</td> <td>Definition</td> <td>Create an procedure, to be filled in later, for moving the mole.</td> </tr><tr><td><span class="callblock">MoveMole</span></td> <td>My Definitions</td> <td>Call MoveMole to make the first placement of the mole.</td> </tr></table><p>Compare the <span class="controlblock">foreach</span> block to the equivalent blocks that would be necessary without it:</p> <p><img src="/sites/all/files/ai2tutorials/moleMash2/blocks_new_old.png" /></p> <p>Not only is the left set of blocks shorter, it is less repetitious, sparing the programmer from semi-mindless copy-and-pasting and making it easier to modify, for example, if the name of the picture is changed.</p> <h4 class="ai-header">Moving the Mole</h4> <p>Now let's fill in the body of the procedure MoveMole, which we'll call when the program starts, when the mole gets touched, and when our timer goes off every second. What we want it to do is to pick a random hole and move the mole on top of it. Here are a picture and list of the new blocks:</p> <p><img src="/sites/all/files/ai2tutorials/moleMash2/blocks4.png" /></p> <table><tr style="background-color: #EFEFEF; font-weight: bold;"><td> Block type </td> <td> Drawer </td> <td> Purpose </td> </tr><tr><td><span class="setblock">set currentHole to</span></td> <td>My Definitions</td> <td>Save the...</td> </tr><tr><td><span class="listblock">call pick random item</span></td> <td>Lists</td> <td>...randomly selected...</td> </tr><tr><td><span class="argblock">holes</span></td> <td>My Definitions</td> <td>...hole.</td> </tr><tr><td><span class="basicblock">call Mole.MoveTo</span></td> <td>Mole</td> <td>Move the mole to the...</td> </tr><tr><td><span class="argblock">ImageSprite.X</span></td> <td>Advanced/ImageSprite</td> <td>..x-coordinate of...</td> </tr><tr><td><span class="argblock">currentHole</span></td> <td>My Definitions</td> <td>...the chosen hole...</td> </tr><tr><td><span class="argblock">ImageSprite.Y</span></td> <td>Advanced/ImageSprite</td> <td>...and the y-coordinate of...</td> </tr><tr><td><span class="argblock">current Hole</span></td> <td>My Definitions</td> <td>...the chosen hole.</td> </tr></table><p>We now need to specify that MoveMole should be called whenever MoleClock's Timer goes off. We just need two blocks to accomplish that:</p> <p><img src="/sites/all/files/ai2tutorials/moleMash2/blocks5.png" /></p> <table><tr style="background-color: #EFEFEF; font-weight: bold;"><td> Block type </td> <td> Drawer </td> <td> Purpose </td> </tr><tr><td><span class="basicblock">MoleClock.Timer</span></td> <td>MoleClock</td> <td>When the timer goes off...</td> </tr><tr><td><span class="callblock">call MoveMole</span></td> <td>My Definitions</td> <td>...move the mole.</td> </tr></table><h4 class="ai-header">Registering Touches</h4> <p>Finally, we need to specify what happens when the mole is touched. Specifically, we want to:</p> <ol><li>Increment the score.</li> <li>Make the phone vibrate briefly.</li> <li>Move the mole.</li> </ol><p>We can easily translate these to blocks:</p> <p><img src="/sites/all/files/ai2tutorials/moleMash2/blocks6.png" /></p> <table><tr style="background-color: #EFEFEF; font-weight: bold;"><td> Block type </td> <td> Drawer </td> <td> Purpose </td> </tr><tr><td><span class="basicblock">Mole.Touched</span></td> <td>Mole</td> <td>When the mole is touched...</td> </tr><tr><td><span class="setblock">set ScoreValueLabel.Text to</span></td> <td>ScoreValueLabel</td> <td>...update the visible score to...</td> </tr><tr><td><span class="basicblock"> block</span></td> <td>Math</td> <td>...the result of adding...</td> </tr><tr><td><span class="basicblock">number</span> (1)</td> <td>Math</td> <td>...1 [and]...</td> </tr><tr><td><span class="argblock">ScoreValueLabel.Text</span></td> <td>ScoreValueLabel</td> <td>...the previous score.</td> </tr><tr><td><span class="callblock">call Buzzer.Vibrate</span></td> <td>Buzzer</td> <td>Make the phone vibrate for...</td> </tr><tr><td><span class="basicblock">number</span> (100)</td> <td>Math</td> <td>...100 milliseconds.</td> </tr><tr><td><span class="callblock">call MoveMole</span></td> <td>My Definitions</td> <td>Move the mole to a new location.</td> </tr></table><h4 class="ai-header">Final Program</h4> <p><img src="/sites/all/files/ai2tutorials/moleMash2/blocks-final.png" /></p> <h4 class="ai-header">Variations</h4> <p>Here are some variations you might want to implement:</p> <ul><li>Adding a Reset button to set the score back to 0.</li> <li>Having the score depend not just on the number of hits but also the number of misses and escaped moles.</li> <li>Increasing the speed of the game of mole movement if the player is doing well and decreasing it if the player is doing poorly.</li> <li>Adding a second mole on a different timer.</li> </ul><p>You can see how to implement the first two variations in the <a href="http://explore.appinventor.mit.edu/ai2/molemash">original Mole Mash tutorial</a>.</p> <h4 class="ai-header">Review</h4> <p>Here are some of the ideas covered in this tutorial:</p> <ul><li>Putting components in a <b>List</b>.</li> <li>Performing an operation on every component in a <b>List</b> using the <span class="controlblock">foreach</span> block and Advanced features.</li> <li>Placing an <b>ImageSprite</b> on top of another, using their <b style="color:green;">Z</b> properties to control which goes in front.</li> <li>Using the <b>Clock</b> component to control game play.</li> <li>Creating a procedure and calling it from multiple places.</li> </ul><pre class="ai-box">Done with <span style="color:black;">MoleMash 2</span>? Return to the other tutorials <a href="http://explore.appinventor.mit.edu/ai2/tutorials">here</a>.</pre><h4 class="ai-header">Scan the Sample App to your Phone</h4> <p>Scan the following barcode onto your phone to install and run the sample app. </p><p><img src="/sites/all/files/ai2tutorials/moleMash2/MoleMash2Barcode.png" /></p> <p>Or <a href="http://explore.appinventor.mit.edu/sites/all/files/ai2tutorials/moleMash2/MoleMash2.apk">download the apk</a></p> <h4 class="ai-header">Download Source Code</h4> <p>If you'd like to work with this sample in App Inventor, download the <a href="http://explore.appinventor.mit.edu/sites/all/files/ai2tutorials/moleMash2/MoleMash2.aia">source code</a> to your computer, then open App Inventor, go to the My Projects page, and choose <b>More Actions | Upload Source</b>.</p> </div></div></div><section class="field field-name-field-version field-type-taxonomy-term-reference field-label-above view-mode-rss clearfix"> <h2 class="field-label">Tutorial Version:&nbsp;</h2> <ul class="field-items"> <li class="field-item even"> <a href="/tutorial-version/app-inventor-2" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">App Inventor 2</a> </li> </ul> </section> <section class="field field-name-field-tutorial-difficulty field-type-taxonomy-term-reference field-label-above view-mode-rss clearfix"> <h2 class="field-label">Tutorial Difficulty:&nbsp;</h2> <ul class="field-items"> <li class="field-item even"> <a href="/tutorial-difficulty/advanced" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">Advanced</a> </li> </ul> </section> <section class="field field-name-field-tutorial-type field-type-taxonomy-term-reference field-label-above view-mode-rss clearfix"> <h2 class="field-label">Tutorial Type:&nbsp;</h2> <ul class="field-items"> <li class="field-item even"> <a href="/tutorial-type/clock-timer" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">Clock Timer</a> </li> <li class="field-item odd"> <a href="/tutorial-type/game" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">Game</a> </li> <li class="field-item even"> <a href="/tutorial-type/sprites" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">Sprites</a> </li> </ul> </section> Tue, 02 Jul 2013 14:47:11 +0000 aaron 349 at http://dev-explore.appinventor.mit.edu http://dev-explore.appinventor.mit.edu/ai2/molemash-2#comments Get the Gold for App Inventor 2 http://dev-explore.appinventor.mit.edu/ai2/get-gold <div class="field field-name-body field-type-text-with-summary field-label-hidden view-mode-rss"><div class="field-items"><div class="field-item even" property="content:encoded"><style> <!--/*--><![CDATA[/* ><!--*/ .ButtonText { color:green; font-weight: bold; } li { padding-bottom: 7px; } .basicblock { border: 1px dashed #7AA81C; padding-left: 4px; padding-right: 4px; padding-top: 1px; padding-bottom: 1px; background-color: #E7F2CB; font-size: 9pt; text-wrap: suppress; } .callblock { border: 1px dashed #000000; padding-left: 4px; padding-right: 4px; padding-top: 1px; padding-bottom: 1px; background-color: #E0D1FF; font-size: 9pt; text-wrap: suppress; } .argblock { border: 1px dashed #000000; padding-left: 4px; padding-right: 4px; padding-top: 1px; padding-bottom: 1px; background-color: #E5E5FF; font-size: 9pt; text-wrap: suppress; } .textblock { border: 1px dashed #000000; padding-left: 4px; padding-right: 4px; padding-top: 1px; padding-bottom: 1px; background-color: #FADAA0; font-size: 9pt; text-wrap: suppress; } .setblock { border: 1px dashed #000000; padding-left: 4px; padding-right: 4px; padding-top: 1px; padding-bottom: 1px; background-color: #C1D5F8; font-size: 9pt; text-wrap: suppress; } .controlblock { border: 1px dashed #000000; padding-left: 4px; padding-right: 4px; padding-top: 1px; padding-bottom: 1px; background-color: #FAEDBB; font-size: 9pt; text-wrap: suppress; } .listblock { border: 1px dashed #000000; padding-left: 4px; padding-right: 4px; padding-top: 1px; padding-bottom: 1px; background-color: #FCF5D7; font-size: 9pt; text-wrap: suppress; } /*--><!]]>*/ </style><h4 class="ai-header">What You're Building</h4> <p><img src="http://explore.appinventor.mit.edu/sites/all/files/ai2tutorials/GetTheGold/GetTheGoldMain.png" style="float:right; height: 453px; width: 197px;" /></p> <p> By building the <span style="color:green;">Get The Gold App</span> you will get practice with setting visibility, using Clock components and Timers, and detecting collisions in App Inventor. You'll program an application that has a pirate ship whose goal is to collect all the gold on the screen.</p> <h4 class="ai-header">Getting Started</h4> <p>Connect to the App Inventor web site and start a new project. Name it <span style="color:green;">GetTheGold</span>, and also set the screen's <strong style="color:green;">Title</strong> to "GetTheGold". Switch to the Blocks view and connect to a device or emulator.</p> <h4 class="ai-header">Introduction</h4> <p>This tutorial introduces the following skills, useful for future game development:</p> <ul><li>Using the Clock component</li> <li>Using Clock.Timer to move sprites</li> <li>Using Sprite.Flung to move a sprite </li> <li>Using collision detection</li> </ul><h4 class="ai-header">Getting Ready</h4> <p>For this game, you will have two types of imagesprites: pirate and gold coin. Click below to download the image file for your sprites.</p> <p><a href="http://explore.appinventor.mit.edu/sites/all/files/ai2tutorials/GetTheGold/pirateship.jpeg"><img src="http://explore.appinventor.mit.edu/sites/all/files/ai2tutorials/GetTheGold/pirateship.jpeg" /></a><br /><a href="http://explore.appinventor.mit.edu/sites/all/files/ai2tutorials/GetTheGold/goldcoin.jpeg"><img src="http://explore.appinventor.mit.edu/sites/all/files/ai2tutorials/GetTheGold/goldcoin.jpeg" /></a></p> <h4 class="ai-header">Set up the Components</h4> <p>Use the component designer to create the interface for <span style="color:green;">GetTheGold</span>. When you finish, it should look something like the snapshot below (more detailed instructions below the snapshot).</p> <p><img src="http://explore.appinventor.mit.edu/sites/all/files/ai2tutorials/GetTheGold/GetTheGoldDesigner.png" /></p> <p>To create this interface, put the following components into the Designer by dragging them from the Component Palette into the Viewer.</p> <table><tr style="background-color: #EFEFEF; font-weight: bold;"><td> Component Type </td> <td> Palette Group </td> <td> What you'll name it </td> <td> Purpose of Component </td> </tr><tr><td><strong>Canvas</strong></td> <td>Basic</td> <td style="color:green;">Canvas1</td> <td>The background that we will be putting our imagesprites on</td> </tr><tr><td><strong>ImageSprite</strong></td> <td>Animation</td> <td style="color:green;">PirateSprite</td> <td>The pirate ship in our game</td> </tr><tr><td><strong>ImageSprite</strong></td> <td>Animation</td> <td style="color:green;">ImageSprite2</td> <td>One of the gold coins in the game</td> </tr><tr><td><strong>ImageSprite</strong></td> <td>Animation</td> <td style="color:green;">ImageSprite3</td> <td>One of the gold coins in the game</td> </tr><tr><td><strong>ImageSprite</strong></td> <td>Animation</td> <td style="color:green;">ImageSprite4</td> <td>One of the gold coins in the game</td> </tr><tr><td><strong>ImageSprite</strong></td> <td>Animation</td> <td style="color:green;">ImageSprite5</td> <td>One of the gold coins in the game</td> </tr><tr><td><strong>ImageSprite</strong></td> <td>Animation</td> <td style="color:green;">ImageSprite6</td> <td>One of the gold coins in the game</td> </tr><tr><td><strong>Clock</strong></td> <td>Basic</td> <td style="color:green;">Clock1</td> <td>We use the Clock for its Timer method to move the coins</td> </tr><tr><td><strong>Button</strong></td> <td>Basic</td> <td style="color:green;">ResetButton</td> <td>To reset the game so the player can play again</td> </tr></table><p>Set the properties of the components as described below:</p> <table><tr style="background-color: #EFEFEF; font-weight: bold;"><td><strong>Component</strong></td> <td><strong>Action</strong></td> <td> </td> </tr><tr><td><span style="color:green;">ResetButton</span> </td> <td> Change <span class="ButtonText">Text</span> property to "Reset". </td> <td> </td> </tr><tr><td><span style="color:green;">PirateSprite</span> </td> <td> Change <span class="ButtonText">Speed</span> property to 6. </td> <td> Upload the pirateship image and set <span class="ButtonText">Picture</span> property to pirateship. </td> </tr><tr><td><span style="color:green;">ImageSprite(2,3,4,5,6)</span> </td> <td> Upload the goldcoin image and set <span class="ButtonText">Picture</span> property to goldcoin. </td> <td> </td> </tr><tr><td><span style="color:green;">Clock</span> </td> <td> Change <span class="ButtonText">TimerInterval</span> property to 2000. </td> <td> </td> </tr></table><h4 class="ai-header">Moving the Pirate</h4> <p> To move the PirateSprite, we want the user to be able to "fling" the sprite in the direction that they choose. To do this, we will use the <span class="eventblock">PirateSprite.Flung</span> event handler. </p> <p> You may notice that <span class="eventblock">PirateSprite.Flung</span> takes in 6 attributes: x, y, xvel, yvel, speed, and heading. We want to reassign PirateSprite's current heading to the heading given to us from PirateSprite.Flung. This means that the user can now control the direction of the pirate ship with their fingers by flinging on the screen. </p> <p><img src="http://explore.appinventor.mit.edu/sites/all/files/ai2tutorials/GetTheGold/PirateSpriteFlung.png" /></p> <p>To prevent the pirate from moving off the screen, we will also use PirateSprite.Bounce when an edge is reached. </p> <p><img src="http://explore.appinventor.mit.edu/sites/all/files/ai2tutorials/GetTheGold/PirateSpriteBounce.png" /></p> <h4 class="ai-header">Moving the Coins</h4> <p> We want the coins to move to random positions on the screen. We will use <span class="eventblock">Clock1.Timer </span> and the ImageSprite's MoveTo method to do this. </p> <p> When the Clock1.Timer goes off, we want all of our gold coin ImageSprites to move to a new random location on the Canvas. We will do this by using the <span class="callblock-ai2">Sprite.MoveTo</span> block. </p> <p>MoveTo takes in two arguments: the x and y coordinates on the canvas of the new position we want the sprite to move to. We want the Sprite to move to a new <i>random</i> location so we will use the <span class="mathblock-ai2">random integer</span> block found in the Math box. Since we want each Gold ImageSprite to move to a new location, we repeat this process for each sprite's MoveTo function. </p> <p>For ImageSprite2, we want x to be a random integer from 0 to <i>Canvas1.Width-ImageSprite2.Width</i> and y to be a random integer from 0 to <i>Canvas1.Height-ImageSprite2.Height</i>. This is to be repeated for all the Gold Image Sprites.</p> <p>Remember that sprites are measured at the upper left corner as (0,0) so if we don't want them to go off the screen, we need to take the sprite's height/width into account when setting the range for our random numbers.</p> <p>We will do this by setting up our blocks as in the image below:</p> <p><img src="http://explore.appinventor.mit.edu/sites/all/files/ai2tutorials/GetTheGold/ClockTimer.png" /></p> <h4 class="ai-header">Detecting Collisions</h4> <p> App Inventor detects collisions by checking for an intersection between the bounding rectangles of each ImageSprite. We call this rectangle-based collision detection. As you can see in the image below, sprites with circular or polygon shape will appear to collide because of the rectangular bounds around them when they might not actually be colliding.</p> <p><img src="http://explore.appinventor.mit.edu/sites/all/files/ai2tutorials/GetTheGold/CollisionDetection.png" /></p> <p>We can use the <span class="eventblock">PirateSprite.CollidedWith </span> event handler to detect whenever the pirate ship collides with another sprite or gold coin. You may notice that <span class="eventblock">PirateSprite.CollidedWith </span> takes in an argument. This argument is the object that PirateSprite just collided with. We will be testing inside the handler for which object so the name of this argument is not significant. You can name it other. </p> <p>Whenever the pirate collides with a gold coin, we want the coin to disappear. We can do this by setting the coin's visibility to false. To find which coin the pirate collided with, we will use the <span class="eventblock">PirateSprite.CollidingWith</span>. </p> <p> We can use <span class="eventblock">PirateSprite.CollidingWith</span> to take in a component (each of the gold coin sprites) to detect which sprite was hit. This is a component block and NOT a text block with the words ImageSprite inside. The component block can be found in the drawer for each component. If a sprite was hit, we will set its visibility to false. </p> <p><img src="http://explore.appinventor.mit.edu/sites/all/files/ai2tutorials/GetTheGold/CollisionSprites.png" /></p> <h4 class="ai-header">Reset Button</h4> <p>After the user hits all of the gold sprites with the pirate ship, none of them will be visible. The reset button should set all of the gold sprites' visibility to true. </p> <p><img src="http://explore.appinventor.mit.edu/sites/all/files/ai2tutorials/GetTheGold/ResetVis.png" /></p> <h4 class="ai-header">Complete Program</h4> <p>Here's the complete <strong><span style="color:green;">GetTheGold</span></strong> program.</p> <p><img src="http://explore.appinventor.mit.edu/sites/all/files/ai2tutorials/GetTheGold/GetTheGoldAll.png" /></p> <p>Package the final version of the app by choosing <strong>Package For Phone | Barcode</strong> from the Component Designer menu. When the barcode appears, use the barcode scanner on your phone to download and install the app.</p> <h4 class="ai-header">Variations</h4> <p>Once you get this program running, you may want to do the following additional features to extend it. For example,</p> <ul><li>Create a label to display the time that it took you to get all the gold</li> <li>Change the speed of the ship or gold coins</li> <li>Add an enemy sprite that when collided with, causes your pirate to lose speed</li> <li>Use one of the phone's sensors to control movement of the pirate ship </li> </ul><h4 class="ai-header">Scan the Sample App to your Phone</h4> <p>Scan the following barcode onto your phone to install and run the sample app. </p><p><img src="http://explore.appinventor.mit.edu/sites/all/files/ai2tutorials/GetTheGold/GetTheGoldBarcode.png" /></p> <h4 class="ai-header">Download Source Code</h4> <p>If you'd like to work with this sample in App Inventor, download the <a href="http://explore.appinventor.mit.edu/sites/all/files/ai2tutorials/GetTheGold/GetTheGold.aia">source code</a> to your computer, then open App Inventor, go to the My Projects page, and choose <b>More Actions | Upload Source</b>.</p> <p>Done with <span style="color:black;">GetTheGold</span>? Return to to the other App Inventor 2 tutorials <a href="http://explore.appinventor.mit.edu/ai2/tutorials">here</a>.</p> </div></div></div><section class="field field-name-field-version field-type-taxonomy-term-reference field-label-above view-mode-rss clearfix"> <h2 class="field-label">Tutorial Version:&nbsp;</h2> <ul class="field-items"> <li class="field-item even"> <a href="/tutorial-version/app-inventor-2" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">App Inventor 2</a> </li> </ul> </section> <section class="field field-name-field-tutorial-difficulty field-type-taxonomy-term-reference field-label-above view-mode-rss clearfix"> <h2 class="field-label">Tutorial Difficulty:&nbsp;</h2> <ul class="field-items"> <li class="field-item even"> <a href="/tutorial-difficulty/advanced" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">Advanced</a> </li> </ul> </section> <section class="field field-name-field-tutorial-type field-type-taxonomy-term-reference field-label-above view-mode-rss clearfix"> <h2 class="field-label">Tutorial Type:&nbsp;</h2> <ul class="field-items"> <li class="field-item even"> <a href="/tutorial-type/clock-timer" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">Clock Timer</a> </li> <li class="field-item odd"> <a href="/tutorial-type/game" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">Game</a> </li> <li class="field-item even"> <a href="/tutorial-type/sprites" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">Sprites</a> </li> </ul> </section> Mon, 01 Jul 2013 18:09:32 +0000 aaron 347 at http://dev-explore.appinventor.mit.edu http://dev-explore.appinventor.mit.edu/ai2/get-gold#comments Get the Gold http://dev-explore.appinventor.mit.edu/get-gold <div class="field field-name-body field-type-text-with-summary field-label-hidden view-mode-rss"><div class="field-items"><div class="field-item even" property="content:encoded"><style> <!--/*--><![CDATA[/* ><!--*/ .ButtonText { color:green; font-weight: bold; } li { padding-bottom: 7px; } .basicblock { border: 1px dashed #7AA81C; padding-left: 4px; padding-right: 4px; padding-top: 1px; padding-bottom: 1px; background-color: #E7F2CB; font-size: 9pt; text-wrap: suppress; } .callblock { border: 1px dashed #000000; padding-left: 4px; padding-right: 4px; padding-top: 1px; padding-bottom: 1px; background-color: #E0D1FF; font-size: 9pt; text-wrap: suppress; } .argblock { border: 1px dashed #000000; padding-left: 4px; padding-right: 4px; padding-top: 1px; padding-bottom: 1px; background-color: #E5E5FF; font-size: 9pt; text-wrap: suppress; } .textblock { border: 1px dashed #000000; padding-left: 4px; padding-right: 4px; padding-top: 1px; padding-bottom: 1px; background-color: #FADAA0; font-size: 9pt; text-wrap: suppress; } .setblock { border: 1px dashed #000000; padding-left: 4px; padding-right: 4px; padding-top: 1px; padding-bottom: 1px; background-color: #C1D5F8; font-size: 9pt; text-wrap: suppress; } .controlblock { border: 1px dashed #000000; padding-left: 4px; padding-right: 4px; padding-top: 1px; padding-bottom: 1px; background-color: #FAEDBB; font-size: 9pt; text-wrap: suppress; } .listblock { border: 1px dashed #000000; padding-left: 4px; padding-right: 4px; padding-top: 1px; padding-bottom: 1px; background-color: #FCF5D7; font-size: 9pt; text-wrap: suppress; } /*--><!]]>*/ </style><h4 class="ai-header">What You're Building</h4> <p><img src="http://explore.appinventor.mit.edu/sites/all/files/Teach/GetTheGold/GetTheGoldMain.png" style="float:right; height: 453px; width: 197px;" /></p> <p> By building the <span style="color:green;">Get The Gold App</span> you will get practice with setting visibility, using Clock components and Timers, and detecting collisions in App Inventor. You'll program an application that has a pirate ship whose goal is to collect all the gold on the screen.</p> <h4 class="ai-header">Getting Started</h4> <p>Connect to the App Inventor web site and start a new project. Name it <span style="color:green;">GetTheGold</span>, and also set the screen's <strong style="color:green;">Title</strong> to "GetTheGold". Open the Blocks Editor and connect to a device or emulator.</p> <h4 class="ai-header">Introduction</h4> <p>This tutorial introduces the following skills, useful for future game development:</p> <ul><li>Using the Clock component</li> <li>Using Clock.Timer to move sprites</li> <li>Using Sprite.Flung to move a sprite </li> <li>Using collision detection</li> </ul><h4 class="ai-header">Getting Ready</h4> <p>For this game, you will have two types of imagesprites: pirate and gold coin. Click below to download the image file for your sprites.</p> <p><a href="http://explore.appinventor.mit.edu/sites/all/files/Teach/GetTheGold/pirateship.jpeg"><img src="http://explore.appinventor.mit.edu/sites/all/files/Teach/GetTheGold/pirateship.jpeg" /></a><br /><a href="http://explore.appinventor.mit.edu/sites/all/files/Teach/GetTheGold/goldcoin.jpeg"><img src="http://explore.appinventor.mit.edu/sites/all/files/Teach/GetTheGold/goldcoin.jpeg" /></a></p> <h4 class="ai-header">Set up the Components</h4> <p>Use the component designer to create the interface for <span style="color:green;">GetTheGold</span>. When you finish, it should look something like the snapshot below (more detailed instructions below the snapshot).</p> <p><img src="http://explore.appinventor.mit.edu/sites/all/files/Teach/GetTheGold/GetTheGoldDesigner.png" /></p> <p>To create this interface, put the following components into the Designer by dragging them from the Component Palette into the Viewer.</p> <table><tr style="background-color: #EFEFEF; font-weight: bold;"><td> Component Type </td> <td> Palette Group </td> <td> What you'll name it </td> <td> Purpose of Component </td> </tr><tr><td><strong>Canvas</strong></td> <td>Basic</td> <td style="color:green;">Canvas1</td> <td>The background that we will be putting our imagesprites on</td> </tr><tr><td><strong>ImageSprite</strong></td> <td>Animation</td> <td style="color:green;">PirateSprite</td> <td>The pirate ship in our game</td> </tr><tr><td><strong>ImageSprite</strong></td> <td>Animation</td> <td style="color:green;">ImageSprite2</td> <td>One of the gold coins in the game</td> </tr><tr><td><strong>ImageSprite</strong></td> <td>Animation</td> <td style="color:green;">ImageSprite3</td> <td>One of the gold coins in the game</td> </tr><tr><td><strong>ImageSprite</strong></td> <td>Animation</td> <td style="color:green;">ImageSprite4</td> <td>One of the gold coins in the game</td> </tr><tr><td><strong>ImageSprite</strong></td> <td>Animation</td> <td style="color:green;">ImageSprite5</td> <td>One of the gold coins in the game</td> </tr><tr><td><strong>ImageSprite</strong></td> <td>Animation</td> <td style="color:green;">ImageSprite6</td> <td>One of the gold coins in the game</td> </tr><tr><td><strong>Clock</strong></td> <td>Basic</td> <td style="color:green;">Clock1</td> <td>We use the Clock for its Timer method to move the coins</td> </tr><tr><td><strong>Button</strong></td> <td>Basic</td> <td style="color:green;">ResetButton</td> <td>To reset the game so the player can play again</td> </tr></table><p>Set the properties of the components as described below:</p> <table><tr style="background-color: #EFEFEF; font-weight: bold;"><td><strong>Component</strong></td> <td><strong>Action</strong></td> </tr><tr><td><span style="color:green;">ResetButton</span> </td> <td> Change <span class="ButtonText">Text</span> property to "Reset". </td> <td> </td> </tr><tr><td><span style="color:green;">PirateSprite</span> </td> <td> Change <span class="ButtonText">Speed</span> property to 6. </td> <td> Upload the pirateship image and set <span class="ButtonText">Picture</span> property to pirateship. </td> </tr><tr><td><span style="color:green;">ImageSprite(2,3,4,5,6)</span> </td> <td> Upload the goldcoin image and set <span class="ButtonText">Picture</span> property to goldcoin. </td> <td> </td> </tr><tr><td><span style="color:green;">Clock</span> </td> <td> Change <span class="ButtonText">TimerInterval</span> property to 2000. </td> <td> </td> </tr></table><h4 class="ai-header">Moving the Pirate</h4> <p> To move the PirateSprite, we want the user to be able to "fling" the sprite in the direction that they choose. To do this, we will use the <span class="basicblock">PirateSprite.Flung</span> event handler. </p> <p> You may notice that <span class="basicblock">PirateSprite.Flung</span> takes in 6 attributes: x, y, xvel, yvel, speed, and heading. We want to reassign PirateSprite's current heading to the heading given to us from PirateSprite.Flung. This means that the user can now control the direction of the pirate ship with their fingers by flinging on the screen. </p> <p><img src="http://explore.appinventor.mit.edu/sites/all/files/Teach/GetTheGold/PirateSpriteFlung.png" /></p> <p>To prevent the pirate from moving off the screen, we will also use PirateSprite.Bounce when an edge is reached. </p> <p><img src="http://explore.appinventor.mit.edu/sites/all/files/Teach/GetTheGold/PirateSpriteBounce.png" /></p> <h4 class="ai-header">Moving the Coins</h4> <p> We want the coins to move to random positions on the screen. We will use <span class="basicblock">Clock1.Timer </span> and the ImageSprite's MoveTo method to do this. </p> <p> When the Clock1.Timer goes off, we want all of our gold coin ImageSprites to move to a new random location on the Canvas. We will do this by using the <span class="basicblock">Sprite.MoveTo</span> block. </p> <p>MoveTo takes in two arguments: the x and y coordinates on the canvas of the new position we want the sprite to move to. We want the Sprite to move to a new <i>random</i> location so we will use the <span class="basicblock">random integer</span> block found in the Math box. Since we want each Gold ImageSprite to move to a new location, we repeat this process for each sprite's MoveTo function. </p> <p>For ImageSprite2, we want x to be a random integer from 0 to <i>Canvas1.Width-ImageSprite2.Width</i> and y to be a random integer from 0 to <i>Canvas1.Height-ImageSprite2.Height</i>. This is to be repeated for all the Gold Image Sprites.</p> <p>Remember that sprites are measured at the upper left corner as (0,0) so if we don't want them to go off the screen, we need to take the sprite's height/width into account when setting the range for our random numbers.</p> <p>We will do this by setting up our blocks as in the image below:</p> <p><img src="http://explore.appinventor.mit.edu/sites/all/files/Teach/GetTheGold/ClockTimer.png" /></p> <h4 class="ai-header">Detecting Collisions</h4> <p> App Inventor detects collisions by checking for an intersection between the bounding rectangles of each ImageSprite. We call this rectangle-based collision detection. As you can see in the image below, sprites with circular or polygon shape will appear to collide because of the rectangular bounds around them when they might not actually be colliding.</p> <p><img src="http://explore.appinventor.mit.edu/sites/all/files/Teach/GetTheGold/CollisionDetection.png" /></p> <p>We can use the <span class="basicblock">PirateSprite.CollidedWith </span> event handler to detect whenever the pirate ship collides with another sprite or gold coin. You may notice that <span class="basicblock">PirateSprite.CollidedWith </span> takes in an argument. This argument is the object that PirateSprite just collided with. We will be testing inside the handler for which object so the name of this argument is not significant. You can name it other. </p> <p>Whenever the pirate collides with a gold coin, we want the coin to disappear. We can do this by setting the coin's visibility to false. To find which coin the pirate collided with, we will use the <span class="basicblock">PirateSprite.CollidingWith</span>. </p> <p> We can use <span class="basicblock">PirateSprite.CollidingWith</span> to take in a component (each of the gold coin sprites) to detect which sprite was hit. This is a component block and NOT a text block with the words ImageSprite inside. The component block can be found in the drawer for each component. If a sprite was hit, we will set its visibility to false. </p> <p><img src="http://explore.appinventor.mit.edu/sites/all/files/Teach/GetTheGold/CollisionSprites.png" /></p> <h4 class="ai-header">Reset Button</h4> <p>After the user hits all of the gold sprites with the pirate ship, none of them will be visible. The reset button should set all of the gold sprites' visibility to true. </p> <p><img src="http://explore.appinventor.mit.edu/sites/all/files/Teach/GetTheGold/ResetVis.png" /></p> <h4 class="ai-header">Complete Program</h4> <p>Here's the complete <strong><span style="color:green;">GetTheGold</span></strong> program.</p> <p><img src="http://explore.appinventor.mit.edu/sites/all/files/Teach/GetTheGold/GetTheGoldAll.png" /></p> <p>Package the final version of the app by choosing <strong>Package For Phone | Barcode</strong> from the Component Designer menu. When the barcode appears, use the barcode scanner on your phone to download and install the app.</p> <h4 class="ai-header">Variations</h4> <p>Once you get this program running, you may want to do the following additional features to extend it. For example,</p> <ul><li>Create a label to display the time that it took you to get all the gold</li> <li>Change the speed of the ship or gold coins</li> <li>Add an enemy sprite that when collided with, causes your pirate to lose speed</li> <li>Use one of the phone's sensors to control movement of the pirate ship </li> </ul><h4 class="ai-header">Scan the Sample App to your Phone</h4> <p>Scan the following barcode onto your phone to install and run the sample app. </p><p><img src="http://explore.appinventor.mit.edu/sites/all/files/Teach/GetTheGold/GetTheGoldBarcode.png" /></p> <h4 class="ai-header">Download Source Code</h4> <p>If you'd like to work with this sample in App Inventor, download the <a href="http://explore.appinventor.mit.edu/sites/all/files/Teach/GetTheGold/GetTheGold.zip">source code</a> to your computer, then open App Inventor, go to the My Projects page, and choose <b>More Actions | Upload Source</b>.</p> <p>Done with <span style="color:black;">GetTheGold</span>? Return to to the other modules <a href="/teach/module-2-2">here</a> or the tutorials <a href="/tutorials">here</a>.</p> </div></div></div><section class="field field-name-field-version field-type-taxonomy-term-reference field-label-above view-mode-rss clearfix"> <h2 class="field-label">Tutorial Version:&nbsp;</h2> <ul class="field-items"> <li class="field-item even"> <a href="/tutorial-version/app-inventor-1" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">App Inventor 1</a> </li> </ul> </section> <section class="field field-name-field-tutorial-difficulty field-type-taxonomy-term-reference field-label-above view-mode-rss clearfix"> <h2 class="field-label">Tutorial Difficulty:&nbsp;</h2> <ul class="field-items"> <li class="field-item even"> <a href="/tutorial-difficulty/advanced" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">Advanced</a> </li> </ul> </section> <section class="field field-name-field-tutorial-type field-type-taxonomy-term-reference field-label-above view-mode-rss clearfix"> <h2 class="field-label">Tutorial Type:&nbsp;</h2> <ul class="field-items"> <li class="field-item even"> <a href="/tutorial-type/clock-timer" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">Clock Timer</a> </li> <li class="field-item odd"> <a href="/tutorial-type/game" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">Game</a> </li> <li class="field-item even"> <a href="/tutorial-type/sprites" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">Sprites</a> </li> </ul> </section> Fri, 28 Jun 2013 21:35:19 +0000 aaron 346 at http://dev-explore.appinventor.mit.edu http://dev-explore.appinventor.mit.edu/get-gold#comments MoleMash 2 http://dev-explore.appinventor.mit.edu/content/molemash-2 <div class="field field-name-body field-type-text-with-summary field-label-hidden view-mode-rss"><div class="field-items"><div class="field-item even" property="content:encoded"><style> <!--/*--><![CDATA[/* ><!--*/ li { padding-bottom: 7px; } .basicblock { border: 1px dashed #7AA81C; padding-left: 4px; padding-right: 4px; padding-top: 1px; padding-bottom: 1px; background-color: #E7F2CB; font-size: 9pt; text-wrap: suppress; } .callblock { border: 1px dashed #000000; padding-left: 4px; padding-right: 4px; padding-top: 1px; padding-bottom: 1px; background-color: #E0D1FF; font-size: 9pt; text-wrap: suppress; } .argblock { border: 1px dashed #000000; padding-left: 4px; padding-right: 4px; padding-top: 1px; padding-bottom: 1px; background-color: #E5E5FF; font-size: 9pt; text-wrap: suppress; } .textblock { border: 1px dashed #000000; padding-left: 4px; padding-right: 4px; padding-top: 1px; padding-bottom: 1px; background-color: #FADAA0; font-size: 9pt; text-wrap: suppress; } .setblock { border: 1px dashed #000000; padding-left: 4px; padding-right: 4px; padding-top: 1px; padding-bottom: 1px; background-color: #C1D5F8; font-size: 9pt; text-wrap: suppress; } .controlblock { border: 1px dashed #000000; padding-left: 4px; padding-right: 4px; padding-top: 1px; padding-bottom: 1px; background-color: #FAEDBB; font-size: 9pt; text-wrap: suppress; } .listblock { border: 1px dashed #000000; padding-left: 4px; padding-right: 4px; padding-top: 1px; padding-bottom: 1px; background-color: #FCF5D7; font-size: 9pt; text-wrap: suppress; } /*--><!]]>*/ </style><h4 class="ai-header">What You're Building</h4> <p><img src="/sites/all/files/tutorials/moleMash2/front-pic.png" style="float:right;" /></p> <p><a href="http://cs.usfca.edu/~wolber/appinventor/bookSplits/ch3MoleMash.pdf">Download Refined Version (Book Chapter PDF)</a></p> <p>This tutorial shows you how to build a game similar to the Whac-A-MoleTM arcade game. Specifically, your goal is to whack (tap) a mole that randomly pops out of one of five fixed holes. Every time you succeed, your score is increased by one point.</p> <p>In order to highlight new App Inventor features — the Advanced tab and Sprite Z-layering — this app takes a different approach than the <a href="http://explore.appinventor.mit.edu/content/molemash">original Mole Mash tutorial</a>, which you need not have read in order to do this one. You should, however, be familiar with the basics of App Inventor — using the Component Designer to build a user interface and using the Blocks Editor to specify event handlers. If you are not familiar with the basics, try stepping through some of the <a href="/tutorials">basic tutorials</a> before continuing.</p> <h4 class="ai-header">Introduction</h4> <p>This tutorial includes:</p> <ol><li>Creating a list of components</li> <li>Using functionality from the Advanced section of the Blocks Editor to get and set properties of arbitrary components</li> <li>Having game events controlled by the <b>Clock</b> component</li> <li>Using Sprite Z-layering to ensure that one sprite (<b>ImageSprite</b> or <b>Ball</b>) appears in front of another</li> </ol><h4 class="ai-header">Getting Started</h4> <p>Connect to the App Inventor web site and start a new project. Set the screen's <b style="color:green;">Title</b> property to an appropriate name, such as "Mole Mash". Open the Blocks Editor and connect it to the phone. Download these image files (created by Yun Miao) by right-clicking on them, then add them to the project by pressing the "Add..." button in the Media pane.</p> <p><a href="/sites/all/files/tutorials/moleMash2/hole.png"><img src="/sites/all/files/tutorials/moleMash2/hole.png" /></a><a href="/sites/all/files/tutorials/moleMash2/mole.png"><img src="/sites/all/files/tutorials/moleMash2/mole.png" /></a></p> <h4 class="ai-header">Set up the Components</h4> <p>The user interface will contain a total of 6 ImageSprites: 5 unmoving holes and 1 mole, which will move on top of the holes. Use the component designer to create the user interface. When you are done, it should look something like the picture below. Don't worry about lining up the holes evenly. You will specify their locations through their <b style="color:green;">X</b> and <b style="color:green;">Y</b> properties. Additional instructions are below the picture.</p> <p><img src="/sites/all/files/tutorials/moleMash2/designer1.png" /></p> <p>Create the following components by dragging them from the Palette into the Viewer.</p> <table><tr style="background-color: #EFEFEF; font-weight: bold;"><td> Component Type </td> <td> Palette Group </td> <td> What you'll name it </td> <td> Purpose of Component </td> </tr><tr><td> <b>Canvas</b> </td> <td>Basic</td> <td style="color:green;">GameCanvas</td> <td>The game field</td> </tr><tr><td> <b>ImageSprite</b> (5) </td> <td>Animation</td> <td style="color:green;">Hole1 ... Hole5</td> <td>Holes from which the mole can appear</td> </tr><tr><td> <b>ImageSprite</b> </td> <td>Animation</td> <td style="color:green;">Mole</td> <td>The mole</td> </tr><tr><td> <b>HorizontalArrangement</b> </td> <td>Screen Arrangement</td> <td style="color:green;">ScoreArrangement</td> <td>To display the score</td> </tr><tr><td> <b>Label</b> </td> <td>Basic</td> <td style="color:green;">ScoreTextLabel</td> <td>To hold "Score: "</td> </tr><tr><td> <b>Label</b> </td> <td>Basic</td> <td style="color:green;">ScoreValueLabel</td> <td>To hold the score (# of times the mole was hit)</td> </tr><tr><td> <b>Clock</b> </td> <td>Basic</td> <td style="color:green;">MoleClock</td> <td>To control the mole's movement</td> </tr><tr><td> <b>Sound</b> </td> <td>Media</td> <td style="color:green;">Buzzer</td> <td>To vibrate when the mole is touched</td> </tr></table><p>Make the following changes to the components' properties:</p> <table><tr style="background-color: #EFEFEF; font-weight: bold;"><td> Component </td> <td> Action </td> </tr><tr><td>Canvas1</td> <td>Set <b style="color:green;">BackgroundColor</b> to Green. Set <b style="color:green;">Width</b> to 320 pixels. Set <b style="color:green;">Height</b> to 320 pixels.</td> </tr><tr><td>Hole1</td> <td>Set <b style="color:green;">X</b> to 20 and <b style="color:green;">Y</b> to 60 (upper left).</td> </tr><tr><td>Hole2</td> <td>Set <b style="color:green;">X</b> to 130 and <b style="color:green;">Y</b> to 60 (upper center).</td> </tr><tr><td>Hole3</td> <td>Set <b style="color:green;">X</b> to 240 and <b style="color:green;">Y</b> to 60 (upper right)</td> </tr><tr><td>Hole4</td> <td>Set <b style="color:green;">X</b> to 75 and <b style="color:green;">Y</b> to 140 (lower left).</td> </tr><tr><td>Hole5</td> <td>Set <b style="color:green;">X</b> to 185 and <b style="color:green;">Y</b> to 140 (lower right).</td> </tr><tr><td>Mole</td> <td>Set <b style="color:green;">Picture</b> to "mole.png". Set <b style="color:green;">Z</b> to 2 so the mole appears in front of the other <b style="color:green;">ImageSprite</b> s, which have the default <b style="color:green;">Z</b> value of 1.</td> </tr><tr><td>ScoreTextLabel</td> <td>Set <b style="color:green;">Text</b> to "Score: ".</td> </tr><tr><td>ScoreTextValue</td> <td>Set <b style="color:green;">Text</b> to "0".</td> </tr></table><p>Don't worry now about setting the <b style="color:green;">Picture</b> property for the holes; we'll set the property in the Blocks Editor.</p> <h4 class="ai-header">Add Behaviors to the Components</h4> <p>Here is an overview of what we need to create blocks to do:</p> <ol><li>Create variables: <ol><li><b style="color:green;">holes</b>: a list of holes</li> <li><b style="color:green;">currentHole</b>: the hole the mole is currently coming out of</li> </ol></li> <li>When the app starts: <ol><li>Populate the list of holes.</li> <li>Set each hole's <b style="color:green;">Picture</b> property to "hole.png".</li> <li>Call procedure <span class="callblock">MoveMole</span> (below).</li> </ol></li> <li>Create a procedure <span class="callblock">MoveMole</span> to: <ol><li>Set <b style="color:green;">currentHole</b> to a random hole from the list <b style="color:green;">holes</b>.</li> <li>Move the mole to the location of <b style="color:green;">currentHole</b>.</li> </ol></li> <li>Make <b>MoleClock</b> call <span class="callblock">MoveMole</span> whenever its timer goes off (every second). </li> <li>Implement a handler that does the following when the mole is touched: <ol><li>Add one to the score.</li> <li>Make the phone briefly vibrate.</li> <li>Call <span class="callblock">MoveMole</span>.</li> </ol></li> </ol><p>To proceed, open the Blocks Editor.</p> <h4 class="ai-header">Creating Variables</h4> <p>Create the variables <b style="color:green;">holes</b> and <b style="color:green;">currentHole</b>. For now, we will give them "dummy" initial values; we'll set their real initial values in the <span class="basicblock">Screen1.Initialize</span> event handler, which is run when the app starts. (For technical reasons, components cannot be referred to in def blocks, which are run before the app has started.) Here is a picture and list of the blocks you will need:</p> <p><img src="/sites/all/files/tutorials/moleMash2/blocks1.png" /></p> <table><tr style="background-color: #EFEFEF; font-weight: bold;"><td> Block type </td> <td> Drawer </td> <td> Purpose </td> </tr><tr><td><span class="setblock">def variable as</span> (holes)</td> <td>Definition</td> <td>Hold a list of holes.</td> </tr><tr><td><span class="listblock">make a list</span></td> <td>Lists</td> <td>Create an empty list, to be filled in when the program starts.</td> </tr><tr><td><span class="setblock">def variable as</span> (currentHole)</td> <td>Definition</td> <td>Hold the mole's current hole.</td> </tr><tr><td><span class="basicblock">number</span> (0)</td> <td>Numbers</td> <td>Provide a required initial value for <b style="color:green;">currentHole</b>.</td> </tr></table><p>As always, comments (created by right-clicking on a block) are encouraged but not required.</p> <h4 class="ai-header">Starting the App</h4> <p>The first event to occur in any program in <span class="basicblock">Screen1.Initialize</span>, so we will put start-up code in that handler. Specifically, we will add the hole components to the list holes, set each hole's <b style="color:green;">Picture</b> property to "hole.png", and call <span class="callblock">MoveMole</span>. Since we have not yet written MoveMole, we will create an empty procedure with that name, which we will fill in later.</p> <p>Below are a picture and table of the blocks you need to create. Note that the "Any ImageSprite" drawer is found under the "Advanced" tab to the right of "Built-In" and "My Blocks" in the Blocks Editor.</p> <p><img src="/sites/all/files/tutorials/moleMash2/blocks2.png" /></p> <table><tr style="background-color: #EFEFEF; font-weight: bold;"><td> Block type </td> <td> Drawer </td> <td> Purpose </td> </tr><tr><td><span class="basicblock">Screen1.Initialize</span></td> <td>Screen1</td> <td>Specify what should happen when the app starts.</td> </tr><tr><td><span class="listblock">add items to list</span></td> <td>Lists</td> <td>Add the following values to...</td> </tr><tr><td><span class="argblock">holes</span></td> <td>My Definitions</td> <td>...the list of holes:</td> </tr><tr><td><span class="argblock">component Hole1</span></td> <td>Hole1</td> <td>-the upper left hole</td> </tr><tr><td><span class="argblock">component Hole2</span></td> <td>Hole2</td> <td>-the upper center hole</td> </tr><tr><td><span class="argblock">component Hole3</span></td> <td>Hole3</td> <td>-the upper right hole</td> </tr><tr><td><span class="argblock">component Hole4</span></td> <td>Hole4</td> <td>-the lower left hole</td> </tr><tr><td><span class="argblock">component Hole5</span></td> <td>Hole5</td> <td>-the lower right hole</td> </tr><tr><td><span class="controlblock">foreach</span></td> <td>Control</td> <td>Specify that we would like...</td> </tr><tr><td><span class="argblock">name</span> (hole)</td> <td>Definitions</td> <td>...a variable named "hole"...</td> </tr><tr><td><span class="argblock">holes</span></td> <td>My Definitions</td> <td>...to take on each of the values in the list holes .</td> </tr><tr><td><span class="setblock">ImageSprite.Picture</span></td> <td>Any Image Sprite</td> <td>Set the Picture property of...</td> </tr><tr><td><span class="argblock">value hole</span></td> <td>My Definitions</td> <td>...the ImageSprite referred to by the variable hole ...</td> </tr><tr><td><span class="textblock">text (hole.png)</span></td> <td>Text</td> <td>...to the picture of the empty hole.</td> </tr><tr><td><span class="callblock">to procedure</span> (MoveMole)</td> <td>Definition</td> <td>Create an procedure, to be filled in later, for moving the mole.</td> </tr><tr><td><span class="callblock">MoveMole</span></td> <td>My Definitions</td> <td>Call MoveMole to make the first placement of the mole.</td> </tr></table><p>Compare the <span class="controlblock">foreach</span> block to the equivalent blocks that would be necessary without it:</p> <p><img src="/sites/all/files/tutorials/moleMash2/molemash2.JPG" /></p> <p>Not only is the left set of blocks shorter, it is less repetitious, sparing the programmer from semi-mindless copy-and-pasting and making it easier to modify, for example, if the name of the picture is changed.</p> <h4 class="ai-header">Moving the Mole</h4> <p>Now let's fill in the body of the procedure MoveMole, which we'll call when the program starts, when the mole gets touched, and when our timer goes off every second. What we want it to do is to pick a random hole and move the mole on top of it. Here are a picture and list of the new blocks:</p> <p><img src="/sites/all/files/tutorials/moleMash2/blocks4.png" /></p> <table><tr style="background-color: #EFEFEF; font-weight: bold;"><td> Block type </td> <td> Drawer </td> <td> Purpose </td> </tr><tr><td><span class="setblock">set currentHole to</span></td> <td>My Definitions</td> <td>Save the...</td> </tr><tr><td><span class="listblock">call pick random item</span></td> <td>Lists</td> <td>...randomly selected...</td> </tr><tr><td><span class="argblock">holes</span></td> <td>My Definitions</td> <td>...hole.</td> </tr><tr><td><span class="basicblock">call Mole.MoveTo</span></td> <td>Mole</td> <td>Move the mole to the...</td> </tr><tr><td><span class="argblock">ImageSprite.X</span></td> <td>Advanced/ImageSprite</td> <td>..x-coordinate of...</td> </tr><tr><td><span class="argblock">currentHole</span></td> <td>My Definitions</td> <td>...the chosen hole...</td> </tr><tr><td><span class="argblock">ImageSprite.Y</span></td> <td>Advanced/ImageSprite</td> <td>...and the y-coordinate of...</td> </tr><tr><td><span class="argblock">current Hole</span></td> <td>My Definitions</td> <td>...the chosen hole.</td> </tr></table><p>We now need to specify that MoveMole should be called whenever MoleClock's Timer goes off. We just need two blocks to accomplish that:</p> <p><img src="/sites/all/files/tutorials/moleMash2/blocks5.png" /></p> <table><tr style="background-color: #EFEFEF; font-weight: bold;"><td> Block type </td> <td> Drawer </td> <td> Purpose </td> </tr><tr><td><span class="basicblock">MoleClock.Timer</span></td> <td>MoleClock</td> <td>When the timer goes off...</td> </tr><tr><td><span class="callblock">call MoveMole</span></td> <td>My Definitions</td> <td>...move the mole.</td> </tr></table><h4 class="ai-header">Registering Touches</h4> <p>Finally, we need to specify what happens when the mole is touched. Specifically, we want to:</p> <ol><li>Increment the score.</li> <li>Make the phone vibrate briefly.</li> <li>Move the mole.</li> </ol><p>We can easily translate these to blocks:</p> <p><img src="/sites/all/files/tutorials/moleMash2/blocks6.png" /></p> <table><tr style="background-color: #EFEFEF; font-weight: bold;"><td> Block type </td> <td> Drawer </td> <td> Purpose </td> </tr><tr><td><span class="basicblock">Mole.Touched</span></td> <td>Mole</td> <td>When the mole is touched...</td> </tr><tr><td><span class="setblock">set ScoreValueLabel.Text to</span></td> <td>ScoreValueLabel</td> <td>...update the visible score to...</td> </tr><tr><td><span class="basicblock"> block</span></td> <td>Math</td> <td>...the result of adding...</td> </tr><tr><td><span class="basicblock">number</span> (1)</td> <td>Math</td> <td>...1 [and]...</td> </tr><tr><td><span class="argblock">ScoreValueLabel.Text</span></td> <td>ScoreValueLabel</td> <td>...the previous score.</td> </tr><tr><td><span class="callblock">call Buzzer.Vibrate</span></td> <td>Buzzer</td> <td>Make the phone vibrate for...</td> </tr><tr><td><span class="basicblock">number</span> (100)</td> <td>Math</td> <td>...100 milliseconds.</td> </tr><tr><td><span class="callblock">call MoveMole</span></td> <td>My Definitions</td> <td>Move the mole to a new location.</td> </tr></table><h4 class="ai-header">Final Program</h4> <p><img src="/sites/all/files/tutorials/moleMash2/blocks-final.png" /></p> <h4 class="ai-header">Variations</h4> <p>Here are some variations you might want to implement:</p> <ul><li>Adding a Reset button to set the score back to 0.</li> <li>Having the score depend not just on the number of hits but also the number of misses and escaped moles.</li> <li>Increasing the speed of the game of mole movement if the player is doing well and decreasing it if the player is doing poorly.</li> <li>Adding a second mole on a different timer.</li> </ul><p>You can see how to implement the first two variations in the <a href="http://explore.appinventor.mit.edu/content/molemash">original Mole Mash tutorial</a>.</p> <h4 class="ai-header">Review</h4> <p>Here are some of the ideas covered in this tutorial:</p> <ul><li>Putting components in a <b>List</b>.</li> <li>Performing an operation on every component in a <b>List</b> using the <span class="controlblock">foreach</span> block and Advanced features.</li> <li>Placing an <b>ImageSprite</b> on top of another, using their <b style="color:green;">Z</b> properties to control which goes in front.</li> <li>Using the <b>Clock</b> component to control game play.</li> <li>Creating a procedure and calling it from multiple places.</li> </ul><pre class="ai-box">Done with <span style="color:black;">MoleMash 2</span>? Return to the other tutorials <a href="/tutorials">here</a>.</pre><h4 class="ai-header">Scan the Sample App to your Phone</h4> <p>Scan the following barcode onto your phone to install and run the sample app. </p><p><img src="/sites/all/files/tutorials/moleMash2/MoleMash2Barcode.png" /></p> <p>Or <a href="http://explore.appinventor.mit.edu/sites/all/files/tutorials/moleMash2/MoleMash2.apk">download the apk</a></p> <h4 class="ai-header">Download Source Code</h4> <p>If you'd like to work with this sample in App Inventor, download the <a href="http://explore.appinventor.mit.edu/sites/all/files/tutorials/moleMash2/MoleMash2.zip">source code</a> to your computer, then open App Inventor, go to the My Projects page, and choose <b>More Actions | Upload Source</b>.</p> </div></div></div><section class="field field-name-field-version field-type-taxonomy-term-reference field-label-above view-mode-rss clearfix"> <h2 class="field-label">Tutorial Version:&nbsp;</h2> <ul class="field-items"> <li class="field-item even"> <a href="/tutorial-version/app-inventor-1" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">App Inventor 1</a> </li> </ul> </section> <section class="field field-name-field-tutorial-difficulty field-type-taxonomy-term-reference field-label-above view-mode-rss clearfix"> <h2 class="field-label">Tutorial Difficulty:&nbsp;</h2> <ul class="field-items"> <li class="field-item even"> <a href="/tutorial-difficulty/advanced" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">Advanced</a> </li> </ul> </section> <section class="field field-name-field-tutorial-type field-type-taxonomy-term-reference field-label-above view-mode-rss clearfix"> <h2 class="field-label">Tutorial Type:&nbsp;</h2> <ul class="field-items"> <li class="field-item even"> <a href="/tutorial-type/clock-timer" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">Clock Timer</a> </li> <li class="field-item odd"> <a href="/tutorial-type/game" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">Game</a> </li> <li class="field-item even"> <a href="/tutorial-type/sprites" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">Sprites</a> </li> </ul> </section> Wed, 26 Jun 2013 19:45:48 +0000 aaron 338 at http://dev-explore.appinventor.mit.edu http://dev-explore.appinventor.mit.edu/content/molemash-2#comments MakeQuiz and TakeQuiz http://dev-explore.appinventor.mit.edu/content/makequiz-and-takequiz <div class="field field-name-body field-type-text-with-summary field-label-hidden view-mode-rss"><div class="field-items"><div class="field-item even" property="content:encoded"><style> <!--/*--><![CDATA[/* ><!--*/ li { padding-bottom: 7px; } .basicblock { border: 1px dashed #7AA81C; padding-left: 4px; padding-right: 4px; padding-top: 1px; padding-bottom: 1px; background-color: #E7F2CB; font-size: 9pt; text-wrap: suppress; } .callblock { border: 1px dashed #000000; padding-left: 4px; padding-right: 4px; padding-top: 1px; padding-bottom: 1px; background-color: #E0D1FF; font-size: 9pt; text-wrap: suppress; } .argblock { border: 1px dashed #000000; padding-left: 4px; padding-right: 4px; padding-top: 1px; padding-bottom: 1px; background-color: #E5E5FF; font-size: 9pt; text-wrap: suppress; } .textblock { border: 1px dashed #000000; padding-left: 4px; padding-right: 4px; padding-top: 1px; padding-bottom: 1px; background-color: #FADAA0; font-size: 9pt; text-wrap: suppress; } .setblock { border: 1px dashed #000000; padding-left: 4px; padding-right: 4px; padding-top: 1px; padding-bottom: 1px; background-color: #C1D5F8; font-size: 9pt; text-wrap: suppress; } .controlblock { border: 1px dashed #000000; padding-left: 4px; padding-right: 4px; padding-top: 1px; padding-bottom: 1px; background-color: #FAEDBB; font-size: 9pt; text-wrap: suppress; } .listblock { border: 1px dashed #000000; padding-left: 4px; padding-right: 4px; padding-top: 1px; padding-bottom: 1px; background-color: #FCF5D7; font-size: 9pt; text-wrap: suppress; } /*--><!]]>*/ </style><h2 class="ai-header"><span style="color:green;">MakeQuiz</span> and <span style="color:green;">TakeQuiz</span></h2> <h4 class="ai-header">What you're building</h4> <p><img src="/sites/all/files/tutorials/makeQuizTakeQuiz/MakeQuizEmulator.png" style="float:right; width: 200px;" /></p> <p><span style="color:green;">MakeQuiz</span> and <span style="color:green;">TakeQuiz</span> are two apps that, in tandem, allow a teacher to create quizzes for a student. Parents can create fun trivia apps for their children during a long road trip, grade school teachers can build "Math Blaster" quizzes, and college students can build quizzes to help their study groups prepare for a final. This tutorial will walk you through creating both the MakeQuiz and the TakeQuiz app.</p> <p>This tutorial is a followup of the <a href="http://explore.appinventor.mit.edu/content/quizme">QuizMe tutorial</a> -- if you haven't completed that tutorial you should do so before continuing.</p> <h4 class="ai-header">Getting started</h4> <p>Connect to the App Inventor web site and start a new project. Name it "MakeQuiz", and also set the screen's <b style="color:green;">Title</b> to "MakeQuiz". Open the Blocks Editor and connect to the phone.</p> <h4 class="ai-header">Introduction</h4> <p>You'll design two apps, MakeQuiz for the "teacher" and TakeQuiz for the "student". With MakeQuiz:</p> <p><a href="http://explore.appinventor.mit.edu/sites/explore.appinventor.mit.edu/files/MakeQuiz.zip"><img src="http://explore.appinventor.mit.edu/sites/explore.appinventor.mit.edu/files/downloadMakeQuizButton.PNG" style="float:right; width: 200px;border:none" /></a></p> <ul><li>The user enters questions and answers in an input form.</li> <li>The previously entered question-answer pairs are displayed.</li> <li>The quiz is stored persistently, in a database.</li> </ul><p>TakeQuiz will work similarly to the <a href="http://explore.appinventor.mit.edu/content/quizme">QuizMe</a> app-- in fact you'll build it using QuizMe as a basis. TakeQuiz will differ in that the questions asked will be those that were entered into the database using MakeQuiz.</p> <p>This tutorial introduces the following App Inventor concepts:</p> <ul><li>Input forms for allowing the user to enter information.</li> <li>Displaying lists: serializing a list variable to display it on separate lines.</li> <li>Persistent data: MakeQuiz will save the quiz questions and answers in a database and TakeQuiz will load them in from the database.</li> <li>Data Sharing: the two apps together illustrate how two phones (and even two apps) can communicate through a shared, web database:</li> </ul><p><img src="/sites/all/files/tutorials/makeQuizTakeQuiz/dbdiagram.png" /></p> <h4 class="ai-header">Set up the Components for MakeQuiz</h4> <p>Use the Component Designer to create the interface for MakeQuiz. When you finish, it should look something like the snapshot below (there are also more detailed instructions below the snapshot).</p> <p><img src="/sites/all/files/tutorials/makeQuizTakeQuiz/makeQuizComponents.png" /></p> <p>You'll use the following components to create MakeQuiz. Drag each component from the Palette into the Viewer and name it as specified below:</p> <table><tr style="background-color: #EFEFEF; font-weight: bold;"><td> Component Type </td> <td> Palette Group </td> <td> What you'll name it </td> <td> Purpose of Component </td> </tr><tr><td> <b>HorizontalArrangement</b> </td> <td>Screen Arrangement</td> <td style="color:green;">HorizontalArrangement1</td> <td>Display the question prompt and textbox on one line</td> </tr><tr><td><b>Label</b></td> <td>Basic</td> <td style="color:green;">Label1</td> <td>The "Question:" prompt</td> </tr><tr><td><b>TextBox</b></td> <td>Basic</td> <td style="color:green;">QuestionText</td> <td>User enters questions here </td> </tr><tr><td><b>HorizontalArrangement</b></td> <td>Screen Arrangement</td> <td style="color:green;">HorizontalArrangement2</td> <td>Display the answer prompt and textbox on one line</td> </tr><tr><td><b>Label</b></td> <td>Basic</td> <td style="color:green;">Label2</td> <td>The "Answer:" prompt</td> </tr><tr><td><b>TextBox</b></td> <td>Basic</td> <td style="color:green;">AnswerText</td> <td>User enters answers here </td> </tr><tr><td><b>Button</b></td> <td>Basic</td> <td style="color:green;">SubmitButton</td> <td>User clicks to submit a QA pair.</td> </tr><tr><td><b>Label</b></td> <td>Basic</td> <td style="color:green;">QuestionsAnswersLabel</td> <td>This will display previously entered QAs</td> </tr><tr><td><b>TinyWebDB</b></td> <td>Other Stuff</td> <td style="color:green;">TinyWebDB1</td> <td>To store to and retrieve from database</td> </tr></table><p>Set the properties of the components in the following way:</p> <ul><li>Set the Text of Label1 to "Question": and the Text of Label2 to "Answer":</li> <li>Set the Hint of QuestionText to "enter a question" and the Hint of AnswerText to "enter an answer".</li> <li>Set the Text of SubmitButton to " Submit "</li> <li>Set the Text of QuestionsAnswersLabel to "Questions and Answers".</li> </ul><p>Put <span style="color:green;">Label1</span> and <span style="color:green;">QuestionText</span> in <span style="color:green;">HorizontalArrangement1</span>, and <span style="color:green;">Label2</span> and <span style="color:green;">AnswerText</span> in <span style="color:green;">HorizontalArrangement2</span>.</p> <h4 class="ai-header">Add behaviors to the components</h4> <p>Open the Blocks Editor to add the behaviors for the app. As with the original QuizMe app, you'll first define some <em>global variables</em> for the QuestionList and AnswerList , but this time you won't provide fixed questions and answers. You'll need the following blocks:</p> <table><tr style="background-color: #EFEFEF; font-weight: bold;"><td> Block type </td> <td> Drawer </td> <td> Purpose </td> </tr><tr><td><span class="setblock">def variable</span> ("QuestionList") </td> <td>Definitions</td> <td>Defines the <b>QuestionList</b> variable (rename it)</td> </tr><tr><td><span class="setblock">def variable</span> ("AnswerList") </td> <td>Definitions</td> <td>Defines the <b>AnswerList</b> variable (rename it)</td> </tr><tr><td><span class="listblock">make a list</span></td> <td>Lists</td> <td>To set up the <b>QuestionList</b> for new items</td> </tr><tr><td><span class="listblock">make a list</span></td> <td>Lists</td> <td>To set up the <b>AnswerList</b> for new items</td> </tr></table><p>The blocks should look like this:</p> <p><img src="/sites/all/files/tutorials/makeQuizTakeQuiz/lists.png" /></p> <p>Note that, unlike the original QuizMe app, the lists are empty to begin with. This is because with MakeQuiz and TakeQuiz, all data is created by the user of the app (it is <em>user-generated</em>). </p> <h4 class="ai-header">Handle the User's entries</h4> <p>The first behavior you'll build is for handling the user's input. Specifically, when the user enters a question and answer and clicks submit, you'll use <span class="listblock">add item to list</span> blocks to update the QuestionList and AnswerList.</p> <p>You'll need the following blocks:</p> <table><tr style="background-color: #EFEFEF; font-weight: bold;"><td> Block type </td> <td> Drawer </td> <td> Purpose </td> </tr><tr><td><span class="basicblock">SubmitButton.Click </span></td> <td>SubmitButton</td> <td>This event is triggered when the user clicks this button.</td> </tr><tr><td><span class="listblock">add items to list</span> (2)</td> <td>Lists</td> <td>Use these to add the data entered by the user to the lists</td> </tr><tr><td><span class="argblock">global QuestionList</span></td> <td>My Definitions</td> <td>Plug into <b>list</b> slot of <u>first</u> <span class="listblock">add items to list</span></td> </tr><tr><td><span class="argblock">QuestionText.Text</span></td> <td>QuestionText</td> <td>User's entry; plug it into <b>item</b> slot of <u>first</u> <span class="listblock">add items to list</span></td> </tr><tr><td><span class="argblock">global AnswerList</span></td> <td>My Definitions</td> <td>Plug into <b>list</b> slot of <u>second</u> <span class="listblock">add items to list</span></td> </tr><tr><td><span class="argblock">AnswerText.Text</span></td> <td>AnswerText</td> <td>User's entry; plug it into <b>item</b> slot of <u>second</u> <span class="listblock">add items to list</span></td> </tr></table><p>The blocks should look like this:</p> <p><img src="/sites/all/files/tutorials/makeQuizTakeQuiz/submitNoDisplay.png" /></p> <h4 class="ai-header">How the blocks work</h4> <p><span class="listblock">add items to list</span> appends each item to the end of a list. Here, the app takes the text the user has entered in the QuestionText and AnswerText text boxes and appends each to the corresponding list.</p> <p>The behavior updates the hidden QuestionList and AnswerList variables, but the changes are not shown to the user. To display these lists, create a procedure "displayQAs" which makes a text object with both lists and places it into the QuestionsAnswersLabel. Then make sure to call the procedure at the bottom of <span class="basicblock">SubmitButton.Click</span>. You'll need the following blocks:</p> <table><tr style="background-color: #EFEFEF; font-weight: bold;"><td> Block type </td> <td> Drawer </td> <td> Purpose </td> </tr><tr><td><span class="callblock">procedure</span> "displayQAs"</td> <td>Definitions</td> <td>Put the code to display questions and answers here</td> </tr><tr><td><span class="setblock">set QuestionsAnswersLabel.Text to</span></td> <td>QuestionsAnswersLabel</td> <td>Display the lists in this label.</td> </tr><tr><td><span class="textblock">make text</span></td> <td>Text</td> <td>Make a text object out of two lists and a colon separator</td> </tr><tr><td><span class="argblock">global QuestionList</span></td> <td>My Definitions</td> <td>Plug into <span class="textblock">make text</span></td> </tr><tr><td><span class="textblock">text</span> (":")</td> <td>Text</td> <td>Plug into <span class="textblock">make text</span></td> </tr><tr><td><span class="argblock">global AnswerList</span></td> <td>My Definitions</td> <td>Plug into <span class="textblock">make text</span></td> </tr><tr><td><span class="callblock">call displayQAs</span></td> <td>My Definitions</td> <td>Place in the bottom of the SubmitButton.Click event-handler</td> </tr></table><p>The blocks should look like this:</p> <p><img src="/sites/all/files/tutorials/makeQuizTakeQuiz/displayQAs1.png" /></p> <h4 class="ai-header">How the blocks work</h4> <p>The displayQAs procedure is called after the lists are modified in <span class="basicblock">SubmitButton.Click</span>. The QuestionsAnswersLabel is modified to display the two lists separated by a colon. By default, App Inventor displays lists with surrounding parenthesis and spaces between items:</p> <p style="color:grey;">(item1 item2 item3)</p> <p>Of course, this is not the ideal way to display the lists, but it will allow you to test your behavior for now. Later, you'll modify the displayQAs procedure to display a list on separate lines, and to display each question together with its corresponding answer.</p> <pre class="ai-testing"><b>Test this behavior.</b> On the phone, enter a question and answer and click Submit. The app should display the single entry in the QuestionList, a colon, and then the single entry in the AnswerList. Add a second question and answer to make sure the lists are being created correctly.</pre><h4 class="ai-header">Blanking Out the Question and Answer</h4> <p>When a user submits a question-answer pair, you should clear the QuestionText and AnswerText text boxes so they're ready for a new entry.</p> <p>You'll need the following blocks:</p> <table><tr style="background-color: #EFEFEF; font-weight: bold;"><td> Block type </td> <td> Drawer </td> <td> Purpose </td> </tr><tr><td><span class="setblock">set QuestionText.Text to</span></td> <td>QuestionText</td> <td>To blank out question </td> </tr><tr><td><span class="setblock">set AnswerText.Text to</span></td> <td>AnswerText</td> <td>To blank out answer</td> </tr><tr><td><span class="textblock">text</span> (2 blank ones)</td> </tr></table><p>Here's how the blocks for the updated event handler should look:</p> <p><img src="/sites/all/files/tutorials/makeQuizTakeQuiz/submitWithBlank.png" /></p> <h4 class="ai-header">How the blocks work</h4> <p>When the user submits a new question and answer, they are added to their respective lists. At that point, the text in the QuestionText and AnswerText is "blanked out" with empty text blocks (you create an empty text block by clicking on the the block's text and pressing the delete button).</p> <pre class="ai-testing"><b>Test the behavior.</b> Add some questions and answers. When you submit them, the QuestionText and AnswerText should show only their hint (when a TextBox's Text property is empty it shows the hint until the user clicks it).</pre><h4 class="ai-header">Storing the questions and answers in a database</h4> <p>As is, the app records the questions and answers entered by the user, but only in the phone's temporary memory. All variables in App Inventor are transient data-- they are stored on the phone and the data only "lives" through one run of an app. When the user closes the app, the data is lost.</p> <p>The <span style="color:green;">MakeQuiz</span> app needs to record the questions and answers in a database. This will allow the quiz creator (teacher) to always edit the latest update of the quiz. It will also allow the <span style="color:green;">TakeQuiz</span> app to load the quiz and administer it to the student.</p> <p>You'll use the <b>TinyWebDB</b> component to store and retrieve the QuestionList and AnswerList to and from a database. TinyWebDB allows you to store data in AppInventor-compliant databases that live on the web instead of on the phone.</p> <p>The general scheme for storing a list persistently is the following: each time a new item is added to the list, use TinyWebDB to update the database version of the list. Then each time the app is opened (<span class="callblock">Screen1.Initialize</span> event), reload the database version of the list into the variable.</p> <p>Start by storing the QuestionList and AnswerList in the database each time the user enters a new pair. You'll need the following blocks:</p> <table><tr style="background-color: #EFEFEF; font-weight: bold;"><td> Block type </td> <td> Drawer </td> <td> Purpose </td> </tr><tr><td><span class="callblock">TinyWebDB1.StoreValue</span></td> <td>TinyWebDB1</td> <td>for storing questions in the database </td> </tr><tr><td><span class="textblock">text</span> ("questions")</td> <td>Text</td> <td>Plug in "questions" as the tag of <span class="callblock">StoreValue</span></td> </tr><tr><td><span class="argblock">global QuestionList</span></td> <td>My Definitions</td> <td>Plug into the value slot of <span class="callblock">StoreValue</span></td> </tr><tr><td><span class="callblock">TinyWebDB1.StoreValue</span></td> <td>TinyWebDB1</td> <td>For storing answers in the database</td> </tr><tr><td><span class="textblock">text</span> ("answers")</td> <td>Text</td> <td>Plug in "answers" as the tag of <span class="callblock">StoreValue</span></td> </tr><tr><td><span class="argblock">global AnswerList</span></td> <td>My Definitions</td> <td>Plug into the value slot of <span class="callblock">StoreValue</span></td> </tr></table><p>The blocks should look like this:</p> <p><img src="/sites/all/files/tutorials/makeQuizTakeQuiz/submitWithStore.png" /></p> <h4 class="ai-header">How the blocks work</h4> <p>The last two rows of blocks store data in the database. The tag arguments label the data being stored so that you can retrieve it later. The QuestionList is stored with a tag of "questions" while the AnswerList is stored with a tag of "answers".</p> <p>Although our example uses "questions" as the tag, you should actually use your own tag, e.g., "DavesQuestions", because by default, the database entries of all App Inventor programs share the same namespace and so your list of questions may get confused with someone else's list of questions since you both used the same tag. For more information, see <a href="/content/custom-tinywebdb-service">Creating a Custom TinyWebDB service</a>.</p> <pre class="ai-testing"><b>Test this behavior.</b> TinyWebDB stores information on the web, so you can open a browser page to test whether this behavior is working. By default, TinyWebDB stores information at http://appinvtinywebdb.appspot.com . Browse there to check if your data was stored as desired. There will be many entries, as the default service is for testing and is used by many programmers. If you search on the page, you should find the tag-value pairs you just stored. Because the default service is shared amongst programmers and apps, it is only for testing. Fortunately, setting up your own database service is straight forward. For more information, see <a href="/content/custom-tinywebdb-service">Creating a Custom TinyWebDB service</a>.</pre><h4 class="ai-header">Loading Data from the Database</h4> <p>Once the blocks for storing the lists are working, you can add the blocks for loading the lists back in each time the app begins.</p> <p>Loading data from a TinyWebDB database is a two-step process. First, you request the data by calling <span class="callblock">TinyWebDB.GetValue</span> and providing a tag.</p> <p><span class="callblock">GetValue</span> only requests the data from the web service. After the request is made, your app can do other things, such as responding to user actions, while it waits for the TinyWebDB web service to send the data. When the data arrives, a <span class="basicblock">TinyWebDB.GotValue</span> event is triggered. When that event occurs, the data requested is in a variable named "valueFromWebDB". The tag you requested is in the variable "tagFromWebDB". You can access these variables in the <span class="basicblock">TinyWebDB.GotValue</span> event handler.</p> <p>In this case, the app needs to request two things from the TinyWebDB web service, the questions and the answers, so the <span class="basicblock">Screen1.Initialize</span> will make two calls to <span class="callblock">getValue</span>. When the data arrives and the <span class="basicblock">GotValue</span> event-handler is triggered, the app should check the tag to see which request has arrived, and then load the corresponding list. Once the lists are both loaded, <span class="callblock">displayQAs</span> can be called to display them. </p> <p>You'll need the following blocks:</p> <table><tr style="background-color: #EFEFEF; font-weight: bold;"><td> Block type </td> <td> Drawer </td> <td> Purpose </td> </tr><tr><td><span class="basicblock">Screen1.Initialize</span></td> <td>Screen1</td> <td>Event handler triggered when app begins </td> </tr><tr><td><span class="callblock">TinyWebDB.GetValue</span> (2)</td> <td>TinyWebDB</td> <td>To request the stored QuestionList and AnswerList</td> </tr><tr><td><span class="textblock">text</span> ("questions")</td> <td>Text</td> <td>use as the tag to retrieve QuestionList</td> </tr><tr><td><span class="textblock">text</span> ("answers")</td> <td>Text</td> <td>use as the tag to retrieve AnswerList</td> </tr><tr><td><span class="basicblock">TinyWebDB.GotValue</span></td> <td>TinyWebDB1</td> <td>Event handler triggered when data arrives</td> </tr><tr><td><span class="controlblock">ifelse</span></td> <td>Control</td> <td>Need to ask which GetValue request arrived</td> </tr><tr><td><span class="basicblock">=</span> block</td> <td>Math</td> <td>Compare tagFromWebDB to "questions"</td> </tr><tr><td><span class="textblock">text</span> ("questions")</td> <td>Text</td> <td>This is the tag that was used to store QuestionList</td> </tr><tr><td><span class="argblock">value TagFromWebDB</span></td> <td>My Definitions</td> <td>An argument of GotValue, specifies which request</td> </tr><tr><td><span class="setblock">set QuestionList to</span></td> <td>My Definitions</td> <td>If TagFromWebDB is "questions" this list will be set</td> </tr><tr><td><span class="setblock">set AnswerList to</span></td> <td>My Definitions</td> <td>If TagFromWebDB is not "questions" this list will be set</td> </tr><tr><td><span class="argblock">value ValueFromWebDB</span> (2)</td> <td>My Definitions</td> <td>This holds the value returned from database</td> </tr><tr><td><span class="controlblock">if</span></td> <td>Control</td> <td>Check if both the lists are loaded before displaying</td> </tr><tr><td><span class="basicblock">=</span> block</td> <td>Math</td> <td>Compare the lengths of the lists</td> </tr><tr><td><span class="listblock">length of list</span> (2)</td> <td>Lists</td> <td>Check if the length of the lists are the same</td> </tr><tr><td><span class="argblock">global QuestionList</span></td> <td>My Definitions</td> <td>Plug into one of the <span class="listblock">length of list</span> blocks</td> </tr><tr><td><span class="argblock">global AnswerList</span></td> <td>My Definitions</td> <td>Plug into the other <span class="listblock">length of list</span> blocks</td> </tr><tr><td><span class="callblock">call displayQAs</span></td> <td>My Definitions</td> <td>Display the newly loaded questions and answers</td> </tr></table><p>The blocks should look like:</p> <p><img src="/sites/all/files/tutorials/makeQuizTakeQuiz/gotValue.png" /></p> <h4 class="ai-header">How the blocks work</h4> <p>When the app begins, the <span class="basicblock">Screen1.Initialize</span> event is triggered. The app calls <span class="callblock">TinyWebDB1.GetValue</span> twice, once to request the stored QuestionList and once to request the stored AnswerList. After requesting the data, the app can handle other events while it waits for the web database to answer the request. </p><p>When the data arrives from the web database, the <span class="basicblock">TinyWebDB1.GotValue</span> event is triggered. Since two requests were made, it will be triggered twice, once for each list.</p> <p>In the <span class="basicblock">GotValue</span> event-handler, the value returned is in the variable valueFromWebDB . The corresponding tag is in tagFromWebDB . The blocks first check to see which request has returned (even though the request for "questions" is made first in <span class="basicblock">Screen1.Initialize</span>, there is no guarantee that the QuestionList will arrive first). If the tag is "questions", the valueFromWebDB is put into the variable QuestionList. Otherwise (else) it is placed in the AnswerList.</p> <p>At the bottom of <span class="basicblock">GotValue</span>, the app checks to see if both lists have been loaded-- one way to check is to see if the lengths of the lists are the same. If they are, displayQAs is called to display them on the phone.</p> <pre class="ai-testing"><b>Test this behavior.</b> Select Restart Phone in the Blocks Editor. When the app initializes, it should display the previously entered questions and answers. If you close the app and restart again, the previous quiz should still appear.</pre><p>The version of <span style="color:green;">MakeQuiz</span> you've created so far works: the user can create a quiz and it will be stored persistently in the database. If you can accept the fact that the quiz is displayed in an inelegant way, you can proceed to creating the sister app, <span style="color:green;">TakeQuiz</span>, which lets a user step through the quiz and answer the questions.</p> <p>If you'd like to learn how to display list data in a more elegant fashion, step through the steps directly below.</p> <h4 class="ai-header">Displaying a List on Multiple Lines</h4> <p>In the app you've built so far, the question and answer lists are displayed separately and with the default list display format, e.g.,</p> <p style="color:grey;">(question1 question2 question3): (answer1 answer2 answer3)</p> <p>In this section, you'll modify the app so that the newly entered question-answer pairs are displayed in tandem, one on each line:</p> <p style="color:grey;">question1:answer1<br /> question2:answer2<br /> question3:answer3</p> <p>Displaying the data in this way is non-trivial, so you'll start by first displaying a single list, the QuestionList, with each item on a separate line.</p> <pre class="ai-box">To display a list on separate lines, you must serialize it . This means to build a single text object with all the items of the list in it and a special character, '\n', between each item. A "\n" within a text object appears as a newline character when displayed. For example, suppose the user has entered two questions, "What is the capital of California?" and "What is the capital of New York?" and these have succesfully been added to the QuestionList . Your displayQAs procedure should build a text object from QuestionList that looks like: <span style="color:black;">"\nWhat is the capital of California\nWhat is the capital of New York?"</span> When displayed on the phone, such text would appear as: <span style="color:black;">What is the capital of California? What is the capital of New York?</span></pre><p>All the changes will occur in the procedure <span class="callblock">displayQAs</span>. You'll remove the blocks within that procedure, and use a <span class="controlblock">foreach</span> block to build the text by successively adding each question. The blocks within the foreach should add the current item (question) to the end of the text object (QuestionsAnswersLabel) you are building. You'll need the following blocks: </p> <table><tr style="background-color: #EFEFEF; font-weight: bold;"><td> Block type </td> <td> Drawer </td> <td> Purpose </td> </tr><tr><td><span class="setblock">set QuestionsAnswersLabel.Text to</span></td> <td>QuestionsAnswersLabel</td> <td>Initialize the label to empty before repeatedly adding to it</td> </tr><tr><td><span class="textblock">text</span> (blank)</td> <td>Text</td> <td>plug into <span class="setblock">set QuestionsAnswersLabel.Text to</span></td> </tr><tr><td><span class="controlblock">foreach</span></td> <td>Control</td> <td>For each item in list, you'll concatenate it to the QuestionsAnswersLabel</td> </tr><tr><td><span class="argblock">name var</span></td> <td>already in foreach</td> <td>The current item of <span class="controlblock">foreach</span>; rename it to "question"</td> </tr><tr><td><span class="argblock">global QuestionList</span></td> <td>My Definitions</td> <td>Plug this into "in list" slot of <span class="controlblock">foreach</span></td> </tr><tr><td><span class="setblock">set QuestionsAnswersLabel.Text to</span></td> <td>QuestionsAnswersLabel</td> <td>Iteratively build the text</td> </tr><tr><td><span class="textblock">make text</span></td> <td>Text</td> <td>build a text object</td> </tr><tr><td><span class="argblock">QuestionsAnswersLabel.Text</span></td> <td>QuestionsAnswersLabel</td> <td>Plug into make text</td> </tr><tr><td><span class="argblock">value question</span></td> <td>My Definitions</td> <td>Plug into make text (make sure you've renamed foreach variable to "question")</td> </tr><tr><td><span class="textblock">text</span> ("/n")</td> <td>Text</td> <td>New-line character so following text on another line</td> </tr></table><p>The blocks should look like this:</p> <p><img src="/sites/all/files/tutorials/makeQuizTakeQuiz/displayQA1.png" /></p> <h4 class="ai-header">How the blocks work</h4> <p>When the procedure is called, the <span class="setblock">QuestionsAnswersLabel.Text</span> is first set to the empty text. This is in preparation for the <span class="controlblock">foreach</span> block that comes next, which will build the text in <span class="setblock">QuestionsAnswersLabel.Text</span> incrementally.</p> <p>The <span class="controlblock">foreach</span> block specifies that the blocks within it are to be executed once for every item in QuestionList. If there are three questions, then the inner blocks will be executed three times. Within the foreach, the current item being processed is named question.</p> <p>On each iteration, <span class="argblock">QuestionsAnswersLabel.Text</span> is modified. Each time it is set to its previous value, along with the newline character, "\n" and the current question being processed.</p> <p>When the <span class="controlblock">foreach</span> completes, <span class="argblock">QuestionsAnswersLabel.Text</span> will be text string with all the items separated by newline characters. As the app is processing each iteration of the foreach , the phone display doesn't change. But when it completes, the text in <span class="argblock">QuestionsAnswersLabel.Text</span> is displayed on the phone and the items appear on separate lines.</p> <pre class="ai-testing"><b>Test the behavior.</b> On the phone, add another question and answer and click Submit. Now, only the questions should be displayed and they should be displayed on separate lines.</pre><h4 class="ai-header">Including the answer in DisplayQAs</h4> <p>The displayQAs procedure you've created ignores answers and only displays questions. In the next version of displayQAs , you'll display the data as question-answer pairs, e.g., </p> <p style="color:grey;">What is the capital of California?: Sacramento<br /> What is the capital of New York?: Albany </p> <p>Modify displayQAs. Use an index variable to access each answer as the foreach block walks through the questions. You'll need the following blocks:</p> <table><tr style="background-color: #EFEFEF; font-weight: bold;"><td> Block type </td> <td> Drawer </td> <td> Purpose </td> </tr><tr><td><span class="setblock">def var</span> ("answer")</td> <td>Definitions</td> <td>To temporarily store each answer</td> </tr><tr><td><span class="setblock">def var</span> ("answerIndex")</td> <td>Definitions</td> <td>To keep track of which answer (and question) you're on</td> </tr><tr><td><span class="textblock">text</span> ("text")</td> <td>Text</td> <td>Initialize the variable answer to text.</td> </tr><tr><td><span class="basicblock">number</span> (1)</td> <td>Math</td> <td>Initialize the variable answerIndex to 1</td> </tr><tr><td><span class="setblock">set answerIndex to</span></td> <td>My Definitions</td> <td>Re-initialize answerIndex each time displayQAs called</td> </tr><tr><td><span class="basicblock">number</span> (1)</td> <td>Math</td> <td>To re-initialize answerIndex to 1</td> </tr><tr><td><span class="setblock">set answer to</span></td> <td>My Definitions</td> <td>set this variable each time in the <span class="controlblock">foreach</span></td> </tr><tr><td><span class="listblock">select list item</span></td> <td>Lists</td> <td>select from the list AnswerList</td> </tr><tr><td><span class="argblock">global AnswerList</span></td> <td>My Definitions</td> <td>plug into list slot of <span class="listblock">select list item</span></td> </tr><tr><td><span class="argblock">global answerIndex</span></td> <td>My Definitions</td> <td>Plug into index slot of <span class="listblock">select list item</span></td> </tr><tr><td><span class="listblock">set answerIndex to</span></td> <td>My Definitions</td> <td>In order to increment it each iteration through loop</td> </tr><tr><td><span class="argblock">global answerIndex</span></td> <td>My Definitions</td> <td>To increment answerIndex , add 1 to itself.</td> </tr><tr><td><span class="basicblock">number</span> (1)</td> <td>Math</td> <td>To increment answerIndex</td> </tr></table><p>The blocks should look like this:</p> <p><img src="/sites/all/files/tutorials/makeQuizTakeQuiz/displayQAsWithAnswers.png" /></p> <h4 class="ai-header">How the blocks work</h4> <p>The <span class="controlblock">foreach</span> only allows you to iterate through one list. In this case, there are two lists and you need to step through and select each answer as you proceed through the questions. The strategy is to use an index variable, as was done with the currentQuestionIndex in the QuizMe tutorial.</p> <p>For this behavior, the index is a position in the AnswerList, so its named answerIndex. The index is set to 1 before the <span class="controlblock">foreach</span> begins. Within the foreach, it is used to select the current answer from the AnswerList, and then it is incremented.</p> <pre class="ai-testing"><b>Test this behavior.</b> On the phone, add some more question/answer pairs. The display should now show each question with its corresponding answer, and each question:answer pair on separate lines.</pre><h4 class="ai-header">Final MakeQuiz App</h4> <p><img src="/sites/all/files/tutorials/makeQuizTakeQuiz/makeQuizFinal.png" /></p> <h4 class="ai-header">Scan the Sample App to your Phone</h4> <p>Scan the following barcode onto your phone to install and run MakeQuiz. </p><p><img src="/sites/all/files/tutorials/makeQuizTakeQuiz/MakeQuizBarcode.png" /></p> <p>Or <a href="http://explore.appinventor.mit.edu/sites/all/files/tutorials/makeQuizTakeQuiz/MakeQuiz.apk">download the source code</a></p> <p>.</p> <h4 class="ai-header">TakeQuiz</h4> <p><a href="http://explore.appinventor.mit.edu/sites/explore.appinventor.mit.edu/files/TakeQuiz.zip"><img src="http://explore.appinventor.mit.edu/sites/explore.appinventor.mit.edu/files/downloadTakeQuizButton.PNG" style="float:right; width: 200px;" /></a></p> <p>Building TakeQuiz is simpler; it can be built with a few modifications to the <a href="http://explore.appinventor.mit.edu/content/quizme">QuizMe</a> app you completed earlier (if you have not completed that tutorial, do so now before continuing).</p> <p>Begin by opening your QuizMe app, choosing SaveAs, and naming the new project "TakeQuiz." This will leave your QuizMe app as is and allow you to use a copy of it as the basis for TakeQuiz. </p> <p>This version of MakeQuiz/TakeQuiz does not handle images, so first remove the images from the TakeQuiz app: </p> <ol><li>In the Component Designer, choose each image from the media palette and delete it. Also delete the Image1 component, which will remove all references to it from the Blocks Editor.</li> <li>In the Blocks Editor, drag the PictureList to the trash.</li> </ol><p>Since TakeQuiz will work with database data, drag a TinyWebDB component into the Component Designer viewer.</p> <p>Now modify the blocks so that the quiz given to the user is the one from the database. First, since there are no fixed questions and answers, remove all of the actual question and answer text blocks from the make a list blocks within the QuestionList and AnswerList. The blocks should look like this:</p> <p><img src="/sites/all/files/tutorials/makeQuizTakeQuiz/emptylists.png" /></p> <p>Now modify your <span class="basicblock">Screen1.Initialize</span> so that it calls <span class="spanblock">TinyWebDB.GetValue</span> twice to load the lists. The blocks should look like this:</p> <p><img src="/sites/all/files/tutorials/makeQuizTakeQuiz/screenInit.png" /></p> <p>Finally, drag out a <span class="basicblock">TinyWebDB.GotValue</span> event-handler. This event-handler should look similar to the one used in MakeQuiz, but here you only want to show the first question and none of the answers. The blocks should look like this:</p> <p><img src="/sites/all/files/tutorials/makeQuizTakeQuiz/TakeQuizGotValue.png" /></p> <h4 class="ai-header">How the Blocks Work</h4> <p>When the app begins, <span class="basicblock">Screen1.Initialize</span> is triggered and the app requests the questions and the answers from the web database. When each of those requests arrives, the <span class="basic">TinyWebDB.GotValue</span> event-handler is triggered. The app asks which request has come in, using tagFromWebDB , and places the valueFromWebDB into the appropriate list. If it is the QuestionList being loaded, the first question is selected from QuestionList and displayed.</p> <pre class="ai-testing"><b>Test the behavior.</b> Click <b>Restart Phone App</b>. Does the first question from the quiz you created with MakeQuiz appear? Can you take the quiz just as you did with QuizMe (except for the pictures)?</pre><h4 class="ai-header">Final Program (Take Quiz)</h4> <p><img src="/sites/all/files/tutorials/makeQuizTakeQuiz/takequizfinal.png" /></p> <h4 class="ai-header">Scan the Sample App to your Phone</h4> <p>Scan the following barcode onto your phone to install and run Take Quiz. </p><p><img src="/sites/all/files/tutorials/makeQuizTakeQuiz/TakeQuizBarcode.png" /></p> <p>Or <a href="http://explore.appinventor.mit.edu/sites/all/files/tutorials/makeQuizTakeQuiz/TakeQuiz.apk">download the source code</a>.</p> <h4 class="ai-header">Variations</h4> <p>Once you get MakeQuiz and TakeQuiz working, you might want to explore some variations. For example,</p> <ul><li>Incorporate images into the apps. The images will need to be URLs from the web, and the test creator will need to specify these URLs as a third item in the MakeQuiz form.</li> <li>Allow the user to delete items from the questions and answers. You can let the user choose using the ListPicker component, and you can remove an item with the remove list item</li> <li>Allow multiple quizzes to be created. You'll need to conceptualize the list of quizzes as a list of lists.</li> </ul><h4 class="ai-header">Review</h4> <p>Here are some of the ideas covered in this tutorial: </p> <ul><li>You can store data persistently in a web database with the <b>TinyWebDB</b> component.</li> <li>You retrieve data from a TinyWebDB database by requesting it with GetValue . When the web database returns the data, the <span class="basicblock">TinyWebDB.GotValue</span> event is triggered. At that point, you can put the data in a list or process it in some way.</li> <li>TinyWebDB data can be shared amongst multiple phones and apps.</li> </ul><pre class="ai-box">MIT and Google are grateful to <a href="http://www.appinventor.org/">Professor David Wolber</a>, CS Professor at The University of San Francisco, for developing this tutorial. Done with <span style="color:black;">MakeQuiz</span> and <span style="color:black;">TakeQuiz</span>? Return to the other tutorials <a href="/tutorials">here</a>.</pre></div></div></div><section class="field field-name-field-version field-type-taxonomy-term-reference field-label-above view-mode-rss clearfix"> <h2 class="field-label">Tutorial Version:&nbsp;</h2> <ul class="field-items"> <li class="field-item even"> <a href="/tutorial-version/app-inventor-1" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">App Inventor 1</a> </li> </ul> </section> <section class="field field-name-field-tutorial-difficulty field-type-taxonomy-term-reference field-label-above view-mode-rss clearfix"> <h2 class="field-label">Tutorial Difficulty:&nbsp;</h2> <ul class="field-items"> <li class="field-item even"> <a href="/tutorial-difficulty/advanced" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">Advanced</a> </li> </ul> </section> <section class="field field-name-field-tutorial-type field-type-taxonomy-term-reference field-label-above view-mode-rss clearfix"> <h2 class="field-label">Tutorial Type:&nbsp;</h2> <ul class="field-items"> <li class="field-item even"> <a href="/tutorial-type/data-storage" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">Data Storage</a> </li> <li class="field-item odd"> <a href="/tutorial-type/game" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">Game</a> </li> </ul> </section> Fri, 14 Jun 2013 16:11:21 +0000 aaron 313 at http://dev-explore.appinventor.mit.edu http://dev-explore.appinventor.mit.edu/content/makequiz-and-takequiz#comments QuizMe http://dev-explore.appinventor.mit.edu/content/quizme <div class="field field-name-body field-type-text-with-summary field-label-hidden view-mode-rss"><div class="field-items"><div class="field-item even" property="content:encoded"><style> <!--/*--><![CDATA[/* ><!--*/ .ButtonText { color:green; font-weight: bold; } li { padding-bottom: 7px; } .basicblock { border: 1px dashed #7AA81C; padding-left: 4px; padding-right: 4px; padding-top: 1px; padding-bottom: 1px; background-color: #E7F2CB; font-size: 9pt; text-wrap: suppress; } .callblock { border: 1px dashed #000000; padding-left: 4px; padding-right: 4px; padding-top: 1px; padding-bottom: 1px; background-color: #E0D1FF; font-size: 9pt; text-wrap: suppress; } .argblock { border: 1px dashed #000000; padding-left: 4px; padding-right: 4px; padding-top: 1px; padding-bottom: 1px; background-color: #E5E5FF; font-size: 9pt; text-wrap: suppress; } .textblock { border: 1px dashed #000000; padding-left: 4px; padding-right: 4px; padding-top: 1px; padding-bottom: 1px; background-color: #FADAA0; font-size: 9pt; text-wrap: suppress; } .setblock { border: 1px dashed #000000; padding-left: 4px; padding-right: 4px; padding-top: 1px; padding-bottom: 1px; background-color: #C1D5F8; font-size: 9pt; text-wrap: suppress; } .controlblock { border: 1px dashed #000000; padding-left: 4px; padding-right: 4px; padding-top: 1px; padding-bottom: 1px; background-color: #FAEDBB; font-size: 9pt; text-wrap: suppress; } .listblock { border: 1px dashed #000000; padding-left: 4px; padding-right: 4px; padding-top: 1px; padding-bottom: 1px; background-color: #FCF5D7; font-size: 9pt; text-wrap: suppress; } /*--><!]]>*/ </style><h2 class="ai-header"><span style="color:green;">QuizMe</span></h2> <h4 class="ai-header">What you're building</h4> <p><img src="http://beta.appinventor.mit.edu/learn/tutorials/quizme/QuizMeAssets/quizOnEmulator.png" style="float:right; height: 453px; width: 197px;" /></p> <p><a href="http://cs.usfca.edu/~wolber/appinventor/bookSplits/ch8Quiz.pdf">Download Alternate Example Version (Book Chapter PDF)</a></p> <p><span style="color:green;">QuizMe</span> is a trivia game about baseball, but you can use it as a template to build quizzes on any topic. With <span style="color:green;">QuizMe</span>:</p> <ul><li>The user steps through a series of questions, clicking a button to proceed to the next question.</li> <li>The user enters an answer for each question and the app reports whether each answer is correct or not.</li> </ul><p>With <span style="color:green;">QuizMe</span>, the quiz questions are always the same unless you, the programmer, change them. Later, you can create <a href="/content/makequiz-and-takequiz">MakeQuiz &amp; TakeQuiz</a>, an app that lets users of the app create and modify the quiz questions.</p> <p>This tutorial assumes you are familiar with the basics of App Inventor -- using the Component Designer to build a user interface, and using the Blocks Editor to specify event-handlers. If you are not familiar with the basics, try stepping through some of the <a href="http://explore.appinventor.mit.edu/tutorials">basic tutorials</a> before continuing.</p> <h4 class="ai-header">Getting Started</h4> <p>Connect to the App Inventor web site and start a new project. Name it <span style="color:green;">QuizMe</span>, and also set the screen's <strong style="color:green;">Title</strong> to "QuizMe". Open the Blocks Editor and connect to the phone.</p> <p>Also download the following pictures of baseball players and save them on your computer. Later, you'll load these images into your project.</p> <ul><li><a href="http://beta.appinventor.mit.edu/learn/tutorials/quizme/QuizMeAssets/Larsenberra.jpg">Larsenberra.jpg</a></li> <li><a href="http://beta.appinventor.mit.edu/learn/tutorials/quizme/QuizMeAssets/dallasbraden.jpg">Dallasbraden.jpg</a></li> <li><a href="http://beta.appinventor.mit.edu/learn/tutorials/quizme/QuizMeAssets/cyyoung.jpg">Cyyoung.jpg</a></li> <li><a href="http://beta.appinventor.mit.edu/learn/tutorials/quizme/QuizMeAssets/nolanryan.jpg">Nolanryan.jpg</a></li> </ul><h4 class="ai-header">Introduction</h4> <p>You'll design the quiz game so that the user proceeds from question to question by clicking a Next button, and receives simple correct/incorrect feedback on each answer.</p> <p>This tutorial introduces:</p> <ul><li>Defining and displaying lists of information.</li> <li>Sequencing through a list using an index variable -- a variable that keeps track of a position in a list.</li> <li>Conditional behaviors-- performing certain operations only when a condition is met.</li> <li>Switching an image to show a different picture at different times.</li> </ul><h4 class="ai-header">Set up the Components</h4> <p>Use the component designer to create the interface for <span style="color:green;">QuizMe</span>. When you finish, it should look something like the snapshot below (there are also more detailed instructions below the snapshot).</p> <p><img src="http://beta.appinventor.mit.edu/learn/tutorials/quizme/QuizMeAssets/designer.png" /></p> <p>To create this interface, first load the images you downloaded into the project. Click on the Add button in the Media area and select one of the downloaded files (e.g., Larsenberra.jpg). Then do the same for the other three images.</p> <p>Next, create the following components by dragging them from the Palette into the Viewer.</p> <table><tr style="background-color: #EFEFEF; font-weight: bold;"><td> Component Type </td> <td> Palette Group </td> <td> What you'll name it </td> <td> Purpose of Component </td> </tr><tr><td> <strong>Image</strong> </td> <td>Basic</td> <td style="color:green;">Image1</td> <td>The picture part of the question</td> </tr><tr><td><strong>Label</strong></td> <td>Basic</td> <td style="color:green;">QuestionLabel</td> <td>Displays the current question</td> </tr><tr><td><strong>HorizontalArrangement</strong></td> <td>Screen Arrangement</td> <td style="color:green;">HorizontalArrangement1</td> <td>Organizes the AnswerPrompt and Text</td> </tr><tr><td><strong>Label</strong></td> <td>Basic</td> <td style="color:green;">AnswerPromptLabel</td> <td>Text prompting for an anwer</td> </tr><tr><td><strong>TextBox</strong></td> <td>Basic</td> <td style="color:green;">AnswerText</td> <td>User will enter answer here.</td> </tr><tr><td><strong>Label</strong></td> <td>Basic</td> <td style="color:green;">RightWrongLabel</td> <td>Correct/Incorrect is displayed here.</td> </tr><tr><td><strong>HorizontalArrangement</strong></td> <td>Screen Arrangement</td> <td style="color:green;">HorizontalArrangement2</td> <td>Organizes the AnswerButton and NextButton</td> </tr><tr><td><strong>Button</strong></td> <td>Basic</td> <td style="color:green;">AnswerButton</td> <td>User clicks to submit an answer</td> </tr><tr><td><strong>Button</strong></td> <td>Basic</td> <td style="color:green;">NextButton</td> <td>User clicks to proceed to the next answer</td> </tr></table><p>Set the properties of the components as described below:</p> <table><tr style="background-color: #EFEFEF; font-weight: bold;"><td><strong>Component</strong></td> <td><strong>Action</strong></td> </tr><tr><td> <span style="color:green;">Image1</span> </td> <td>Set its <span class="ButtonText">Picture</span> property to "Larsenberra.jpg". This is the first picture that should appear.</td> </tr><tr><td><span style="color:green;">QuestionLabel</span> </td> <td> Change <span class="ButtonText">Text</span> property to "question" </td> </tr><tr><td><span style="color:green;">AnswerPromptLabel</span> </td> <td>Change <span class="ButtonText">Text</span> property to "Enter Answer:". On the Viewer screen, move this label into <span style="color:green;">HorizontalArrangement1</span>. </td> </tr><tr><td><span style="color:green;">AnswerText</span> </td> <td>Change <span class="ButtonText">Hint</span> to "please enter an answer". On the Viewer screen, move <span style="color:green;">AnswerText</span> into <span style="color:green;">HorizontalArrangement1</span>. </td> </tr><tr><td><span style="color:green;">AnswerButton</span> </td> <td>Change <span class="ButtonText">Text</span> property to "Submit". On the Viewer, move the button into <span style="color:green;">HorizontalArrangment2.</span> </td> </tr><tr><td> <span style="color:green;">NextButton</span> </td> <td>Change <span class="ButtonText">Text</span> property to "Next". Move the button into <span style="color:green;">HorizontalArrangement2</span>. </td> </tr><tr><td><span style="color:green;">RightWrongLabel</span></td> <td> Change <span class="ButtonText">Text</span> property to "correct/incorrect". </td> </tr></table><h4 class="ai-header">Add Behaviors to the Components</h4> <p>Open the Blocks Editor to add the behaviors for the app. First, you'll define two list variables, <span style="color:green;">QuestionList</span> to hold the list of questions, and <span style="color:green;">AnswerList</span> to hold the list of corresponding answers.</p> <p>To define the two list variables, you'll need the following blocks:</p> <table><tr style="background-color: #EFEFEF; font-weight: bold;"><td>Block Type</td> <td>Drawer</td> <td>Purpose</td> </tr><tr><td><span class="setblock">def variable</span></td> <td>Definitions</td> <td>Defines the <span style="color:green;">QuestionList</span> variable (rename it)</td> </tr><tr><td><span class="setblock">def variable</span></td> <td>Definitions</td> <td>Defines the <span style="color:green;">AnswerList</span> variable (rename it)</td> </tr><tr><td><span class="listblock">make a list</span></td> <td>Lists</td> <td>Used to insert the items of the <span style="color:green;">QuestionList</span></td> </tr><tr><td><span class="textblock">text</span> (3 of them)</td> <td>Text</td> <td>The actual questions</td> </tr><tr><td><span class="listblock">make a list</span></td> <td>Lists</td> <td>Used to insert the items of the <span style="color:green;">AnswerList</span></td> </tr><tr><td><span class="textblock">text</span> (3 of them)</td> <td>Text</td> <td>The actual answers</td> </tr></table><p>You create global variables by dragging in a <span class="setblock">def variable</span> block from the Definitions drawer and double-clicking the default name "variable" to change its name. The <span class="setblock">def variable</span> block has a slot for the initial value of the variable. The variable can represent a number or text, or even a list, for which you can plug in a <span class="listblock">make a list</span> block into the variable definition.</p> <p>The blocks should look like this:</p> <p><img src="http://beta.appinventor.mit.edu/learn/tutorials/quizme/QuizMeAssets/questionlist.png" /></p> <p><img src="http://beta.appinventor.mit.edu/learn/tutorials/quizme/QuizMeAssets/AnswerList.png" /></p> <h4 class="ai-header">Define the Hidden Index Variable</h4> <p>Each time the user clicks the <span style="color:green;">NextButton</span> to proceed through the quiz, the app needs to remember which question it is on. In programming, to remember something, you define a new variable. In this case, the app needs to remember the current question number -- the index into the list <span style="color:green;">QuestionList</span>.</p> <p>To create the variable <span style="color:green;">currentQuestionIndex</span>, you'll need the following blocks:</p> <table><tr style="background-color: #EFEFEF; font-weight: bold;"><td>Block Type</td> <td>Drawer</td> <td>Purpose</td> </tr><tr><td><span class="setblock">def variable</span></td> <td>Definitions</td> <td>Defines the <span style="color:green;">currentQuestionIndex</span> variable (rename it)</td> </tr><tr><td><span class="basicblock">number</span> (1)</td> <td>Math</td> <td>Set the initial value of <span style="color:green;">currentQuestionIndex</span> to 1</td> </tr></table><p>The blocks should look like this:</p> <p><img src="http://beta.appinventor.mit.edu/learn/tutorials/quizme/QuizMeAssets/index.png" /></p> <h4 class="ai-header">Display the first question</h4> <p>To start, you'll ignore the answers and just work on the behavior to sequence through the questions. The desired behavior is the following: when the app starts, the first question should appear in the label named <span style="color:green;">QuestionLabel</span>. When the user clicks the <span style="color:green;">NextButton</span>, the second question should appear. When the user clicks again, the third should appear. When the last question is reached, clicking the <span style="color:green;">NextButton</span> should result in the first question once again appearing in the <span color="color:green;">QuestionLabel</span>.</p> <pre class="ai-box">With App Inventor, you select particular items in a list with the <span class="listblock">select list item</span> block. The block asks you to specify the list and an index--a position in the list. If a list has three items, the indexes 1, 2, and 3 are valid.</pre><p>For <span style="color:green;">QuizMe</span>, when the app starts, the app should choose the first question in the list and display it in the <span style="color:green;">QuestionLabel</span> component.</p> <p>For this app initialization behavior, you'll need the following blocks:</p> <table><tr style="background-color: #EFEFEF; font-weight: bold;"><td>Block Type</td> <td>Drawer</td> <td>Purpose</td> </tr><tr><td><span class="basicblock">Screen1.Initialize</span></td> <td>Screen1</td> <td>When the app begins, this event-handler is triggered.</td> </tr><tr><td><span class="setblock">set QuestionLabel.Text to</span></td> <td>QuestionLabel</td> <td>Need to put the first question in <span style="color:green;">QuestionLabel</span></td> </tr><tr><td><span class="listblock">select list item</span></td> <td>Lists</td> <td>Need to select the first question from <span style="color:green;">QuestionLabel</span></td> </tr><tr><td><span class="argblock">global QuestionList</span></td> <td>My Definitions</td> <td>The list to select from</td> </tr><tr><td><span class="basicblock">number</span> (1)</td> <td>Math</td> <td>Select the first question by using an index of 1</td> </tr></table><p>The blocks should look like this:</p> <p><img src="http://beta.appinventor.mit.edu/learn/tutorials/quizme/QuizMeAssets/screenInit.png" /></p> <h4 class="ai-header">How the blocks work</h4> <p>The <span class="basicblock">Screen1.Initialize</span> event is triggered when the app begins. The first item of the variable <span style="color:green;">QuestionList</span> is selected and placed into <span class="basicblock">QuestionLabel.Text</span>. So when the app begins, the user will see the first question.</p> <pre class="ai-testing"><strong style="color:black;">Test this behavior.</strong> Click <span style="color:black;">Restart Phone App</span> (or <span style="color:black;">Connect Phone</span> if not connected). What appears on the phone? If you created the <span style="color:black;">QuestionList</span> as described above, the first item of <span style="color:black;">QuestionList</span>, "Who pitched a perfect game in the World Series?", should appear in the <span style="color:black;">QuestionLabel</span>.</pre><h4 class="ai-header">Iterating Through the Questions</h4> <p>Now program the behavior of the <span style="color:green;">NextButton</span>. You've already defined the <span class="listblock">currentQuestionIndex</span> to remember the question the user is on. When <span style="color:green;">NextButton</span> is clicked, the app needs to increment this variable, e.g., change it from 1 to 2 or from 2 to 3, etc., and then use the resulting value to select the new "current" question. For this behavior, you'll need the following blocks:</p> <table><tr style="background-color: #EFEFEF; font-weight: bold;"><td>Block Type</td> <td>Drawer</td> <td>Purpose</td> </tr><tr><td><span class="basicblock">NextButton.Click</span></td> <td>NextButton</td> <td>When user clicks Next, this event-handler is triggered.</td> </tr><tr><td><span class="setblock">set currentQuestionIndex to</span></td> <td>My Definitions</td> <td>Need to put the first question in <span style="color:green;">QuestionLabel</span></td> </tr><tr><td><span class="basicblock">+</span> block</td> <td>Math</td> <td>Used to increment <span style="color:green;">currentQuestionIndex</span></td> </tr><tr><td><span class="argblock">global currentQuestionIndex</span></td> <td>My Definitions</td> <td>New value will be old value + 1</td> </tr><tr><td><span class="basicblock">number</span> (1)</td> <td>Math</td> <td>For the + 1</td> </tr><tr><td><span class="setblock">set QuestionLabel.Text to</span></td> <td>QuestionLabel</td> <td>Need to display the next question here</td> </tr><tr><td><span class="listblock">select list item</span></td> <td>Lists</td> <td>Need to select the first question from <span style="color:green;">QuestionList</span></td> </tr><tr><td><span class="argblock">global QuestionList</span></td> <td>My Definitions</td> <td>Plug into <span style="color:green;">list</span> slot of call select list item</td> </tr><tr><td><span class="argblock">global currentQuestionIndex</span></td> <td>My Definitions</td> <td>Plug into <span style="color:green;">index</span> slot of call select list item, we want nth item</td> </tr></table><p>The blocks should look like this:</p> <p><img src="http://beta.appinventor.mit.edu/learn/tutorials/quizme/QuizMeAssets/firstNext.png" /></p> <h4 class="ai-header">How the Blocks Work</h4> <p>The first row of blocks increments the variable <span style="color:green;">currentQuestionIndex</span>. If <span style="color:green;">currentQuestionIndex</span> has a 1 in it, it is changed to 2. If it has a 2, it is changed to 3, and so on. Once the <span style="color:green;">currentQuestionIndex</span> variable has been changed, the app uses it to select the "current" question.</p> <p>Recall that in the <span class="basicblock">Screen.Initialize</span> event-handler, the app selected the first question to display:</p> <p><img src="http://beta.appinventor.mit.edu/learn/tutorials/quizme/QuizMeAssets/selectFirst.png" /></p> <p>When the <span style="color:green;">NextButton</span> is clicked, the app doesn't choose the first item in the list, or the 2nd or 3rd, it chooses the <span class="listblock">currentQuestionIndex</span>-th item.</p> <p><img src="http://beta.appinventor.mit.edu/learn/tutorials/quizme/QuizMeAssets/chooseCurrent.png" /></p> <p>The blocks are executed in a right-to-left manner. The app first evaluates the index parameter of <span class="listblock">select list item</span>, which is the variable <span style="color:green;">currentQuestionIndex</span>. The number is stored in <span style="color:green;">currentQuestionIndex</span> is used as the index when the select list item is executed.</p> <p>When the <span style="color:green;">NextButton</span> is clicked for the first time, the increment blocks will set <span style="color:green;">currentQuestionIndex</span> from 1 to 2, so the app will select the second item from <span style="color:green;">QuestionList</span>, "who pitched the first perfect game of 2010?". The second time <span style="color:green;">NextButton</span> is clicked, <span style="color:green;">currentQuestionIndex</span> will be set from 2 to 3, and the app will select the 3rd question in the list, "who pitched the first perfect game of the modern era?"</p> <pre class="ai-testing"><strong style="color:black;">Test this behavior.</strong> Test the behavior of the <span style="color:black;">NextButton</span> to see if the app is working correctly thus far. To test, play the role of the user and click the <span style="color:black;">NextButton</span> on the phone. Does the phone display the second question, "Who pitched the first perfect game of 2010?" It should, and the third question should appear when you click the <span style="color:black;">NextButton</span> again. If this is working, pat yourself on the back quickly, and then go on. Try clicking the <span style="color:black;">NextButton</span> again (a third time). You should see an error: "Attempting to get item 4 of a list of length 3". The app has a bug-- do you know what the problem is?</pre><p>The problem with the app is that it always increments the <span style="color:green;">currentQuestionIndex</span> variable when the <span style="color:green;">NextButton</span> is clicked. When <span style="color:green;">currentQuestionIndex</span> is already 3 and the user clicks the <span style="color:green;">NextButton</span>, the app changes <span style="color:green;">currentQuestionIndex</span> from 3 to 4, then calls select list item to get the <span style="color:green;">currentQuestionIndex</span>-th , or in this case, the 4th item. Since there are only three items in the variable <span style="color:green;">QuestionList</span>, Android complains.</p> <p>What the app needs to do is ask a question-- check a condition-- when the <span style="color:green;">NextButton</span> is clicked, and execute different blocks dependending on the answer. One way to ask the question is to ask, "is the variable <span style="color:green;">currentQuestionIndex</span> already 3?" If the answer is yes, you should set <span style="color:green;">currentQuestionIndex</span> back to 0 so the user is taken back to the first question.</p> <p>You'll need the following blocks:</p> <table><tr style="background-color: #EFEFEF; font-weight: bold;"><td>Block Type</td> <td>Drawer</td> <td>Purpose</td> </tr><tr><td><span class="controlblock">if test then-do</span></td> <td>Control</td> <td>To ask if user is on last question</td> </tr><tr><td><span class="basicblock">=</span> block</td> <td>Math</td> <td>to test if <span class="listblock">currentQuestionIndex</span> is 3</td> </tr><tr><td><span class="setblock">global currentQuestionIndex</span></td> <td>My Definitions</td> <td>-</td> </tr><tr><td><span class="basicblock">number</span> 3</td> <td>Math</td> <td>3 is number of items in the list</td> </tr><tr><td><span class="setblock">set currentQuestionIndex to</span></td> <td>My Definitions</td> <td>set to 0 to go back to first question</td> </tr><tr><td><span class="basicblock">Number</span> 0</td> <td>Math</td> <td>set to 0 because next blocks will increment to 1</td> </tr></table><p>The modified <span class="basicblock">NextButton.Click</span> event-handler should look like this:</p> <p><img src="http://beta.appinventor.mit.edu/learn/tutorials/quizme/QuizMeAssets/nextif3.png" /></p> <h4 class="ai-header">How the blocks work</h4> <p>When the <span style="color:green;">NextButton</span> is clicked, the app first checks to see if <span style="color:green;">currentQuestionIndex</span> has a 3 in it. If it does, <span style="color:green;">currentQuestionIndex</span> is set back to 0 so that when 1 is added to it with the blocks below, it will be 1 and the quiz will loop back to display the first question. Note that only the blocks inset within the <span class="controlblock">if-test-then-do</span> block are dependent on the condition-- the increment and set <span class="setblock">QuestionLabel.Text to</span> blocks are executed under all conditions.</p> <pre class="ai-testing"><strong style="color:black;">Test this behavior.</strong> Because variables like <span style="color:black;">currentQuestionIndex</span> are hidden, they are often the source of bugs in a program. Fortunately, App Inventor provides a way to make such hidden variables transparent during testing. Specifically, App Inventor allows you to "watch" how the value of a variable change as an app progresses. For this test, right-click the <span style="color:black;">currentQuestionIndex</span> def block in the Blocks Editor and choose <span style="color:black;">Watch</span>. Then choose <span style="color:black;">Restart Phone App</span>. The def block will then appear with a watch box showing the initial value of <span style="color:black;">currentQuestionIndex</span> (which should be 1): <img src="http://beta.appinventor.mit.edu/learn/tutorials/quizme/QuizMeAssets/watchindex1.png" /> Now pick up the phone and click the <span style="color:black;">NextButton</span>. The second question, "who pitched the most recent perfect game in the major leagues?" should appear in the <span style="color:black;">QuestionLabel</span> on the phone, as before. On the App Inventor screen, 2 should appear in the <span style="color:black;">currentQuestionIndex</span> memory cell: <img src="http://beta.appinventor.mit.edu/learn/tutorials/quizme/QuizMeAssets/watchindex2.png" /> When you click again, the third question should appear on the phone and 3 should appear in the memory cell . If you click again, 1 should appear in <span style="color:black;">currentQuestionIndex</span> and the first question on the phone.</pre><h4 class="ai-header">A Maintainable App: Making it Easy to Modify the Questions</h4> <p>Next, you'll modify the app to make it easy to add and remove elements from the list. You'll rewrite the blocks so that they'll work on any list, not just one with exactly three items. To begin, add a fourth question to <span style="color:green;">QuestionList</span> and another answer into <span style="color:green;">AnswerList</span>. The blocks should look like this:</p> <p><img src="http://beta.appinventor.mit.edu/learn/tutorials/quizme/QuizMeAssets/listsWith4.png" /></p> <pre class="ai-testing"><strong style="color:black;">Test the modified app.</strong> Click the <span style="color:black;">NextButton</span> a number of times. You should see that the fourth question never appears, no matter how many times you click <span style="color:black;">Next</span>.</pre><p>The problem is that the test to see if the user is on the last question is too specific: it asks if the <span style="color:green;">currentQuestionIndex</span> variable is 3:</p> <p><img src="http://beta.appinventor.mit.edu/learn/tutorials/quizme/QuizMeAssets/if3.png" /></p> <p>You could just change the number 3 to a 4, and the app would again work correctly. The problem with this solution, however, is that each time you modify the questions and answers, you also have to remember to make this change. Such dependencies in a computer program often lead to bugs, especially as an app grows in complexity. It's much better to set the program up so that it will work no matter how many questions there are. Such generality is even more important when the list you are working with changes dynamically, e.g., a quiz app that allows the user to add new questions.</p> <p>The better solution is to ask the question in a more general way. You really want to know if the current question the user is on-- the value of <span style="color:green;">currentQuestionIndex</span> -- is as large as the number of items in <span style="color:green;">QuestionList</span>. If the app asks the question in this more general manner, it will work even when you add to or remove items from the <span style="color:green;">QuestionList</span>. To modify the <span class="basicblock">NextButton.Click</span> event-handler you'll replace the previous test that referred directly to 3. You'll need the following blocks:</p> <table><tr style="background-color: #EFEFEF; font-weight: bold;"><td>Block Type</td> <td>Drawer</td> <td>Purpose</td> </tr><tr><td><span class="listblock">length of list</span></td> <td>Lists</td> <td>asks how many items are in <span style="color:green;">QuestionList</span></td> </tr><tr><td><span class="argblock">global QuestionList</span></td> <td>My Definitions</td> <td>put into list slot of <span class="listblock">length of list</span></td> </tr></table><p>Your <span class="basicblock">NextButton.Click</span> event-handler should now appear as:</p> <p><img src="http://beta.appinventor.mit.edu/learn/tutorials/quizme/QuizMeAssets/nextWithLength.png" /></p> <h4 class="ai-header">How the Blocks Work</h4> <p>The <span class="controlblock">if</span> test now compares the <span style="color:green;">currentQuestionIndex</span> to the length of the <span style="color:green;">QuestionList</span>. So if <span style="color:green;">currentQuestionIndex</span> has a 4 in it, and the length of the <span style="color:green;">QuestionList</span> is 4, then the <span style="color:green;">currentQuestionIndex</span> will be set to 0 (and then 1 after the increment operation in the first row of blocks after the if). Note that, because the blocks no longer refer to 3 or any specific size, the behavior will work no matter how many items are in the list.</p> <pre class="ai-testing"><strong style="color:black;">Test the modified behavior.</strong> When you click the <span style="color:black;">NextButton</span>, does the app now sequence through the four questions, moving to the first one after the fourth?</pre><h4 class="ai-header">Switching the Image for Each Question</h4> <p>The current app shows the same image, no matter what question is being asked. You can change this so an image pertaining to each question appears when the <span style="color:green;">NextButton</span> is clicked. Earlier, you added four pictures as media for the project. Now, you'll create a third list, <span style="color:green;">PictureList</span>, with the names of the image files as its items. and you'll modify the <span class="basicblock">NextButton.Click</span> event-handler to switch the picture each time.</p> <p>First, create a <span style="color:green;">PictureList</span> and initialize it with the names of the image files. Be sure that the names are exactly the same as the names of the files that were loaded in to the media of the project. Here's how the blocks for the <span style="color:green;">PictureList</span> should look:</p> <p><img src="http://beta.appinventor.mit.edu/learn/tutorials/quizme/QuizMeAssets/pictureList.png" /></p> <p>Next, you need to modify the <span class="basicblock">NextButton.Click</span> event-handler so that it modifies the picture depending on what question the user is on. If you set the <strong style="color:green;">Image.Picture</strong> property to a file name of an image that has been loaded, that image will appear. To modify <span class="basicblock">NextButton.Click</span>, you'll need the following blocks:</p> <table><tr style="background-color: #EFEFEF; font-weight: bold;"><td>Block Type</td> <td>Drawer</td> <td>Purpose</td> </tr><tr><td><span class="setblock">set Image1.Picture to </span></td> <td>Image1</td> <td>set this to change the picture</td> </tr><tr><td><span class="listblock">select list item</span></td> <td>Lists</td> <td>need to select the picture corresponding to current question</td> </tr><tr><td><span class="argblock">global PictureList</span></td> <td>My Definitions</td> <td>select a file name from this list</td> </tr><tr><td><span class="argblock">global currentQuestionIndex</span></td> <td>My Definitions</td> <td>select the <span style="color:green;">currentQuestionIndex</span>-th item</td> </tr></table><p>Here is how the blocks should look:</p> <p><img src="http://beta.appinventor.mit.edu/learn/tutorials/quizme/QuizMeAssets/nextWithImageSwitch.png" /></p> <h4 class="ai-header">How the Blocks Work</h4> <p>The <span style="color:green;">currentQuestionIndex</span> serves as the index for the <span style="color:green;">QuestionList</span> and the <span style="color:green;&gt;PictureList&lt;/span&gt;. When &lt;span style=" color:green="">currentQuestionIndex</span> is 1, the app selects the first question and the first picture. When <span style="color:green;">currentQuestionIndex</span> is 2, the app selects the second question and second picture. Of course this scheme depends on the lists being in sync and indeed they are. For instance, the first picture, LarsenBerra.jpg, is a picture of Don Larsen, and Don Larsen is the answer to the first question, "Who pitched a perfect game in the World Series?" Test the modified behavior. Does a different image appear each time you click the <span style="color:green;">NextButton</span>?</p> <h4 class="ai-header">Evaluating Answers</h4> <p>Next, you'll add blocks that report whether the user has answered a question correctly or not. The user enters the answer in <span style="color:green;">AnswerText</span> and then clicks the <span style="color:green;">AnswerButton</span>. The app must compare the user's entry with the answer to the "current" question, using an <span class="controlblock">ifelse</span> block to check. The <span style="color:green;">RightWrongLabel</span> should be modified to report whether or not the answer is correct. You'll need the following blocks for this behavior:</p> <table><tr style="background-color: #EFEFEF; font-weight: bold;"><td>Block Type</td> <td>Drawer</td> <td>Purpose</td> </tr><tr><td><span class="basicblock">AnswerButton.Click</span></td> <td>AnswerButton</td> <td>the behavior is triggered when user clicks the <span style="color:green;">AnswerButton</span></td> </tr><tr><td><span class="controlblock">ifelse</span></td> <td>Control</td> <td>if answer is correct, do one thing, else do another</td> </tr><tr><td><span class="basicblock">=</span> block</td> <td>Math</td> <td>to ask if answer is correct</td> </tr><tr><td><span class="argblock">AnswerText.Text</span></td> <td>AnswerText</td> <td>the user's answer is in this textbox</td> </tr><tr><td><span class="listblock">select list item</span></td> <td>Lists</td> <td>to select the current answer from <span style="color:green;">AnswerList</span></td> </tr><tr><td><span class="argblock">global AnswerList</span></td> <td>My Definitions</td> <td>The list to select from</td> </tr><tr><td><span class="argblock">global currentQuestionIndex</span></td> <td>My Definitions</td> <td>the question number (and answer number) the user is on</td> </tr><tr><td><span class="setblock">set RightWrongLabel.Text to</span></td> <td>RightWrongLabel</td> <td>report the answer here</td> </tr><tr><td><span class="textblock">text block</span> "correct"</td> <td>Text</td> <td>if answer is right</td> </tr><tr><td><span class="setblock">set RightWrongLabel.Text to</span></td> <td>RightWrongLabel</td> <td>report the answer here</td> </tr><tr><td><span class="textblock">text block</span> "incorrect"</td> <td>Text</td> <td>if answer is wrong</td> </tr></table><p>The blocks should look like this:</p> <p><img src="http://beta.appinventor.mit.edu/learn/tutorials/quizme/QuizMeAssets/answerButton.png" /></p> <h4 class="ai-header">How the Blocks Work</h4> <p>The <span class="controlblock">ifelse</span> test reads, "is the user's answer (<strong style="color:green;">AnswerText.Text</strong>) equal to the <span style="color:green;">currentQuestionIndex</span>-th item in the <span style="color:green;">AnswerList</span>?" If <span style="color:green;">currentQuestionIndex</span> is 1, the app will compare the user's answer with the first item in <span style="color:green;">AnswerList</span>, "Don Larsen". If <span style="color:green;">currentQuestionIndex</span> is 2, the app will compare the user's answer with the second answer in the list, "Dallas Braden", and so on. If the test result is positive, the <span class="controlblock">then-do</span> blocks are executed and the <span style="color:green;">RightWrongLabel</span> is set to "correct!". If the test is false, the <span class="controlblock">else-do</span> blocks are executed and the <span style="color:green;">RightWrongLabel</span> is set to "incorrect".</p> <pre class="ai-testing"><strong style="color:black;">Test the modified app.</strong> Try answering one of the questions. It should report whether or not you answered the question exactly as is specified in the <span style="color:black;">AnswerList</span>. Test with both a correct and incorrect answer (because text is being compared, the test is case-sensitive). Click the <span style="color:black;">NextButton</span> and answer a second question. Does it still work? It should, but you might notice that when you click the <span style="color:black;">NextButton</span>, the "correct"/"incorrect" text and the previous answer are still there. Though it's fairly innocuous, such user interface issues will definitely be noticed by the users of your app.</pre><p>To blank out the <span style="color:green;">RightWrongLabel</span> and the <span style="color:green;">AnswerText</span>, you'll put the following blocks within the <span class="basicblock">NextButton.click</span> event-handler:</p> <table><tr style="background-color: #EFEFEF; font-weight: bold;"><td>Block Type</td> <td>Drawer</td> <td>Purpose</td> </tr><tr><td><span class="setblock">set RightWrongLabel.Text to</span></td> <td>RightWrongLabel</td> <td>the label to blank out</td> </tr><tr><td><span class="textblock">text</span> (blank)</td> <td>Text</td> <td>When <span style="color:green;">Next</span> is clicked, erase old answer critique</td> </tr><tr><td><span class="setblock">set AnswerText.Text to</span></td> <td>AnswerText</td> <td>the user's answer from previous question</td> </tr><tr><td><span class="textblock">text</span> (blank)</td> <td>Text</td> <td>When <span style="color:green;">Next</span> is clicked, erase old answer</td> </tr></table><p>The blocks should look like this:</p> <p><img src="http://beta.appinventor.mit.edu/learn/tutorials/quizme/QuizMeAssets/nextButtonFinal.png" /></p> <h4 class="ai-header">How the Blocks Work</h4> <p>When the <span style="color:green;">NextButton</span> is clicked, the user is moving on to the next question, so the top two rows of the event-handler blank out the <span style="color:green;">RightWrongLabel</span> and the <span style="color:green;">AnswerText</span>.</p> <pre class="ai-testing"><strong style="color:black;">Test this behavior.</strong> Answer a question and click <span style="color;black;">Submit</span>, then click the <span style="color:black;">NextButton</span>. Does your previous answer and the apps critique disappear?</pre><h4 class="ai-header">Final Program</h4> <p><strong><span style="color:green;">QuizMe</span>! Final Version:</strong></p> <p><img src="http://beta.appinventor.mit.edu/learn/tutorials/quizme/QuizMeAssets/quizmeFinal.png" /></p> <p>Package the final version of the app by choosing <strong>Package For Phone | Barcode</strong> from the Component Designer menu. When the barcode appears, use the barcode scanner on your phone to download and install the app.</p> <h4 class="ai-header">Variations</h4> <p>Once you get a quiz working, you might want to explore some variations. For example,</p> <ul><li>Instead of just showing images for each question, try playing a sound clip or a short video. With sound, you can turn your quiz app into a <span style="color:green;">Name That Tune</span> app.</li> <li>The quiz is very rigid in terms of what is accepted as a valid answer. There are a number of ways to modify this. One is to use the text.contains block to see if the user's answer is contained in the actual answer. Another is to provide multiple answers for each question, and check by iterating (using <span class="controlblock">foreach</span>) through them to see if any match.</li> <li>Transform the quiz so that it is multiple-choice. The list of answers will need to be a list of lists, with each sub-list holding the answer choices. Use the <strong>ListPicker</strong> component to allow the user to choose an answer.</li> </ul><h4 class="ai-header">Review</h4> <p>Here are some of the ideas covered in this tutorial:</p> <ul><li>Apps can be written in a general manner so that they work with any data list.</li> <li>Index variables are used to track the current position within a list. When you increment them, be careful about reaching the end of the list.</li> </ul><h4 class="ai-header">Scan the Sample App to your Phone</h4> <p>Scan the following barcode onto your phone to install and run the sample app. </p><p><img src="/sites/all/files/tutorials/quizMe/QuizMeBarcode.png" /></p> <h4 class="ai-header">Download Source Code</h4> <p>If you'd like to work with this sample in App Inventor, download the <a href="/sites/all/files/tutorials/quizMe/QuizMe.zip">source code</a> to your computer, then open App Inventor, go to the My Projects page, and choose <b>More Actions | Upload Source</b>.</p> <pre class="ai-box">MIT and Google are grateful to <a href="http://www.appinventor.org/">Professor David Wolber</a>, CS Professor at The University of San Francisco, for developing this tutorial. Done with <span style="color:black;">QuizMe</span>? Return to the other tutorials <a href="/tutorials">here</a>.</pre><style> <!--/*--><![CDATA[/* ><!--*/ .ButtonText { color:green; font-weight: bold; } li { padding-bottom: 7px; } .basicblock { border: 1px dashed #7AA81C; padding-left: 4px; padding-right: 4px; padding-top: 1px; padding-bottom: 1px; background-color: #E7F2CB; font-size: 9pt; text-wrap: suppress; } .callblock { border: 1px dashed #000000; padding-left: 4px; padding-right: 4px; padding-top: 1px; padding-bottom: 1px; background-color: #E0D1FF; font-size: 9pt; text-wrap: suppress; } .argblock { border: 1px dashed #000000; padding-left: 4px; padding-right: 4px; padding-top: 1px; padding-bottom: 1px; background-color: #E5E5FF; font-size: 9pt; text-wrap: suppress; } .textblock { border: 1px dashed #000000; padding-left: 4px; padding-right: 4px; padding-top: 1px; padding-bottom: 1px; background-color: #FADAA0; font-size: 9pt; text-wrap: suppress; } .setblock { border: 1px dashed #000000; padding-left: 4px; padding-right: 4px; padding-top: 1px; padding-bottom: 1px; background-color: #C1D5F8; font-size: 9pt; text-wrap: suppress; } .controlblock { border: 1px dashed #000000; padding-left: 4px; padding-right: 4px; padding-top: 1px; padding-bottom: 1px; background-color: #FAEDBB; font-size: 9pt; text-wrap: suppress; } .listblock { border: 1px dashed #000000; padding-left: 4px; padding-right: 4px; padding-top: 1px; padding-bottom: 1px; background-color: #FCF5D7; font-size: 9pt; text-wrap: suppress; } /*--><!]]>*/ </style><h2 class="ai-header"><span style="color:green;">QuizMe</span></h2> <h4 class="ai-header">What you're building</h4> <p><img src="http://beta.appinventor.mit.edu/learn/tutorials/quizme/QuizMeAssets/quizOnEmulator.png" style="float:right; height: 453px; width: 197px;" /></p> <p><a href="http://cs.usfca.edu/~wolber/appinventor/bookSplits/ch8Quiz.pdf">Download Alternate Example Version (Book Chapter PDF)</a></p> <p><span style="color:green;">QuizMe</span> is a trivia game about baseball, but you can use it as a template to build quizzes on any topic. With <span style="color:green;">QuizMe</span>:</p> <ul><li>The user steps through a series of questions, clicking a button to proceed to the next question.</li> <li>The user enters an answer for each question and the app reports whether each answer is correct or not.</li> </ul><p>With <span style="color:green;">QuizMe</span>, the quiz questions are always the same unless you, the programmer, change them. Later, you can create <a href="/content/makequiz-and-takequiz">MakeQuiz &amp; TakeQuiz</a>, an app that lets users of the app create and modify the quiz questions.</p> <p>This tutorial assumes you are familiar with the basics of App Inventor -- using the Component Designer to build a user interface, and using the Blocks Editor to specify event-handlers. If you are not familiar with the basics, try stepping through some of the <a href="http://explore.appinventor.mit.edu/content/tutorials">basic tutorials</a> before continuing.</p> <h4 class="ai-header">Getting Started</h4> <p>Connect to the App Inventor web site and start a new project. Name it <span style="color:green;">QuizMe</span>, and also set the screen's <strong style="color:green;">Title</strong> to "QuizMe". Open the Blocks Editor and connect to the phone.</p> <p>Also download the following pictures of baseball players and save them on your computer. Later, you'll load these images into your project.</p> <ul><li><a href="http://beta.appinventor.mit.edu/learn/tutorials/quizme/QuizMeAssets/Larsenberra.jpg">Larsenberra.jpg</a></li> <li><a href="http://beta.appinventor.mit.edu/learn/tutorials/quizme/QuizMeAssets/dallasbraden.jpg">Dallasbraden.jpg</a></li> <li><a href="http://beta.appinventor.mit.edu/learn/tutorials/quizme/QuizMeAssets/cyyoung.jpg">Cyyoung.jpg</a></li> <li><a href="http://beta.appinventor.mit.edu/learn/tutorials/quizme/QuizMeAssets/nolanryan.jpg">Nolanryan.jpg</a></li> </ul><h4 class="ai-header">Introduction</h4> <p>You'll design the quiz game so that the user proceeds from question to question by clicking a Next button, and receives simple correct/incorrect feedback on each answer.</p> <p>This tutorial introduces:</p> <ul><li>Defining and displaying lists of information.</li> <li>Sequencing through a list using an index variable -- a variable that keeps track of a position in a list.</li> <li>Conditional behaviors-- performing certain operations only when a condition is met.</li> <li>Switching an image to show a different picture at different times.</li> </ul><h4 class="ai-header">Set up the Components</h4> <p>Use the component designer to create the interface for <span style="color:green;">QuizMe</span>. When you finish, it should look something like the snapshot below (there are also more detailed instructions below the snapshot).</p> <p><img src="http://beta.appinventor.mit.edu/learn/tutorials/quizme/QuizMeAssets/designer.png" /></p> <p>To create this interface, first load the images you downloaded into the project. Click on the Add button in the Media area and select one of the downloaded files (e.g., Larsenberra.jpg). Then do the same for the other three images.</p> <p>Next, create the following components by dragging them from the Palette into the Viewer.</p> <table><tr style="background-color: #EFEFEF; font-weight: bold;"><td> Component Type </td> <td> Palette Group </td> <td> What you'll name it </td> <td> Purpose of Component </td> </tr><tr><td> <strong>Image</strong> </td> <td>Basic</td> <td style="color:green;">Image1</td> <td>The picture part of the question</td> </tr><tr><td><strong>Label</strong></td> <td>Basic</td> <td style="color:green;">QuestionLabel</td> <td>Displays the current question</td> </tr><tr><td><strong>HorizontalArrangement</strong></td> <td>Screen Arrangement</td> <td style="color:green;">HorizontalArrangement1</td> <td>Organizes the AnswerPrompt and Text</td> </tr><tr><td><strong>Label</strong></td> <td>Basic</td> <td style="color:green;">AnswerPromptLabel</td> <td>Text prompting for an anwer</td> </tr><tr><td><strong>TextBox</strong></td> <td>Basic</td> <td style="color:green;">AnswerText</td> <td>User will enter answer here.</td> </tr><tr><td><strong>Label</strong></td> <td>Basic</td> <td style="color:green;">RightWrongLabel</td> <td>Correct/Incorrect is displayed here.</td> </tr><tr><td><strong>HorizontalArrangement</strong></td> <td>Screen Arrangement</td> <td style="color:green;">HorizontalArrangement2</td> <td>Organizes the AnswerButton and NextButton</td> </tr><tr><td><strong>Button</strong></td> <td>Basic</td> <td style="color:green;">AnswerButton</td> <td>User clicks to submit an answer</td> </tr><tr><td><strong>Button</strong></td> <td>Basic</td> <td style="color:green;">NextButton</td> <td>User clicks to proceed to the next answer</td> </tr></table><p>Set the properties of the components as described below:</p> <table><tr style="background-color: #EFEFEF; font-weight: bold;"><td><strong>Component</strong></td> <td><strong>Action</strong></td> </tr><tr><td> <span style="color:green;">Image1</span> </td> <td>Set its <span class="ButtonText">Picture</span> property to "Larsenberra.jpg". This is the first picture that should appear.</td> </tr><tr><td><span style="color:green;">QuestionLabel</span> </td> <td> Change <span class="ButtonText">Text</span> property to "question" </td> </tr><tr><td><span style="color:green;">AnswerPromptLabel</span> </td> <td>Change <span class="ButtonText">Text</span> property to "Enter Answer:". On the Viewer screen, move this label into <span style="color:green;">HorizontalArrangement1</span>. </td> </tr><tr><td><span style="color:green;">AnswerText</span> </td> <td>Change <span class="ButtonText">Hint</span> to "please enter an answer". On the Viewer screen, move <span style="color:green;">AnswerText</span> into <span style="color:green;">HorizontalArrangement1</span>. </td> </tr><tr><td><span style="color:green;">AnswerButton</span> </td> <td>Change <span class="ButtonText">Text</span> property to "Submit". On the Viewer, move the button into <span style="color:green;">HorizontalArrangment2.</span> </td> </tr><tr><td> <span style="color:green;">NextButton</span> </td> <td>Change <span class="ButtonText">Text</span> property to "Next". Move the button into <span style="color:green;">HorizontalArrangement2</span>. </td> </tr><tr><td><span style="color:green;">RightWrongLabel</span></td> <td> Change <span class="ButtonText">Text</span> property to "correct/incorrect". </td> </tr></table><h4 class="ai-header">Add Behaviors to the Components</h4> <p>Open the Blocks Editor to add the behaviors for the app. First, you'll define two list variables, <span style="color:green;">QuestionList</span> to hold the list of questions, and <span style="color:green;">AnswerList</span> to hold the list of corresponding answers.</p> <p>To define the two list variables, you'll need the following blocks:</p> <table><tr style="background-color: #EFEFEF; font-weight: bold;"><td>Block Type</td> <td>Drawer</td> <td>Purpose</td> </tr><tr><td><span class="setblock">def variable</span></td> <td>Definitions</td> <td>Defines the <span style="color:green;">QuestionList</span> variable (rename it)</td> </tr><tr><td><span class="setblock">def variable</span></td> <td>Definitions</td> <td>Defines the <span style="color:green;">AnswerList</span> variable (rename it)</td> </tr><tr><td><span class="listblock">make a list</span></td> <td>Lists</td> <td>Used to insert the items of the <span style="color:green;">QuestionList</span></td> </tr><tr><td><span class="textblock">text</span> (3 of them)</td> <td>Text</td> <td>The actual questions</td> </tr><tr><td><span class="listblock">make a list</span></td> <td>Lists</td> <td>Used to insert the items of the <span style="color:green;">AnswerList</span></td> </tr><tr><td><span class="textblock">text</span> (3 of them)</td> <td>Text</td> <td>The actual answers</td> </tr></table><p>You create global variables by dragging in a <span class="setblock">def variable</span> block from the Definitions drawer and double-clicking the default name "variable" to change its name. The <span class="setblock">def variable</span> block has a slot for the initial value of the variable. The variable can represent a number or text, or even a list, for which you can plug in a <span class="listblock">make a list</span> block into the variable definition.</p> <p>The blocks should look like this:</p> <p><img src="http://beta.appinventor.mit.edu/learn/tutorials/quizme/QuizMeAssets/questionlist.png" /></p> <p><img src="http://beta.appinventor.mit.edu/learn/tutorials/quizme/QuizMeAssets/AnswerList.png" /></p> <h4 class="ai-header">Define the Hidden Index Variable</h4> <p>Each time the user clicks the <span style="color:green;">NextButton</span> to proceed through the quiz, the app needs to remember which question it is on. In programming, to remember something, you define a new variable. In this case, the app needs to remember the current question number -- the index into the list <span style="color:green;">QuestionList</span>.</p> <p>To create the variable <span style="color:green;">currentQuestionIndex</span>, you'll need the following blocks:</p> <table><tr style="background-color: #EFEFEF; font-weight: bold;"><td>Block Type</td> <td>Drawer</td> <td>Purpose</td> </tr><tr><td><span class="setblock">def variable</span></td> <td>Definitions</td> <td>Defines the <span style="color:green;">currentQuestionIndex</span> variable (rename it)</td> </tr><tr><td><span class="basicblock">number</span> (1)</td> <td>Math</td> <td>Set the initial value of <span style="color:green;">currentQuestionIndex</span> to 1</td> </tr></table><p>The blocks should look like this:</p> <p><img src="http://beta.appinventor.mit.edu/learn/tutorials/quizme/QuizMeAssets/index.png" /></p> <h4 class="ai-header">Display the first question</h4> <p>To start, you'll ignore the answers and just work on the behavior to sequence through the questions. The desired behavior is the following: when the app starts, the first question should appear in the label named <span style="color:green;">QuestionLabel</span>. When the user clicks the <span style="color:green;">NextButton</span>, the second question should appear. When the user clicks again, the third should appear. When the last question is reached, clicking the <span style="color:green;">NextButton</span> should result in the first question once again appearing in the <span color="color:green;">QuestionLabel</span>.</p> <pre class="ai-box">With App Inventor, you select particular items in a list with the <span class="listblock">select list item</span> block. The block asks you to specify the list and an index--a position in the list. If a list has three items, the indexes 1, 2, and 3 are valid.</pre><p>For <span style="color:green;">QuizMe</span>, when the app starts, the app should choose the first question in the list and display it in the <span style="color:green;">QuestionLabel</span> component.</p> <p>For this app initialization behavior, you'll need the following blocks:</p> <table><tr style="background-color: #EFEFEF; font-weight: bold;"><td>Block Type</td> <td>Drawer</td> <td>Purpose</td> </tr><tr><td><span class="basicblock">Screen1.Initialize</span></td> <td>Screen1</td> <td>When the app begins, this event-handler is triggered.</td> </tr><tr><td><span class="setblock">set QuestionLabel.Text to</span></td> <td>QuestionLabel</td> <td>Need to put the first question in <span style="color:green;">QuestionLabel</span></td> </tr><tr><td><span class="listblock">select list item</span></td> <td>Lists</td> <td>Need to select the first question from <span style="color:green;">QuestionLabel</span></td> </tr><tr><td><span class="argblock">global QuestionList</span></td> <td>My Definitions</td> <td>The list to select from</td> </tr><tr><td><span class="basicblock">number</span> (1)</td> <td>Math</td> <td>Select the first question by using an index of 1</td> </tr></table><p>The blocks should look like this:</p> <p><img src="http://beta.appinventor.mit.edu/learn/tutorials/quizme/QuizMeAssets/screenInit.png" /></p> <h4 class="ai-header">How the blocks work</h4> <p>The <span class="basicblock">Screen1.Initialize</span> event is triggered when the app begins. The first item of the variable <span style="color:green;">QuestionList</span> is selected and placed into <span class="basicblock">QuestionLabel.Text</span>. So when the app begins, the user will see the first question.</p> <pre class="ai-testing"><strong style="color:black;">Test this behavior.</strong> Click <span style="color:black;">Restart Phone App</span> (or <span style="color:black;">Connect Phone</span> if not connected). What appears on the phone? If you created the <span style="color:black;">QuestionList</span> as described above, the first item of <span style="color:black;">QuestionList</span>, "Who pitched a perfect game in the World Series?", should appear in the <span style="color:black;">QuestionLabel</span>.</pre><h4 class="ai-header">Iterating Through the Questions</h4> <p>Now program the behavior of the <span style="color:green;">NextButton</span>. You've already defined the <span class="listblock">currentQuestionIndex</span> to remember the question the user is on. When <span style="color:green;">NextButton</span> is clicked, the app needs to increment this variable, e.g., change it from 1 to 2 or from 2 to 3, etc., and then use the resulting value to select the new "current" question. For this behavior, you'll need the following blocks:</p> <table><tr style="background-color: #EFEFEF; font-weight: bold;"><td>Block Type</td> <td>Drawer</td> <td>Purpose</td> </tr><tr><td><span class="basicblock">NextButton.Click</span></td> <td>NextButton</td> <td>When user clicks Next, this event-handler is triggered.</td> </tr><tr><td><span class="setblock">set currentQuestionIndex to</span></td> <td>My Definitions</td> <td>Need to put the first question in <span style="color:green;">QuestionLabel</span></td> </tr><tr><td><span class="basicblock">+</span> block</td> <td>Math</td> <td>Used to increment <span style="color:green;">currentQuestionIndex</span></td> </tr><tr><td><span class="argblock">global currentQuestionIndex</span></td> <td>My Definitions</td> <td>New value will be old value + 1</td> </tr><tr><td><span class="basicblock">number</span> (1)</td> <td>Math</td> <td>For the + 1</td> </tr><tr><td><span class="setblock">set QuestionLabel.Text to</span></td> <td>QuestionLabel</td> <td>Need to display the next question here</td> </tr><tr><td><span class="listblock">select list item</span></td> <td>Lists</td> <td>Need to select the first question from <span style="color:green;">QuestionList</span></td> </tr><tr><td><span class="argblock">global QuestionList</span></td> <td>My Definitions</td> <td>Plug into <span style="color:green;">list</span> slot of call select list item</td> </tr><tr><td><span class="argblock">global currentQuestionIndex</span></td> <td>My Definitions</td> <td>Plug into <span style="color:green;">index</span> slot of call select list item, we want nth item</td> </tr></table><p>The blocks should look like this:</p> <p><img src="http://beta.appinventor.mit.edu/learn/tutorials/quizme/QuizMeAssets/firstNext.png" /></p> <h4 class="ai-header">How the Blocks Work</h4> <p>The first row of blocks increments the variable <span style="color:green;">currentQuestionIndex</span>. If <span style="color:green;">currentQuestionIndex</span> has a 1 in it, it is changed to 2. If it has a 2, it is changed to 3, and so on. Once the <span style="color:green;">currentQuestionIndex</span> variable has been changed, the app uses it to select the "current" question.</p> <p>Recall that in the <span class="basicblock">Screen.Initialize</span> event-handler, the app selected the first question to display:</p> <p><img src="http://beta.appinventor.mit.edu/learn/tutorials/quizme/QuizMeAssets/selectFirst.png" /></p> <p>When the <span style="color:green;">NextButton</span> is clicked, the app doesn't choose the first item in the list, or the 2nd or 3rd, it chooses the <span class="listblock">currentQuestionIndex</span>-th item.</p> <p><img src="http://beta.appinventor.mit.edu/learn/tutorials/quizme/QuizMeAssets/chooseCurrent.png" /></p> <p>The blocks are executed in a right-to-left manner. The app first evaluates the index parameter of <span class="listblock">select list item</span>, which is the variable <span style="color:green;">currentQuestionIndex</span>. The number is stored in <span style="color:green;">currentQuestionIndex</span> is used as the index when the select list item is executed.</p> <p>When the <span style="color:green;">NextButton</span> is clicked for the first time, the increment blocks will set <span style="color:green;">currentQuestionIndex</span> from 1 to 2, so the app will select the second item from <span style="color:green;">QuestionList</span>, "who pitched the first perfect game of 2010?". The second time <span style="color:green;">NextButton</span> is clicked, <span style="color:green;">currentQuestionIndex</span> will be set from 2 to 3, and the app will select the 3rd question in the list, "who pitched the first perfect game of the modern era?"</p> <pre class="ai-testing"><strong style="color:black;">Test this behavior.</strong> Test the behavior of the <span style="color:black;">NextButton</span> to see if the app is working correctly thus far. To test, play the role of the user and click the <span style="color:black;">NextButton</span> on the phone. Does the phone display the second question, "Who pitched the first perfect game of 2010?" It should, and the third question should appear when you click the <span style="color:black;">NextButton</span> again. If this is working, pat yourself on the back quickly, and then go on. Try clicking the <span style="color:black;">NextButton</span> again (a third time). You should see an error: "Attempting to get item 4 of a list of length 3". The app has a bug-- do you know what the problem is?</pre><p>The problem with the app is that it always increments the <span style="color:green;">currentQuestionIndex</span> variable when the <span style="color:green;">NextButton</span> is clicked. When <span style="color:green;">currentQuestionIndex</span> is already 3 and the user clicks the <span style="color:green;">NextButton</span>, the app changes <span style="color:green;">currentQuestionIndex</span> from 3 to 4, then calls select list item to get the <span style="color:green;">currentQuestionIndex</span>-th , or in this case, the 4th item. Since there are only three items in the variable <span style="color:green;">QuestionList</span>, Android complains.</p> <p>What the app needs to do is ask a question-- check a condition-- when the <span style="color:green;">NextButton</span> is clicked, and execute different blocks dependending on the answer. One way to ask the question is to ask, "is the variable <span style="color:green;">currentQuestionIndex</span> already 3?" If the answer is yes, you should set <span style="color:green;">currentQuestionIndex</span> back to 0 so the user is taken back to the first question.</p> <p>You'll need the following blocks:</p> <table><tr style="background-color: #EFEFEF; font-weight: bold;"><td>Block Type</td> <td>Drawer</td> <td>Purpose</td> </tr><tr><td><span class="controlblock">if test then-do</span></td> <td>Control</td> <td>To ask if user is on last question</td> </tr><tr><td><span class="basicblock">=</span> block</td> <td>Math</td> <td>to test if <span class="listblock">currentQuestionIndex</span> is 3</td> </tr><tr><td><span class="setblock">global currentQuestionIndex</span></td> <td>My Definitions</td> <td>-</td> </tr><tr><td><span class="basicblock">number</span> 3</td> <td>Math</td> <td>3 is number of items in the list</td> </tr><tr><td><span class="setblock">set currentQuestionIndex to</span></td> <td>My Definitions</td> <td>set to 0 to go back to first question</td> </tr><tr><td><span class="basicblock">Number</span> 0</td> <td>Math</td> <td>set to 0 because next blocks will increment to 1</td> </tr></table><p>The modified <span class="basicblock">NextButton.Click</span> event-handler should look like this:</p> <p><img src="http://beta.appinventor.mit.edu/learn/tutorials/quizme/QuizMeAssets/nextif3.png" /></p> <h4 class="ai-header">How the blocks work</h4> <p>When the <span style="color:green;">NextButton</span> is clicked, the app first checks to see if <span style="color:green;">currentQuestionIndex</span> has a 3 in it. If it does, <span style="color:green;">currentQuestionIndex</span> is set back to 0 so that when 1 is added to it with the blocks below, it will be 1 and the quiz will loop back to display the first question. Note that only the blocks inset within the <span class="controlblock">if-test-then-do</span> block are dependent on the condition-- the increment and set <span class="setblock">QuestionLabel.Text to</span> blocks are executed under all conditions.</p> <pre class="ai-testing"><strong style="color:black;">Test this behavior.</strong> Because variables like <span style="color:black;">currentQuestionIndex</span> are hidden, they are often the source of bugs in a program. Fortunately, App Inventor provides a way to make such hidden variables transparent during testing. Specifically, App Inventor allows you to "watch" how the value of a variable change as an app progresses. For this test, right-click the <span style="color:black;">currentQuestionIndex</span> def block in the Blocks Editor and choose <span style="color:black;">Watch</span>. Then choose <span style="color:black;">Restart Phone App</span>. The def block will then appear with a watch box showing the initial value of <span style="color:black;">currentQuestionIndex</span> (which should be 1): <img src="http://beta.appinventor.mit.edu/learn/tutorials/quizme/QuizMeAssets/watchindex1.png" /> Now pick up the phone and click the <span style="color:black;">NextButton</span>. The second question, "who pitched the most recent perfect game in the major leagues?" should appear in the <span style="color:black;">QuestionLabel</span> on the phone, as before. On the App Inventor screen, 2 should appear in the <span style="color:black;">currentQuestionIndex</span> memory cell: <img src="http://beta.appinventor.mit.edu/learn/tutorials/quizme/QuizMeAssets/watchindex2.png" /> When you click again, the third question should appear on the phone and 3 should appear in the memory cell . If you click again, 1 should appear in <span style="color:black;">currentQuestionIndex</span> and the first question on the phone.</pre><h4 class="ai-header">A Maintainable App: Making it Easy to Modify the Questions</h4> <p>Next, you'll modify the app to make it easy to add and remove elements from the list. You'll rewrite the blocks so that they'll work on any list, not just one with exactly three items. To begin, add a fourth question to <span style="color:green;">QuestionList</span> and another answer into <span style="color:green;">AnswerList</span>. The blocks should look like this:</p> <p><img src="http://beta.appinventor.mit.edu/learn/tutorials/quizme/QuizMeAssets/listsWith4.png" /></p> <pre class="ai-testing"><strong style="color:black;">Test the modified app.</strong> Click the <span style="color:black;">NextButton</span> a number of times. You should see that the fourth question never appears, no matter how many times you click <span style="color:black;">Next</span>.</pre><p>The problem is that the test to see if the user is on the last question is too specific: it asks if the <span style="color:green;">currentQuestionIndex</span> variable is 3:</p> <p><img src="http://beta.appinventor.mit.edu/learn/tutorials/quizme/QuizMeAssets/if3.png" /></p> <p>You could just change the number 3 to a 4, and the app would again work correctly. The problem with this solution, however, is that each time you modify the questions and answers, you also have to remember to make this change. Such dependencies in a computer program often lead to bugs, especially as an app grows in complexity. It's much better to set the program up so that it will work no matter how many questions there are. Such generality is even more important when the list you are working with changes dynamically, e.g., a quiz app that allows the user to add new questions.</p> <p>The better solution is to ask the question in a more general way. You really want to know if the current question the user is on-- the value of <span style="color:green;">currentQuestionIndex</span> -- is as large as the number of items in <span style="color:green;">QuestionList</span>. If the app asks the question in this more general manner, it will work even when you add to or remove items from the <span style="color:green;">QuestionList</span>. To modify the <span class="basicblock">NextButton.Click</span> event-handler you'll replace the previous test that referred directly to 3. You'll need the following blocks:</p> <table><tr style="background-color: #EFEFEF; font-weight: bold;"><td>Block Type</td> <td>Drawer</td> <td>Purpose</td> </tr><tr><td><span class="listblock">length of list</span></td> <td>Lists</td> <td>asks how many items are in <span style="color:green;">QuestionList</span></td> </tr><tr><td><span class="argblock">global QuestionList</span></td> <td>My Definitions</td> <td>put into list slot of <span class="listblock">length of list</span></td> </tr></table><p>Your <span class="basicblock">NextButton.Click</span> event-handler should now appear as:</p> <p><img src="http://beta.appinventor.mit.edu/learn/tutorials/quizme/QuizMeAssets/nextWithLength.png" /></p> <h4 class="ai-header">How the Blocks Work</h4> <p>The <span class="controlblock">if</span> test now compares the <span style="color:green;">currentQuestionIndex</span> to the length of the <span style="color:green;">QuestionList</span>. So if <span style="color:green;">currentQuestionIndex</span> has a 4 in it, and the length of the <span style="color:green;">QuestionList</span> is 4, then the <span style="color:green;">currentQuestionIndex</span> will be set to 0 (and then 1 after the increment operation in the first row of blocks after the if). Note that, because the blocks no longer refer to 3 or any specific size, the behavior will work no matter how many items are in the list.</p> <pre class="ai-testing"><strong style="color:black;">Test the modified behavior.</strong> When you click the <span style="color:black;">NextButton</span>, does the app now sequence through the four questions, moving to the first one after the fourth?</pre><h4 class="ai-header">Switching the Image for Each Question</h4> <p>The current app shows the same image, no matter what question is being asked. You can change this so an image pertaining to each question appears when the <span style="color:green;">NextButton</span> is clicked. Earlier, you added four pictures as media for the project. Now, you'll create a third list, <span style="color:green;">PictureList</span>, with the names of the image files as its items. and you'll modify the <span class="basicblock">NextButton.Click</span> event-handler to switch the picture each time.</p> <p>First, create a <span style="color:green;">PictureList</span> and initialize it with the names of the image files. Be sure that the names are exactly the same as the names of the files that were loaded in to the media of the project. Here's how the blocks for the <span style="color:green;">PictureList</span> should look:</p> <p><img src="http://beta.appinventor.mit.edu/learn/tutorials/quizme/QuizMeAssets/pictureList.png" /></p> <p>Next, you need to modify the <span class="basicblock">NextButton.Click</span> event-handler so that it modifies the picture depending on what question the user is on. If you set the <strong style="color:green;">Image.Picture</strong> property to a file name of an image that has been loaded, that image will appear. To modify <span class="basicblock">NextButton.Click</span>, you'll need the following blocks:</p> <table><tr style="background-color: #EFEFEF; font-weight: bold;"><td>Block Type</td> <td>Drawer</td> <td>Purpose</td> </tr><tr><td><span class="setblock">set Image1.Picture to </span></td> <td>Image1</td> <td>set this to change the picture</td> </tr><tr><td><span class="listblock">select list item</span></td> <td>Lists</td> <td>need to select the picture corresponding to current question</td> </tr><tr><td><span class="argblock">global PictureList</span></td> <td>My Definitions</td> <td>select a file name from this list</td> </tr><tr><td><span class="argblock">global currentQuestionIndex</span></td> <td>My Definitions</td> <td>select the <span style="color:green;">currentQuestionIndex</span>-th item</td> </tr></table><p>Here is how the blocks should look:</p> <p><img src="http://beta.appinventor.mit.edu/learn/tutorials/quizme/QuizMeAssets/nextWithImageSwitch.png" /></p> <h4 class="ai-header">How the Blocks Work</h4> <p>The <span style="color:green;">currentQuestionIndex</span> serves as the index for the <span style="color:green;">QuestionList</span> and the <span style="color:green;&gt;PictureList&lt;/span&gt;. When &lt;span style=" color:green="">currentQuestionIndex</span> is 1, the app selects the first question and the first picture. When <span style="color:green;">currentQuestionIndex</span> is 2, the app selects the second question and second picture. Of course this scheme depends on the lists being in sync and indeed they are. For instance, the first picture, LarsenBerra.jpg, is a picture of Don Larsen, and Don Larsen is the answer to the first question, "Who pitched a perfect game in the World Series?" Test the modified behavior. Does a different image appear each time you click the <span style="color:green;">NextButton</span>?</p> <h4 class="ai-header">Evaluating Answers</h4> <p>Next, you'll add blocks that report whether the user has answered a question correctly or not. The user enters the answer in <span style="color:green;">AnswerText</span> and then clicks the <span style="color:green;">AnswerButton</span>. The app must compare the user's entry with the answer to the "current" question, using an <span class="controlblock">ifelse</span> block to check. The <span style="color:green;">RightWrongLabel</span> should be modified to report whether or not the answer is correct. You'll need the following blocks for this behavior:</p> <table><tr style="background-color: #EFEFEF; font-weight: bold;"><td>Block Type</td> <td>Drawer</td> <td>Purpose</td> </tr><tr><td><span class="basicblock">AnswerButton.Click</span></td> <td>AnswerButton</td> <td>the behavior is triggered when user clicks the <span style="color:green;">AnswerButton</span></td> </tr><tr><td><span class="controlblock">ifelse</span></td> <td>Control</td> <td>if answer is correct, do one thing, else do another</td> </tr><tr><td><span class="basicblock">=</span> block</td> <td>Math</td> <td>to ask if answer is correct</td> </tr><tr><td><span class="argblock">AnswerText.Text</span></td> <td>AnswerText</td> <td>the user's answer is in this textbox</td> </tr><tr><td><span class="listblock">select list item</span></td> <td>Lists</td> <td>to select the current answer from <span style="color:green;">AnswerList</span></td> </tr><tr><td><span class="argblock">global AnswerList</span></td> <td>My Definitions</td> <td>The list to select from</td> </tr><tr><td><span class="argblock">global currentQuestionIndex</span></td> <td>My Definitions</td> <td>the question number (and answer number) the user is on</td> </tr><tr><td><span class="setblock">set RightWrongLabel.Text to</span></td> <td>RightWrongLabel</td> <td>report the answer here</td> </tr><tr><td><span class="textblock">text block</span> "correct"</td> <td>Text</td> <td>if answer is right</td> </tr><tr><td><span class="setblock">set RightWrongLabel.Text to</span></td> <td>RightWrongLabel</td> <td>report the answer here</td> </tr><tr><td><span class="textblock">text block</span> "incorrect"</td> <td>Text</td> <td>if answer is wrong</td> </tr></table><p>The blocks should look like this:</p> <p><img src="http://beta.appinventor.mit.edu/learn/tutorials/quizme/QuizMeAssets/answerButton.png" /></p> <h4 class="ai-header">How the Blocks Work</h4> <p>The <span class="controlblock">ifelse</span> test reads, "is the user's answer (<strong style="color:green;">AnswerText.Text</strong>) equal to the <span style="color:green;">currentQuestionIndex</span>-th item in the <span style="color:green;">AnswerList</span>?" If <span style="color:green;">currentQuestionIndex</span> is 1, the app will compare the user's answer with the first item in <span style="color:green;">AnswerList</span>, "Don Larsen". If <span style="color:green;">currentQuestionIndex</span> is 2, the app will compare the user's answer with the second answer in the list, "Dallas Braden", and so on. If the test result is positive, the <span class="controlblock">then-do</span> blocks are executed and the <span style="color:green;">RightWrongLabel</span> is set to "correct!". If the test is false, the <span class="controlblock">else-do</span> blocks are executed and the <span style="color:green;">RightWrongLabel</span> is set to "incorrect".</p> <pre class="ai-testing"><strong style="color:black;">Test the modified app.</strong> Try answering one of the questions. It should report whether or not you answered the question exactly as is specified in the <span style="color:black;">AnswerList</span>. Test with both a correct and incorrect answer (because text is being compared, the test is case-sensitive). Click the <span style="color:black;">NextButton</span> and answer a second question. Does it still work? It should, but you might notice that when you click the <span style="color:black;">NextButton</span>, the "correct"/"incorrect" text and the previous answer are still there. Though it's fairly innocuous, such user interface issues will definitely be noticed by the users of your app.</pre><p>To blank out the <span style="color:green;">RightWrongLabel</span> and the <span style="color:green;">AnswerText</span>, you'll put the following blocks within the <span class="basicblock">NextButton.click</span> event-handler:</p> <table><tr style="background-color: #EFEFEF; font-weight: bold;"><td>Block Type</td> <td>Drawer</td> <td>Purpose</td> </tr><tr><td><span class="setblock">set RightWrongLabel.Text to</span></td> <td>RightWrongLabel</td> <td>the label to blank out</td> </tr><tr><td><span class="textblock">text</span> (blank)</td> <td>Text</td> <td>When <span style="color:green;">Next</span> is clicked, erase old answer critique</td> </tr><tr><td><span class="setblock">set AnswerText.Text to</span></td> <td>AnswerText</td> <td>the user's answer from previous question</td> </tr><tr><td><span class="textblock">text</span> (blank)</td> <td>Text</td> <td>When <span style="color:green;">Next</span> is clicked, erase old answer</td> </tr></table><p>The blocks should look like this:</p> <p><img src="http://beta.appinventor.mit.edu/learn/tutorials/quizme/QuizMeAssets/nextButtonFinal.png" /></p> <h4 class="ai-header">How the Blocks Work</h4> <p>When the <span style="color:green;">NextButton</span> is clicked, the user is moving on to the next question, so the top two rows of the event-handler blank out the <span style="color:green;">RightWrongLabel</span> and the <span style="color:green;">AnswerText</span>.</p> <pre class="ai-testing"><strong style="color:black;">Test this behavior.</strong> Answer a question and click <span style="color;black;">Submit</span>, then click the <span style="color:black;">NextButton</span>. Does your previous answer and the apps critique disappear?</pre><h4 class="ai-header">Final Program</h4> <p><strong><span style="color:green;">QuizMe</span>! Final Version:</strong></p> <p><img src="http://beta.appinventor.mit.edu/learn/tutorials/quizme/QuizMeAssets/quizmeFinal.png" /></p> <p>Package the final version of the app by choosing <strong>Package For Phone | Barcode</strong> from the Component Designer menu. When the barcode appears, use the barcode scanner on your phone to download and install the app.</p> <h4 class="ai-header">Variations</h4> <p>Once you get a quiz working, you might want to explore some variations. For example,</p> <ul><li>Instead of just showing images for each question, try playing a sound clip or a short video. With sound, you can turn your quiz app into a <span style="color:green;">Name That Tune</span> app.</li> <li>The quiz is very rigid in terms of what is accepted as a valid answer. There are a number of ways to modify this. One is to use the text.contains block to see if the user's answer is contained in the actual answer. Another is to provide multiple answers for each question, and check by iterating (using <span class="controlblock">foreach</span>) through them to see if any match.</li> <li>Transform the quiz so that it is multiple-choice. The list of answers will need to be a list of lists, with each sub-list holding the answer choices. Use the <strong>ListPicker</strong> component to allow the user to choose an answer.</li> </ul><h4 class="ai-header">Review</h4> <p>Here are some of the ideas covered in this tutorial:</p> <ul><li>Apps can be written in a general manner so that they work with any data list.</li> <li>Index variables are used to track the current position within a list. When you increment them, be careful about reaching the end of the list.</li> </ul><h4 class="ai-header">Scan the Sample App to your Phone</h4> <p>Scan the following barcode onto your phone to install and run the sample app. </p><p><img src="/sites/all/files/tutorials/quizMe/QuizMeBarcode.png" /></p> <h4 class="ai-header">Download Source Code</h4> <p>If you'd like to work with this sample in App Inventor, download the <a href="/sites/all/files/tutorials/quizMe/QuizMe.zip">source code</a> to your computer, then open App Inventor, go to the My Projects page, and choose <b>More Actions | Upload Source</b>.</p> <p>Or <a href="http://explore.appinventor.mit.edu/sites/all/files/tutorials/quizMe/QuizMe.apk">download the apk</a></p> <p>.</p> <pre class="ai-box">MIT and Google are grateful to <a href="http://www.appinventor.org/">Professor David Wolber</a>, CS Professor at The University of San Francisco, for developing this tutorial. Done with <span style="color:black;">QuizMe</span>? Return to the other tutorials <a href="http://explore.appinventor.mit.edu/content/tutorials">here</a>.</pre></div></div></div><section class="field field-name-field-version field-type-taxonomy-term-reference field-label-above view-mode-rss clearfix"> <h2 class="field-label">Tutorial Version:&nbsp;</h2> <ul class="field-items"> <li class="field-item even"> <a href="/tutorial-version/app-inventor-1" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">App Inventor 1</a> </li> </ul> </section> <section class="field field-name-field-tutorial-difficulty field-type-taxonomy-term-reference field-label-above view-mode-rss clearfix"> <h2 class="field-label">Tutorial Difficulty:&nbsp;</h2> <ul class="field-items"> <li class="field-item even"> <a href="/tutorial-difficulty/advanced" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">Advanced</a> </li> </ul> </section> <section class="field field-name-field-tutorial-type field-type-taxonomy-term-reference field-label-above view-mode-rss clearfix"> <h2 class="field-label">Tutorial Type:&nbsp;</h2> <ul class="field-items"> <li class="field-item even"> <a href="/tutorial-type/data-storage" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">Data Storage</a> </li> <li class="field-item odd"> <a href="/tutorial-type/game" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">Game</a> </li> </ul> </section> Fri, 14 Jun 2013 16:10:24 +0000 aaron 312 at http://dev-explore.appinventor.mit.edu http://dev-explore.appinventor.mit.edu/content/quizme#comments Mini Golf: Fling, TouchUp, TouchDown Gestures http://dev-explore.appinventor.mit.edu/content/minigolf <div class="field field-name-body field-type-text-with-summary field-label-hidden view-mode-rss"><div class="field-items"><div class="field-item even" property="content:encoded"><p>This Mini Golf App demonstrates how to use the Fling, TouchUp, and TouchDown gestures for Sprites<br />Note that these event handlers are also available for the Canvas.</p> <p><img src="/sites/all/files/tutorials/miniGolf/GolfSampleScreen.png" style="float: right;border:none" width="250" /></p> <p>To play this mini golf app, the player first positions his/her ball within the confines of the tee, and then flings the ball toward the hole. The ball will bounce off of the rectangular obstacle and the sides of the course. For each fling of the ball, the stroke count goes up by one. The total score is the number of strokes it takes to complete the entire course. </p> <p>This tutorial covers:</p> <ul><li>Using the <b>Sprite</b> component and the TouchUp, TouchDown, and Flung events</li> <li>Using a <b>Clock</b> component</li> <li>Dynamic Positioning of sprites on a canvas, based on the size of the screen</li> <li>Sprite Collisions</li> </ul><p>This tutorial assumes you are familiar with the basics of App Inventor-- using the Component Designer to build a user interface, and using the Blocks Editor to specify the app's behavior. If you are not familiar with the basics, try stepping through some of the <a href="http://appinventor.mit.edu/explore/tutorials.html">basic tutorials</a> before continuing.</p> <p><a href="/sites/all/files/tutorials/miniGolf/FlingitMiniGolfTutorial.zip"><img src="/sites/all/files/tutorials/miniGolf/downloadSourcebutton.png" style="float: right; border:none" width="250" /></a><br /><br /><br /><br /></p> <hr /><h3>Part I: Start a new app and make a ball that responds to fling events</h3> <p>We'll build this app in stages, adding a little bit of the game at a time. Log into App Inventor and start a new project. Name it "MiniGolf". When the Design window opens notice that App Inventor automatically names the screen "Screen1", but you can set the Title of the screen, which will show up in the top bar of the app. Think of a title related to Mini Golf, or feel free to use the suggested title "Flingit Mini Golf", and type it into the Properties pane on the right side of the Designer.</p> <p>In the Screen Properties (shown in right-hand pane): Uncheck the checkbox labeled "Scrollable" so that the screen will not scroll when the app is running. Screens that are set to scroll do not have a height. We’ll need our screen to have a defined height in order to set up the golf course properly.</p> <p><strong>Add the following components in the Designer:</strong></p> <table cellpadding="0" cellspacing="0"><tbody><tr style="background-color: #EFEFEF; font-weight: bold;"><td> <p><strong>Component Type</strong></p> </td> <td> <p><strong>Palette Group</strong></p> </td> <td> <p><strong>What You'll Name It</strong></p> </td> <td> <p><strong>Purpose</strong></p> </td> <td> <p><strong>Properties</strong></p> </td> </tr><tr><td> <p>Canvas1</p> </td> <td> <p>Basic</p> </td> <td> <p>Canvas1</p> </td> <td> <p>The canvas serves as the golf course</p> </td> <td> <p>Height: 300<br />Width: FillParent<br />BackgroundColor: Green (or whatever you like!)</p> </td> </tr><tr><td> <p>BallSprite</p> </td> <td> <p>Animation</p> </td> <td> <p>GolfBall</p> </td> <td> <p>This is the ball the player will fling to try to hit the Hole</p> </td> <td> <p>Radius = 10<br />Color: White (or your choice!)<br />Speed: 0<br />Interval: 1 (ms)</p> <p>Z = 2 (this makes the sprite appear on top of sprites with lower numbers)</p> </td> </tr><tr><td> <p>BallSprite</p> </td> <td> <p>Animation</p> </td> <td> <p>Hole</p> </td> <td> <p>This will be the target for the GolfBall</p> </td> <td> <p>Radius = 15<br />Color: Black<br />Speed: 0</p> </td> </tr><tr><td> <p>Clock1</p> </td> <td> <p>Basic</p> </td> <td> <p>Clock1</p> </td> <td> <p>The clock will fire continuously to control the movement of the ball</p> </td> <td> <p>Timer Always Fires</p> <p>Timer Enabled</p> <p>TimerInterval: 100</p> </td> </tr></tbody></table><p><strong>Open the Blocks Editor</strong></p> <p><strong>Program the behavior of the Ball:</strong></p> <p>First, use the <span class="basicblock">GolfBall.Flung</span> event handler to move the golf ball when it is flung. Essentially, set the GolfBall sprite’s speed and heading to match the speed and heading of the player’s fling gesture. You may want to scale up the speed a little bit because the speed of the fling is a little slower than how a golf ball would move. You can play with this "scaling factor" to make the ball more or less responsive to a fling.</p> <p> <img height="312" src="/sites/all/files/tutorials/miniGolf/golfBall.flung.png" width="564" /></p> <p><strong>Program the behavior of the clock:</strong></p> <p> Use timer event to slow ball down so it doesn’t bounce around forever.</p> <p>Each time the clock fires, it will reduce the speed of the ball slightly. Notice that if the ball is not moving then these blocks will do nothing. If you don’t have this then the ball will just bounce forever.</p> <p><img height="257" src="/sites/all/files/tutorials/miniGolf/clock1.timer.png" width="554" /></p> <p><strong>Program a new procedure called SetupNewHole:</strong></p> <p>This procedure will be called when a hole is scored and the ball has to be placed back at the starting point. Note that the <span class="callblock">Hole.MoveTo</span> block sets the hole up in a new random location for the next play.</p> <p><img height="301" src="/sites/all/files/tutorials/miniGolf/setupNewHole.png" width="671" /></p> <p><strong>Program the Behavior of the Hole: </strong><span>When the ball collides with the hole, the ball disappears and resets at the bottom of the screen.</span></p> <p>Note: When you first drag out the <span class="basicblock">GolfBall.CollidedWith</span> event handler, the named parameter is called "other". You can rename this by clicking once on the word "other" and typing in something new. Use a name that makes sense, as in this example where we use "ObjectHitByGolfBall". Notice that the <span class="controlblock">if then</span> block tests to see if the object involved in the collision with the golf ball (<span class="argblock">ObjectHitByGolfBall</span>) is the black ball sprite representing the hole. You can't just put a text block with the word "Hole" in it, you must use the <span class="argblock">component Hole</span><span> block, that can be found in the Hole drawer under "My Blocks". Do not use a text block here.</span></p> <p><img height="196" src="/sites/all/files/tutorials/miniGolf/golfBall.collidedWith.png" width="502" /></p> <pre class="ai-testing"><strong>Test this Behavior.</strong> Connect your device to AppInventor, or start the emulator to load your app. When you fling the ball it should move in the direction of your fling, with a speed similar to the strength of your fling. The ball should slow down as it moves, eventually stopping. When the ball hits the hole, the ball should reset at the bottom of the screen and the hole should move to a new random location.</pre><p> </p> <p><strong>Does your ball get stuck if it hits the edge? </strong></p> <p>This is easy to fix with the when <span class="basicblock">EdgeReached</span> event. Note that you can find the "edge" value block under My Definitions. You can also use a developer’s shortcut by clicking anywhere on the workspace background and typing the word "edge". You’ll see a dropdown box appear. If you click the word "edge" you’ll see the value edge block appear on the screen. Big time saver!</p> <p><img height="101" src="/sites/all/files/tutorials/miniGolf/golfBall.edgeReached.png" width="334" /></p> <p>Double check to make sure your code is right: fling the ball a few times and see that that ball now bounces off the edges of the course.</p> <h3>Part II: Keeping Score</h3> <p>Games are more fun if you have a way to see how you’re doing. Let’s add a stroke counter. In mini golf your score goes up as you take more strokes. The goal is to have the lowest score possible. Let’s show the player how many strokes she or he has taken on this hole. Let’s also show the number of strokes taken during the whole game.</p> <p> </p> <p>Go back to the Designer and set up the following components:</p> <p><a href="#" name="84f417a34cd2d904669a10a8f96b32bf41ae274b" id="84f417a34cd2d904669a10a8f96b32bf41ae274b"></a><a href="#" name="2" id="2"></a><br /></p><table cellpadding="0" cellspacing="0"><tbody><tr style="background-color: #EFEFEF; font-weight: bold;"><td> <p><strong>Component Type</strong></p> </td> <td> <p><strong>Palette Group</strong></p> </td> <td> <p><strong>What You’ll Name It</strong></p> </td> <td> <p><strong>Purpose</strong></p> </td> <td> <p><strong>Properties</strong></p> </td> </tr><tr><td> <p>Horizontal Arrangement</p> </td> <td> <p>Screen Arrangement</p> </td> <td> <p>HorizontalArrangement1</p> </td> <td> <p>Contains LabelScore and LabelStroke</p> </td> <td> <p>Place at top of screen</p> </td> </tr><tr><td> <p>Label1</p> </td> <td> <p>Basic</p> </td> <td> <p>LabelScore</p> </td> <td> <p>Displays the total stroke count for the entire game</p> </td> <td></td> </tr><tr><td> <p>Label2</p> </td> <td> <p>Basic</p> </td> <td> <p>LabelStroke</p> </td> <td> <p>Displays the stroke count for the hole the player is currently on</p> </td> <td></td> </tr></tbody></table><p>In the Blocks Editor, you can program updates to the Score and Stroke labels. First, set two new global variables called <span class="setblock">StrokeCount</span> and <span class="setblock">Score</span>, and set their initial values to 0.</p> <p><img height="101" src="/sites/all/files/tutorials/miniGolf/strokeCount.png" width="265" /></p> <p>Then add the following blocks to the <span class="basicblock">GoflBall.Flung</span> event (red rectangle indicates new blocks):</p> <p><img height="500" src="/sites/all/files/tutorials/miniGolf/golfBall.flung_final.png" width="592" /></p> <p>Next add the following blocks to the Event that handles the ball hitting the hole:</p> <p><img height="462" src="/sites/all/files/tutorials/miniGolf/golf_collidewith.png" width="607" /></p> <pre class="ai-testing"><strong>Test the behavior.</strong> With these new changes, you should have a "Total Strokes" count and "This Hole" count at the top of the screen. When you fling the ball, the "This Hole" count  and "Total Strokes" count should both increase by one, and when you make the ball go into the hole the "This Hole" count should reset to 0.</pre><h3>Part III: Positioning Ball on Tee using TouchUp and TouchDown events</h3> <p>Ok, so now you’ve got a working game! Now let’s make it a little more interesting and fun. First we’ll add a Tee and let the player position the golf ball on the tee before they fling the ball.</p> <p><strong>Go back to the Designer and add three new image sprite components:</strong></p> <p><a href="#" name="f32e9ebd8bb0c367ac6b009ebba0af05e4eb1b4e" id="f32e9ebd8bb0c367ac6b009ebba0af05e4eb1b4e"></a><a href="#" name="1" id="1"></a><br /></p><table cellpadding="0" cellspacing="0"><tbody><tr style="background-color: #EFEFEF; font-weight: bold;"><td> <p><strong>Component Type</strong></p> </td> <td> <p><strong>Palette Group</strong></p> </td> <td> <p><strong>What You’ll Name It</strong></p> </td> <td> <p><strong>Purpose</strong></p> </td> <td> <p><strong>Properties</strong></p> </td> </tr><tr><td> <p>ImageSprite</p> </td> <td> <p>Animation</p> </td> <td> <p>Tee</p> </td> <td> <p>A rectangular area in which the player can position their ball before teeing off.</p> </td> <td> <p>Upload the Tee image (<a href="/sites/all/files/tutorials/miniGolf/tee_graphic.png">right click on this link</a>, or see below).</p> </td> </tr><tr><td> <p>ImageSprite</p> </td> <td> <p>Animation</p> </td> <td> <p>LeftSprite</p> </td> <td> <p>This is a left pointing arrow that the player will use to move the ball to the left on the tee</p> </td> <td> <p>Upload the left arrow graphic (<a href="/sites/all/files/tutorials/miniGolf/left_arrow.jpg">right click on this link</a></p> </td> </tr><tr><td> <p>ImageSprite</p> </td> <td> <p>Animation</p> </td> <td> <p>RightSprite</p> </td> <td> <p>This is a right pointing arrow that the player will use to move the ball to the left on the tee</p> </td> <td> <p>Upload the right arrow graphic (<a href="/sites/all/files/tutorials/miniGolf/right_arrow.jpg">right click on this link</a></p> </td> </tr></tbody></table><p><strong>Program the size of the canvas, and the placement of the ball and image sprites on the canvas:</strong></p> <p>First, program the setup of these components on the screen. It’s best to accommodate all different screen sizes by placing the sprites on the screen relative to the size of the screen. The blocks below show how to set up the screen <em>dynamically</em><span> so that everything fits the right way. We start off by making the canvas size based on the screen size, and then we place each sprite in relation to the width and height of the canvas. Try to understand all of these blocks before you move on.</span></p> <p><img src="/sites/all/files/tutorials/miniGolf/golf_screen_init.png" /></p> <p><strong>Position the Golf Ball on the Tee using TouchUp and TouchDown on the Arrow sprites:</strong></p> <p>To handle this, first set up two global variables that are toggled each time an arrow is pressed.</p> <p><img height="96" src="/sites/all/files/tutorials/miniGolf/globalMoveRight.png" width="249" /></p> <p><strong>Program the behavior of the Right and Left Arrows</strong></p> <p>The left and right arrows are image sprites, so they come equipped with the ability to know when the player is is holding his/her finger down on them. The following blocks toggle the global variables based on whether the user is pressing either of these arrows.</p> <p><img height="383" src="/sites/all/files/tutorials/miniGolf/leftSprite.touchDown.png" width="599" /></p> <p><strong>Procedure MoveBallOnTee:</strong></p> <p>Make a new procedure <span class="callblock">MoveBallOnTee</span> that makes the golf ball move left or right on the tee depending on the global variables. Although the math here looks complicated, it’s pretty simple. If the ball is supposed to move left, you first check to make sure that moving the ball 2 pixels left will not exceed the left-most coordinate of the Tee. If moving the golf ball to the right, you first check that moving the ball right 2 pixels will not move it past the right-most coordinate of the Tee.</p> <p><img height="368" src="/sites/all/files/tutorials/miniGolf/moveBallOnTee.png" width="701" /></p> <p>On each new course, players can position the ball on the tee before attempting to fling the ball toward the hole. To program this, you first have to check to make sure this is a new course and the ball has not been flung yet. If <span class="argblock">StrokeCount</span> = 0 then we know this course is brand new and the player has not yet attempted to get the ball into the hole.</p> <p><img height="188" src="/sites/all/files/tutorials/miniGolf/clock1.timer_final.png" width="448" /></p> <p>As the blocks above show, after verifying that the StrokeCount is 0, you then want to proceed to move the golf ball left or right depending on which arrow is being pressed. </p> <p>Note that the blocks that we had inside the <span class="basicblock">Clock1.Timer</span> event are now moved over to a new procedure called <span class="callblock">MoveBallOnCourse:</span></p> <p><strong>MoveBallOnCourse Procedure</strong></p> <p><img height="214" src="/sites/all/files/tutorials/miniGolf/moveBallOnCourse.png" width="512" /></p> <pre class="ai-testing"><strong>Test the behavior.</strong> Make sure your app is doing what you expect: play the game on your device or emulator. Before you tee off, are you able to move the ball left and right on the tee by using the left and right arrows? After you tee off, you should no longer be able to use the left and right arrows (pressing them will do nothing). After the ball goes into the hole and the screen resets, you should then be able to move the ball left and right on the tee before teeing off again.</pre><p><strong>Keep track of the number of holes played, and allow a game reset</strong></p> <p>The game is working pretty well now, but what about giving the player a way to reset the game? Also, it would be nice to give the player some instructions so they know how to play the game. While we’re at it, let’s also give an indication of how many holes the player has completed. Add the following components in the Designer:</p> <p><a href="#" name="0899df2ccc45cb7f22bfe41d004593ed854f9f2c" id="0899df2ccc45cb7f22bfe41d004593ed854f9f2c"></a><a href="#" name="3" id="3"></a><br /></p><table cellpadding="0" cellspacing="0"><tbody><tr style="background-color: #EFEFEF; font-weight: bold;"><td> <p><strong>Component Type</strong></p> </td> <td> <p><strong>Palette Group</strong></p> </td> <td> <p><strong>What You’ll Name It</strong></p> </td> <td> <p><strong>Purpose</strong></p> </td> <td> <p><strong>Properties</strong></p> </td> </tr><tr><td> <p>Horizontal Arrangement2</p> </td> <td> <p>Screen Arrangement</p> </td> <td> <p>Horizontal Arrangement2</p> </td> <td> <p>Contains the NewGame button and the HoleNum label</p> </td> <td></td> </tr><tr><td> <p>Button</p> </td> <td> <p>Basic</p> </td> <td> <p>ButtonNewGame</p> </td> <td> <p>Resets the game to Hole #1 with a score of 0.</p> </td> <td> <p>Text: "New Game"</p> </td> </tr><tr><td> <p>Label3</p> </td> <td> <p>Basic</p> </td> <td> <p>LabelHoleNum</p> </td> <td> <p>Displays the current hole number, increments by one each time a hole is completed.</p> </td> <td> <p>Text = "Hole # 1"<br />Font: bold, 28, blue<br /></p> </td> </tr><tr><td> <p>Label4</p> </td> <td> <p>Basic</p> </td> <td> <p>LabelInstruct</p> </td> <td> <p>Displays instructions</p> </td> <td> <p>Text = "Use arrows to position ball on tee. Hit the ball by flinging it with your finger."</p> </td> </tr></tbody></table><p>Define a new global variable to keep track of the Hole Number:</p> <p><img height="44" src="/sites/all/files/tutorials/miniGolf/holeCount.png" width="234" /></p> <p>Add the following blocks to the <span class="callblock">SetupNewHole</span> procedure: set <span class="setblock">global HoleCount</span> and set <span class="setblock">LabelHoleNum.Text</span>...</p> <p><img height="291" src="/sites/all/files/tutorials/miniGolf/setupNewHole_add.png" width="557" /></p> <p>Program the "New Game" button’s behavior, which is pretty simple. When the button is pressed, set up a new course and reset both the hole stroke counter and total stroke counter to zero. Also set the hole number back to 1, by displaying "Hole #1" in LabelHoleNum. The blocks look like this:</p> <p><img height="412" src="/sites/all/files/tutorials/miniGolf/buttonNewGame.click.png" width="450" /></p> <pre class="ai-testing"><strong>Test the behavior.</strong><p> Go back to your device or emulator and play the game some more. Now you should see the Hole # displayed in the lower right. Hitting "New Game" button should reset the game, returning both scores to 0, resetting the screen, and setting the Hole number to #1.</p></pre><h3>Part IV: Introduce an Obstacle</h3> <p>Most mini golf courses have obstacles on them. Let’s add a simple rectangular obstacle that will randomly position itself on the course somewhere between the Tee and the Hole. Each time a new course is presented, the obstacle will move, just the same way the Hole moves each time a new course is set up.</p> <p><strong>Add the following component in the Designer:</strong></p> <p><a href="#" name="981d9864ae92d2e44bbc01311278b4463bf01a1e" id="981d9864ae92d2e44bbc01311278b4463bf01a1e"></a><a href="#" name="4" id="4"></a></p> <table cellpadding="0" cellspacing="0"><tbody><tr style="background-color: #EFEFEF; font-weight: bold;"><td> <p><strong>Component Type</strong></p> </td> <td> <p><strong>Palette Group</strong></p> </td> <td> <p><strong>What You’ll Name It</strong></p> </td> <td> <p><strong>Purpose</strong></p> </td> <td> <p><strong>Properties</strong></p> </td> </tr><tr><td> <p>ImageSprite</p> </td> <td> <p>Animation</p> </td> <td> <p>ObstacleSprite1</p> </td> <td> <p>This sprite will be somewhere between the golf ball and hole and will make it harder to get the ball into the hole</p> </td> <td> <p>Upload the obstacle (rectangle) graphic (<a href="/sites/all/files/tutorials/miniGolf/golf_obstacle1.png">right click on this link</a>, or see below).</p> </td> </tr></tbody></table><p>Program the behavior of the obstacle in the blocks editor. First, set the behavior for when the ball hits the obstacle.  *Note: Using Heading = 0 - heading works because we are dealing with bouncing off of horizonal surfaces, this will not work for bouncing off of vertical or inclined surfaces. For our purposes, it works all right. See Challenge #2 below for more information.</p> <p><img height="181" src="/sites/all/files/tutorials/miniGolf/obstacleSprite1.png" width="604" /></p> <p>Each time the course is reset, position the obstacle will be positioned randomly. Add these blocks to the <span class="callblock">SetupNewHole</span> procedure:</p> <p><img height="277" src="/sites/all/files/tutorials/miniGolf/setupNewHole_final.png" width="706" /></p> <pre class="ai-testing"><strong>Test the behavior.</strong> Play the game again. Notice that the ball bounces off when it hits the obstacle. When the ball goes into the hole, or when the New Game button is pressed, the obstacle appears in a new location somewhere between the tee and the hole.</pre><p>That’s it! Share your game with friends by building an APK or by downloading the source and sharing the zip file with other App Inventors!<br /></p> <h3>Part V: Challenges</h3> <p>Here are some extra challenges to make your game better.</p> <p><strong>Challenge 1:</strong> Program the Ball to Hole collision so that the ball only goes into the hole if the golf ball’s speed is not too fast. In real mini golf, the ball will bounce right over the hole if you hit the ball too hard.</p> <p><strong>Challenge 2:</strong> There is a slight bug when the ball hits the vertical sides of obstacle. Figure out how to program the ball to obstacle collision so that it bounces the way you would expect when the ball hits the vertical sides.</p> <p><strong>Challenge 3:</strong> Limit the number of holes per game. Keep track of the number of holes and end the game after a set number. (A typical mini golf course has 18 holes.)</p> <p>Below is a summary of all of the components, and a screen shot of all the blocks (some are collapsed to save space.)</p> <p><img height="455" src="/sites/all/files/tutorials/miniGolf/components.png" width="231" /></p> <p><img height="642" src="/sites/all/files/tutorials/miniGolf/finalCode.png" width="710" /></p> <p>Scan the following barcode onto your phone to install and run the sample app. </p><p><img src="http://explore.appinventor.mit.edu/sites/all/files/tutorials/miniGolf/MiniGolfBarcode.png" /></p> <h4 class="ai-header">Download Source Code</h4> <p>If you'd like to work with this sample in App Inventor, download the <a href="http://explore.appinventor.mit.edu/sites/all/files/tutorials/miniGolf/FlingitMiniGolfTutorial.zip">source code</a> to your computer, then open App Inventor, go to the My Projects page, and choose <b>More Actions | Upload Source</b>.</p> <pre class="ai-box"><span style="color:black;">Done with Mini Golf?</span> <a href="/tutorials">Return to the other tutorials</a>.</pre></div></div></div><section class="field field-name-field-version field-type-taxonomy-term-reference field-label-above view-mode-rss clearfix"> <h2 class="field-label">Tutorial Version:&nbsp;</h2> <ul class="field-items"> <li class="field-item even"> <a href="/tutorial-version/app-inventor-1" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">App Inventor 1</a> </li> </ul> </section> <section class="field field-name-field-tutorial-difficulty field-type-taxonomy-term-reference field-label-above view-mode-rss clearfix"> <h2 class="field-label">Tutorial Difficulty:&nbsp;</h2> <ul class="field-items"> <li class="field-item even"> <a href="/tutorial-difficulty/advanced" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">Advanced</a> </li> </ul> </section> <section class="field field-name-field-tutorial-type field-type-taxonomy-term-reference field-label-above view-mode-rss clearfix"> <h2 class="field-label">Tutorial Type:&nbsp;</h2> <ul class="field-items"> <li class="field-item even"> <a href="/tutorial-type/clock-timer" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">Clock Timer</a> </li> <li class="field-item odd"> <a href="/tutorial-type/game" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">Game</a> </li> <li class="field-item even"> <a href="/tutorial-type/sprites" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">Sprites</a> </li> </ul> </section> Fri, 14 Jun 2013 15:45:30 +0000 aaron 308 at http://dev-explore.appinventor.mit.edu http://dev-explore.appinventor.mit.edu/content/minigolf#comments MoleMash http://dev-explore.appinventor.mit.edu/content/molemash <div class="field field-name-body field-type-text-with-summary field-label-hidden view-mode-rss"><div class="field-items"><div class="field-item even" property="content:encoded"><p><img style="float:right;" src="/sites/all/files/tutorials/moleMash/MoleOnEmulator.png" /></p> <p>In the game <span style="color:green;">MoleMash</span>, a mole pops up at random positions on a playing field, and the player scores points by hitting the mole before it jumps away. This tutorial shows how to build <span style="color:green;">MoleMash</span> as an example of a simple game that uses animation.</p> <p>The tutorial assumes that you have completed the <a href="http://explore.appinventor.mit.edu/hellopurr">HelloPurr</a> and <a href="/content/paintpot-part-1">PaintPot</a> tutorials.</p> <p><a href="http://cs.usfca.edu/~wolber/appinventor/bookSplits/ch3MoleMash.pdf">Download Book Chapter (PDF)</a></p> <h4 class="ai-header">Getting Started</h4> <p>Connect to the App Inventor web site and start a new project. Name it "MoleMash", and also set the screen's <strong style="color:green;">Title</strong> to "MoleMash". Open the Blocks Editor and connect to the phone.</p> <p>Also download this <a href="/sites/all/files/tutorials/moleMash/mole.png">picture of a mole</a> and save it on your computer.</p> <h4 class="ai-header">Introduction</h4> <p>You'll design the game so that the mole moves once every half-second. If it is touched, the score increases by one, and the phone vibrates. Pressing restart resets the score to zero.</p> <p>This tutorial introduces:</p> <ul><li>image sprites</li> <li>timers and the <strong>Clock</strong> component</li> <li>procedures</li> <li>picking random numbers between 0 and 1</li> <li>text blocks</li> <li>typeblocking</li> </ul><h4 class="ai-header">The first components</h4> <p>Several components should be familiar from previous tutorials:</p> <ul><li>A <strong>Canvas</strong> named "MyCanvas". This is the area where the mole moves.</li> <li>A <strong>Label</strong> named "ScoreLabel" that shows the score, i.e., the number of times the player has hit the mole.</li> <li>A <strong>Button</strong> named "ResetButton".</li> </ul><p>Drag these components from the Palette onto the Viewer and assign their names. Put <span style="color:green;">MyCanvas</span> on top and set its dimensions to 300 pixels wide by 300 pixels high. Set the <strong style="color:green;">Text</strong> of ScoreLabel to "Score: ---". Set the <strong style="color:green;">Text</strong> of ResetButton to "Reset". Also add a <strong>Sound</strong> component and name it "Noise". You'll use <span style="color:green;">Noise</span> to make the phone vibrate when the mole is hit, similar to the way you made the kitty purr in <span style="color:green;">HelloPurr</span>.</p> <h4 class="ai-header">Timers and the Clock component</h4> <p>You need to arrange for the mole to jump periodically, and you'll do this with the aid of a <strong>Clock</strong> component. The Clock component provides various operations dealing with time, like telling you what the date is. Here, you'll use the component as a timer that fires at regular internals. The firing interval is determined by the Clock 's <strong style="color:green;">TimerInterval</strong> property. Drag out a Clock component; it will go into the non-visible components area. Name it "MoleTimer". Set its TimeInterval to 500 milliseconds to make the mole move every half second. Make sure that <strong style="color:green;">Enabled</strong> is checked.</p> <h4 class="ai-header">Adding an Image Sprite</h4> <p>To add the moving mole we'll use a <em>sprite</em>.</p> <p>Sprites are images that can move on the screen within a Canvas. Each sprite has a <strong style="color:green;">Speed</strong> and a <strong style="color:green;">Heading</strong>, and also an <strong style="color:green;">Interval</strong> that determines how often the sprite moves at its designated speed. Sprites can also detect when they are touched. In <span style="color:green;">MoleMash</span>, the mole has a speed zero, so it won't move by itself. Instead, you'll be setting the mole's position each time the timer fires. Drag an <strong>ImageSprite</strong> component onto the Viewer. You'll find this component in the Animation category of the Palette. Place it within <span style="color:green;">MyCanvas</span> area. Set these properties for the Mole sprite:</p> <ul><li><strong style="color:green;">Picture</strong>: Use mole.png, which you downloaded to your computer at the beginning of this tutorial.</li> <li><strong style="color:green;">Enabled</strong>: checked</li> <li><strong style="color:green;">Interval</strong>: 500 (The interval doesn't matter here, because the mole's speed is zero: it's not moving by itself.)</li> <li><strong style="color:green;">Heading</strong>: 0 The heading doesn't matter here either, because the speed is 0.</li> <li><strong style="color:green;">Speed</strong>: 0.0</li> <li><strong style="color:green;">Visible</strong>: checked</li> <li><strong style="color:green;">Width</strong>: Automatic</li> <li><strong style="color:green;">Height</strong>: Automatic</li> </ul><p>You should see the <strong style="color:green;">x</strong> and <strong style="color:green;">y</strong> properties already filled in. They were determined by where you placed the mole when you dragged it onto <span style="color:green;">MyCanvas</span>. Go ahead and drag the mole some more. You should see <strong style="color:green;">x</strong> and <strong style="color:green;">y</strong> change. You should also see the mole on your connected phone, and the mole moving around on the phone as you drag it around in the Designer. You've now specified all the components. The Designer should look like this. Notice how <span style="color:green;">Mole</span> is indented under <span style="color:green;">MyCanvas</span> in the component structure list, indicating that the sprite is a sub-component of the canvas.</p> <p><img src="/sites/all/files/tutorials/moleMash/MoleMashDesigner.png" /></p> <h4 class="ai-header">Component Behavior and Event Handlers</h4> <p>Now you'll specify the component behavior. This introduces some new App Inventor ideas. The first is the idea of a <em>procedure</em>.</p> <p>A procedure is a sequence of statements that you can refer to all at once as single command. If you have a sequence that you need to use more than once in a program, you can define that as a procedure, and then you don't have to repeat the sequence each time you use it. Procedures in App Inventor can take arguments and return values. This tutorial covers only the simplest case: procedures that take no arguments and return no values.</p> <h4 class="ai-header">Define Procedures</h4> <p>Define two procedures:</p> <ul><li><span class="callblock">MoveMole</span> moves the <span style="color:green;">Mole</span> sprite to a new random position on the canvas.</li> <li><span class="callblock">UpdateScore</span> shows the score, by changing the text of the <strong style="color:green;">ScoreLabel</strong></li> </ul><p>Start with MoveMole:</p> <ul><li>In the Blocks Editor, under Built-In, open the Definition drawer. Drag out a <span class="callblock">to procedure</span> block and change the label "procedure" to "MoveMole".<br /><pre class="box">Note: There are two similar blocks: <span class="callblock">procedure</span> and <span class="callblock">procedureWithResult</span>. Here you should use <span class="callblock">procedure</span>.</pre><p>The <span class="callblock">to MoveMole</span> block has a slot labeled "do". That's where you put the statements for the procedure. In this case there will be two statements: one to set the mole's x position and one to set its y position. In each case, you'll set the position to be a random fraction, between 0 and 1, of the difference between the size of the canvas and the size of the mole. You create that value using blocks for <span class="basicblock">random fraction</span> and multiplication and subtraction. You can find these in the Math drawer.</p></li> <li>Build the <span style="color:green;">MoveMole</span> procedure. The completed definition should look like this:<br /><img src="/sites/all/files/tutorials/moleMash/MoveMole.png" /><br /> Leave the arg socket for <span style="color:green;">MoveMole</span> empty because <span style="color:green;">MoveMole</span> does not take any arguments. Observe how the blocks connect together: the first statement uses the <span class="setblock">Mole.X set</span> block to set mole's horizontal position. The value plugged into the block's socket is the result of multiplying: <ol><li>The result of the <span class="basicblock">call random fraction</span> block, which a value between 0 and 1</li> <li>The result of subtracting the mole's width from the canvas width</li> </ol><p>The vertical position is handled similarly.</p></li> </ul><p>With <span style="color:green;">MoveMole</span> done, the next step is to define a variable called <span style="color:green;">score</span> to hold the score (number of hits) and give it initial value 0. Also define a procedure <span class="callblock">UpdateScore</span> that shows the score in <span style="color:green;">ScoreLabel</span>. The actual contents to be shown in <span style="color:green;">ScoreLabel</span> will be the text "Score: " joined to the value of <span style="color:green;">score</span>.</p> <ul><li>To create the "Score: " part of the label, drag out a text block from the Text drawer. Change the block to read "Score: " rather than "text".</li> <li>Use a join block to attach this to a block that gives the value of the score variable. You can find the join block in the Text drawer.</li> </ul><p>Here's how <span style="color:green;">score</span> and <span class="callblock">UpdateScore</span> should look:</p> <p><img src="/sites/all/files/tutorials/moleMash/UpdateScore.png" /></p> <h4 class="ai-header">Add a Timer</h4> <p>The next step is to make the mole keep moving. Here's where you'll use <span style="color:green;">MoleTimer</span>. Clock components have an event handler called <span class="basicblock">when ... Timer</span> that triggers repeatedly at a rate determined by the <strong style="color:green;">TimerInterval</strong>.</p> <p>Set up <span style="color:green;">MoleTimer</span> to call <span class="callblock">MoveMole</span> each time the timer fires, by building the event handler like this:</p> <p><img src="/sites/all/files/tutorials/moleMash/MoleMashTimerEventHandler.png" /></p> <pre class="ai-box">Notice how the mole starts jumping around on the phone as soon as you define the event handler. This is an example of how things in App Inventor start happening instantaneously, as soon as you define them.</pre><h4 class="ai-header">Add a Mole Touch Handler</h4> <p>The program should increment the score each time the mole is touched. Sprites, like canvases, respond to touch events. So create a touch event handler for <span style="color:green;">Mole</span> that:</p> <ol><li>Increments the score.</li> <li>Calls <span class="callblock">UpdateScore</span> to show the new score.</li> <li>Makes the phone vibrate for 1/10 second (100 milliseconds).</li> <li>Calls <span class="callblock">MoveMole</span> so that the mole moves right away, rather than waiting for the timer.</li> </ol><p>Here's what this looks like in blocks. Go ahead and assemble the <span class="basicblock">when Mole.Touched</span> blocks as shown.</p> <p><img src="/sites/all/files/tutorials/moleMash/MoleMashTouchEventHandler.png" /></p> <p>Here's a tip: You can use typeblocking: typing to quickly create blocks.</p> <ul><li>To create a value block containing 100, just type 100 and press return.</li> <li>To create a <span class="callblock">MoveMole</span> block, just type <span class="callblock">MoveMole</span> and select the block you want from the list</li> </ul><h4 class="ai-header">Reset the Score</h4> <p>One final detail is resetting the score. That's simply a matter of making the <span style="color:green;">ResetButton</span> change the score to 0 and calling <span class="callblock">UpdateScore</span>.</p> <h4 class="ai-header">Complete Program</h4> <p>Here's the complete <span style="color:green;">MoleMash</span> program:</p> <p><img src="/sites/all/files/tutorials/moleMash/MoleMashComplete.png" /></p> <h4 class="ai-header">Variations</h4> <p>Once you get the game working, you might want to explore some variations. For example:</p> <ul><li>Make the game vary the speed of the mole in response to how well the player is doing. To vary how quickly the mole moves, you'll need to change the <span style="color:green;">MoleTimer</span>'s <strong style="color:green;">Interval</strong> property.</li> <li>Keep track of when the player hits the mole and when the player misses the mole, and show a score with both hits and misses. To do this, you'll need do define touched handlers both for <span style="color:green;">Mole</span>, same as now, and for <span style="color:green;">MyCanvas</span>. One subtle issue, if the player touches the mole, does that also count as a touch for <span style="color:green;">MyCanvas</span>? The answer is yes. Both touch events will register.</li> </ul><h4 class="ai-header">Review</h4> <p>Here are some of the ideas covered in this project:</p> <ul><li>Sprites are touch-sensitive shapes that you can program to move around on a <strong>Canvas</strong>.</li> <li>The <strong>Clock</strong> component can be used as a timer to make events that happen at regular intervals.</li> <li>Procedures are defined using <span class="callblock">to</span> blocks.</li> <li>For each procedure you define, App Inventor automatically creates an associated call block and places it in the My Definitions drawer.</li> <li>Making a <span class="basicblock">random-fraction</span> block produces a number between 0 and 1.</li> <li>Text blocks specify literal text, similar to the way that number blocks specify literal numbers.</li> <li>Typeblocking is a way to create blocks quickly, by typing a block's name.</li> </ul><h4 class="ai-header">Scan the Sample App to your Phone</h4> <p>Scan the following barcode onto your phone to install and run the sample app. </p><p><img src="/sites/all/files/tutorials/moleMash/MoleMashBarcode.png" /></p> <h4 class="ai-header">Download Source Code</h4> <p>If you'd like to work with this sample in App Inventor, download the <a href="/sites/all/files/tutorials/moleMash/MoleMash.zip">source code</a> to your computer, then open App Inventor, go to the My Projects page, and choose <b>More Actions | Upload Source</b>.</p> <pre class="ai-box">Done with <span style="color:black;">MoleMash</span>? Return to the other tutorials <a href="/tutorials">here</a>.</pre></div></div></div><section class="field field-name-field-version field-type-taxonomy-term-reference field-label-above view-mode-rss clearfix"> <h2 class="field-label">Tutorial Version:&nbsp;</h2> <ul class="field-items"> <li class="field-item even"> <a href="/tutorial-version/app-inventor-1" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">App Inventor 1</a> </li> </ul> </section> <section class="field field-name-field-tutorial-difficulty field-type-taxonomy-term-reference field-label-above view-mode-rss clearfix"> <h2 class="field-label">Tutorial Difficulty:&nbsp;</h2> <ul class="field-items"> <li class="field-item even"> <a href="/tutorial-difficulty/basic" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">Basic</a> </li> </ul> </section> <section class="field field-name-field-tutorial-type field-type-taxonomy-term-reference field-label-above view-mode-rss clearfix"> <h2 class="field-label">Tutorial Type:&nbsp;</h2> <ul class="field-items"> <li class="field-item even"> <a href="/tutorial-type/clock-timer" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">Clock Timer</a> </li> <li class="field-item odd"> <a href="/tutorial-type/game" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">Game</a> </li> <li class="field-item even"> <a href="/tutorial-type/sprites" typeof="skos:Concept" property="rdfs:label skos:prefLabel" datatype="">Sprites</a> </li> </ul> </section> Fri, 14 Jun 2013 15:43:59 +0000 aaron 306 at http://dev-explore.appinventor.mit.edu http://dev-explore.appinventor.mit.edu/content/molemash#comments