Turn off Lights - A

11

Turn Off Lights is a variation of the famous old Whack-a-Mole game: this one promoting the socially useful message of saving electricity. In the game, a light bulb (represented by an ImageSprite) pops up at random positions on the screen. A player can score by touching the light bulb before it disappears.

This app uses animation, a clock, and randomness to move the ImageSprite around the canvas. This tutorial guides you through the basic steps in creating the animation.

Objectives

  • follow an instructor-led walk-through to create the TurnOffLights app on a mobile device
  • develop your understanding of how timing, animation, and randomness are programmed
  • develop your understanding of procedures and procedural abstraction
  • deepen your understanding of event-driven programming

Getting Ready & Video Tutorials

  • Open App Inventor with the Turn Off Lights template. The template app just contains the images and sound files for the app, but no design or code yet.
  • When the project opens, use the Save As option to rename it TurnOffLights.
  • Then follow along with the following tutorial.

The Turn Off Lights User Interface (UI)

The UI for our this app will consist of four types of Components:

  • Basic Components: Canvas, Label, Clock
  • Media Component: Sound
  • Animation Component: an ImageSprite
  • Layout Component: Vertical Arrangement

The Canvas serves as the background where the light bulb jumps around. The light bulb is represented by an ImageSprite that is contained in the Canvas component. We'll come back to this. The Clock is used as a timer to move the ImageSprite to a random spot on the Canvas every time the Clock ticks. The Sound is used to vibrate the phone or play a sound whenever the player hits the ImageSprite.

Adding the Canvas

To begin with, set the various Screen1 properties as shown in the UI screenshot above, including AppName, ScreenOrientation, Title and others. Next, drag and drop a VerticalArrangement component from the Layout drawer and set its height and width to Fill parent. The Canvas and other component will be contained within this arrangement and will fill the screen. By using a VerticalArrangement, we can guarantee that all of its components will be visible on the screen without scrolling.

You have used the Canvas component for drawing in the Paint Pot tutorials. In this app Canvas is used to support animation. App Inventor uses two types of components that can move for animation, Balls and ImageSprites, both of which are contained within a Canvas component. First, we'll add the Canvas component.

  1. Drag and drop a Canvas component from the Palette's Drawing and Animation category into the VerticalArrangement. .
  2. Set the Canvas's width and height to fill-parent.
  3. Set the Canvas's BackgroundImage to kitchen-picture.jpg.

Adding the Save Electricity Label

Add the Label to the UI, right underneath the Canvas in the VerticalArrangement. Name the label LabelSaveElectricity and set its text property to "Help Save Electricity!"

Adding the ImageSprite

As mentioned before, the light bulb is represented by an ImageSprite, a component that can move (like a Ball) and can also display an Image (unlike a Ball). ImageSprites can only be used on a Canvas.

  1. Drag and drop an ImageSprite component from the Palette's Drawing and Animation drawer onto the Canvas.
  2. Set the ImageSprite's picture property to the lightbulb.jpg image file, which is included in the template's Media panel.
  3. Set the ImageSprit's height and width properties to 50 pixels each.
  4. Rename the ImageSprite to "LightBulbSprite".

Adding the Sound

We will use a Sound Component to vibrate the device when the player successfully touches the light bulb. Drag and drop a Sound component from the Palette's Media category into the Viewer. It will be named Sound1 and will appear as a non-visible component.

Adding the Clock

The ImageSprite component has a Speed property, which controls the Sprite's movement. However, for this app, we won't be using that property. Instead, we will use the Clock component to move the Sprite to a random location on the canvas whenever the clock ticks. The Clock has a Timer event that can be used to move the Sprite to a new random location whenever the Timer event fires. In effect, every time the Timer ticks, the Sprite will 'jump' to a new random location.

  1. Drag and drop a Clock component from the Palette's Sensors category into the Viewer. It will be named Clock1 and it will appear at the bottom of the Viewer as a non-visible component.
  2. Set the Clock's TimerInterval property to 1000 milliseconds. This will make the clock tick every second.

Coding the App's Behavior

In order to get the Sprite moving, we'll first set up a Clock.Timer event that will allow the Sprite to 'jump' to various positions randomly with the help of some Math blocks that are used for randomness. Once the Sprite is moving we'll need to make the device vibrate each time the user touches the Sprite (light bulb).

Moving the Sprite

To construct this you will pull the when Clock1.Timer block from the Clock1 drawer, the MoveTo block from the LightBulb drawer, and two number blocks from the Math drawer.

The Clock.Timer event is triggered periodically. If you have set the Clock's TimerInterval property to 1000, this event will trigger every 1000 milliseconds, or every second. If you are testing the app, you'll see that the Sprite jumps to the location x=100, y=100 and just stays there. The event keeps triggering, but after the first time the Sprite is already at 100,100 so it doesn't appear as if anything is happening.

What we really want is for the Sprite to move to a random location each time the clock triggers. For this, drag out two random integer blocks from the Math drawer, and plug them in as seen to the right.

Now you should see the Sprite move around randomly every 1000 ms., but stay within the top left section of the Canvas.

Of course the upper limit of 100 is incorrect. We really want the Sprite to jump around anywhere on the Canvas. For this, we can use the Width and Height properties of the Canvas. Pull out Canvas.Width, Canvas.Height from the Canvas drawer and modify your blocks as seen.

Now you should see the LightBulb jumping randomly all over the canvas.

Refactoring: The moveRandom Procedure

As we learned in an earlier lesson, having identical segments of code in two separate locations in the app is not a good programming practice. To fix that, let's define a moveRandom procedure and call it to manage moving the ImageSprite to a random location.

Abstraction

When you define a procedure in a programming language you are creating an abstraction. The procedure represents a particular algorithm. Once you define the procedure, it encapsulates the details of the algorithm (hides the details). To execute the algorithm, you only need to call the procedure. When calling the procedure, you aren't necessarily aware of the details of the algorithm. Thus, defining and using procedures helps reduce the complexity in our programs and makes them easier to read, modify, and maintain.

In our app, the Screen.Initialize and Clock.Timer events both do the same thing and call the same blocks to move the ImageSprite randomly. Whenever you copy-paste, as we did, a little bell should go off in your head: I need a procedure! In this case, the moveRandom procedure is appropriate.

  1. Drag out a to procedure block from the Procedures drawer.
  2. Name the procedure "moveRandom".
  3. Drag the blocks from Screen.Initialize and place them in "moveRandom".

Open the Procedures drawer again. You should now see a block, "call moveRandom". Pull it out and place it in Screen.Initialize. Take out the blocks for Clock.Timer as well and replace them with a call moveRandom block.

Your app should work exactly the same, with the Sprite moving around randomly.

Handling the Touched Event

Similar to Paint Pot, the Turn Off Lights app will also use a Touched event. However, this touched event is used differently. When a player touches the Sprite we want them to get some type of feedback for their accomplishment. This helps give the user feedback when taking actions within the app. For now, let's make the phone vibrate for 500 milliseconds (half a second) whenever the Sprite is touched:

  1. Get a LightBulb.Touched block from the LightBulb drawer.
  2. Get a Sound1.Vibrate block from the Sound1 drawer.
  3. Set the Vibrate interval to 500 millisecs.
  4. Place the Vibrate block inside the Touched block.

NOTE that not all Android devices contain a vibration component. If your device does not vibrate, replace the Vibrate block with a Sound1.Play block and set the Sound1.Source property (in the Designer) to the beep.mp3 file.

Testing the App

Still Curious?

You can think of procedures like "shortcuts" in your code. Where a complicated process, such as taking the sum of a list of numbers, can simply be given a shortcut name like "sum". Once you make the procedure you will not have to worry about how it works, i.e. assume sum works correctly, instead simply use the call to the shortcut name in other code blocks.