2017년 7월 18일 화요일

Ball, Canvas: Bounce a ball off a drawing on the Canvas


Kelly from the App Inventor in Education forum asked about bouncing a ball off of a line on the canvas. I thought I would include my solution here. The key is to detect the color under the ball and to have the ball bounce when it touches a specific color or any color that is not the background color. This particular solution looks for a red object and if it touches it, bounces. Both timers are needed for the ball to not pass through a thin line.

Blue ball, red line, white canvas:

Timers can be configured in the Screen Designer:



Timer settings were included here to show what worked for me, but they can be set up in the Screen Designer instead:



--
I have been created a maze game for a school assignment and it took me awhile to get the maze generation working but now a new problem has arisen. Even using this method my imagesprite still goes through the walls sometimes. Increasing the thickness of the walls from 2-4 also increases the chance of a successful rebound but tis is far to big for my test normal test device. I tried things like adjusting the speed of the player, disabling the player's input until the cooldown ends and tweaking the clocks timer intervals but atlas to no avail. I have considered checking all the corners and with the walls at a thickness of 4 it worked when moving left or right through walls (Up and down didn't work because the change in heading affected were the corners would be. ie the area it would be checking would now be below the sprite rather than at the corner.). I also tried using the negate block on the players speed property but this was disastrous, is getpixelcolour more effective than getpixelbackgroundcolour because at the moment that is the only difference I have (Besides setting player input to false - I do this by setting a variable to false then when the canvas is flung it needs that variable to be set to true for it to move the player).  I am considering doing more tweaking with the player's interval and the clock times. If you have nay help or suggestions it would be greatly appreciated as I am running out of time. Also if it helps the imagesprite is 20x12 and I haven't tested if it works with a ball yet. Thanks
EDIT: Okay so I now have it so the player can only move in 4 directions, currently I only have 2 of the directions set up to check all the corners of the image sprite but I can definitely see improvement however it is not fixed and rarely it will still go through walls (If the sprite stops close to the wall and then move again it will pass through the wall). Once again your help would be greatly appreciated.

EDIT 2: So its now set to recognise all directions but it doesn't pick up my up or down directions and left and right have the error mentioned above. Back to the drawing board.

--
Unfortunately, when using the Canvas, animation is not very responsive in some cases.
I would recommend setting your clock timer to an interval of 0 (zero) to make it as responsive as possible.
Other than that, I have struggled with the same issue as yourself -- sometimes the sprite does not bounce off the background color as expected.
It should not matter which block is used. Either GetPixelColor or GetBackgroundPixelColor should work the same.
GetPixelColor also detects the color of a sprite at the specified x,y location. That is how it is different.

--
I made this in App Inventor2, but cannot use a custom color.
Why is that?

--
@imans314: For general App Inventor questions please ask in the MIT App Inventor Forum.

--

is it possible for a sprite to detect is its touching a color?


hi, i was wondering if its possible for a sprite (ball) to detect is its touching a color (light blue). i have tried many times, but i simple cant find out.

--
Maybe... You'd have to check every pixel for it's color, and no matter how hard you try, that'll be very consumptive in AI...

You'd have to analyze the color of each pixel based upon it's location... Use the Canvas.GetBackgroundPixelColor, and pass it the x,y of each tick, but expect the deal to be VERY slow...

--
Try here ...

Ball, Canvas: Bounce a ball off a drawing on the Canvas


The first link (Scott Ferguson) in this thread discusses this.

--
Please not that Scott's example is an AI Classic project... you'll have to convert it to AI2...

--
thanks for the link, but sadly i didn't work. i put in some screen shots of my app, i was wondering if u have any suggestions. 
i want to make it so when the ball (red thing) touches the light blue, it would trigger the game over screen. the light blue, is just a picture with white and blue.


i do not know of any other way to fix it. so if u come up with any ideas please tell me

--
You appear to have different timers for different stuff... That's NOT the way you should do this.  You need to check that color every time you move the sprite, which I'm sure, is in another timer.... Do this in there... When the sprite moves, check the color.

Also, why open another screen when the game is over?  Just put up a Notifier... you can also change the image in the background of the same screen...

--
what is the timer interval of your clock?
what happens, if you set the ball manually to a x/y coordinate with the light blue background?
use Do it to debug your blocks

--
im some what confused... could you show me how you would do it in the same timer?

--
Perhaps     

1. http://rosettacode.org/wiki/Color_of_a_screen_pixel      

App Inventor has two Canvas blocks to determine the color under a pixel.
GetBackgroundPixelColor returns a color from the Canvas but ignores Ball sprites and ImageSprites.
GetPixelColor returns a color from either the Canvas or a Ball sprite or ImageSprite.
In the app's display below, the purple Ball sprite was touched on the left canvas, but the pixel color (green) returned was from the area below it.


2. https://lh4.googleusercontent.com/-Gw0xm7RIEck/Uute2nQSGsI/AAAAAAAAJ90/rq3UuWYE9Yw/s1600/Capture.PNG  


might help

--
thanks for the link, but sadly it still doesn't seam to work, ive tried another way, by setting the canvas background color to the light blue, and making the path a white .PNG, do u know if there would be any way i can detect if the ball comes off the path (touches the blue canvas)?

--
Post a screenshot of how and where you're moving the ball...

--

How to increment a string?


I have a TextBox that I want the user to be able to input a string consisting of 1-3 letters followed by 1-2 numbers.  For example "A1" or "AAA11".

How do I increment this string by 1 so that I can use the new value?

--
Perhaps



-- 
AA11 + 1 = AA12 or AA111 ??
AA99 + 1 = ?

-- 
first you have to separate the numbers 
then add 1

the for loop is searching for the last letter. -> NumberStart+1 is the first number

then the whole number will be separated

and add 1

 (you can replace the TextBox by a Variable)

-- 

Navegador GPS


Olá existe uma maneira de criar um navegado gps como o Waze ou google maps?

Hello there is a way to create a GPS navigator like Waze or google maps?

--
There are many ways to use App Inventor along with the Google Map API.  The techniques can be adapted to mage your gps Navigator..  Here are some basic tutorials

Android, Where's My Car? for App Inventor 2
You parked somewhere near the stadium, but when the concert ends you don't have a clue where the car is. Fortunately you haven't lost your Android phone that never forgets anything, and you remember you have the hot new app, Android, Where's My Car?. With this app, you click a button when you park your car, and the Android uses its location sensor to record the car's GPS coordinates and address. Later, when you reopen the app, it shows you a map from where you are to the remembered location-- problem solved! With this tutorial you'll be able to download a created app and then study the annotated blocks below to better understand the app and App Inventor programming in general. This app covers: GPS, TinyDB, and using Activity Starter to open a map.
Map It: Displaying Locations on a Google Map
This tutorial shows how you can develop an app that allows you to record list of addresses and view the address on the Google Maps. It will also show you how view your current location on the Google Map.
Exploring with Location Sensor in AI2
The location sensor object is used to communicate with the global positioning satellite receiver (GPS) in your phone/tablet. When the LocationSensor communicates with the built-in GPS receiver, the GPS can determine the location of your device.  The sensor can also work with network/wifi location services.  Finding a location using the network uses very different techniques to determine a location. Location means, the device's present latitude and longitude or it can mean your street address.
Have you tried any of these tutorials Nando?

or very simply you could use ActivityStarter to navigate  as shown above if you turn your GPS on and allow LocationServices.

--
HELLO STEVE THANK YOU VERY MUCH FOR YOUR SO QUICK RESPONSE, WHAT YOU INDICATED ME HAS ALREADY DONE IN MY PROJECT HE MARK DOTS ON MAP AND USA ActivityStarter TO CALL A NATIVE GOOGLE BROWSER, WHAT I LOOK FOR IS A WAY TO CREATE MY PROPERTY BROWSER, LIKE THE WAZE FOR EXAMPLE.

--
Sorry.  I do not understand exactly what you want to do.  Your image posted is from WAZE.  What do you mean 'property browser?'

If you want to show  many different locations, use a Google Map API Static Map with multiple pins https://developers.google.com/maps/documentation/static-maps/intro#quick_example .  These examples can be replicated with AI2.

If you want a traffic layer use JavaScript to display https://developers.google.com/maps/documentation/javascript/examples/layer-traffic  

Here are other links:


Google has a Business Map API...perhaps that is what you are interested in?

Provide a better description of exactly what you want to do Nando and someone will provide more advice.  It appears you may already have created a StaticMap with pins using google.   You can do something similar using OSM.

Perhaps find the articles     

How to start OsmAnd and open the map with a place marker and  How to launch Waze to look for a specified location   described on Taifun's snippets http://puravidaapps.com/snippets.php 


You can do something like this using a static map and an ActivityStarter

These images are from an app that stores geocoordinates of locations in a List, labels those locations and allows one to get a routing.  The top image shows a routing from the White House to the Lincoln Memorial.   Developers could create a polyline showing the same route with additional code however the developer would have to manually code the route on the map.

Press the blue >>>> on the top image walking map to get the walking directions in text as shown above.    Yes, this app uses Google Maps.

--

Finding distance between 2 coordinates - Haversine implementation


I'm writing a simple app to (amongst other things) show the distance between two GPS points.  This distance will typically be under 500m (locating a downed quadcopter), and I'm trying to implement the Haversine formula.  I've read through all of the previous mentions of this but haven't found the answer.

I'm using the formula here:
http://rosettacode.org/wiki/Haversine_formula#Python
Python version:
def haversine(lat1, lon1, lat2, lon2):
  R = 6372.8 # Earth radius in kilometers
  dLat = radians(lat2 - lat1)
  dLon = radians(lon2 - lon1)
  lat1 = radians(lat1)
  lat2 = radians(lat2)
  a = sin(dLat/2)**2 + cos(lat1)*cos(lat2)*sin(dLon/2)**2
  c = 2*asin(sqrt(a))
  return R * c
>>> haversine(36.12, -86.67, 33.94, -118.40)
2887.2599506071106


I convert the coordinates to radians before passing these values to the attached blocks, and as far as I can see, it's working ok until it gets to the lines calculating a,b,c.
(I split it up in order to try and trace the steps).  However, the values returned are nowhere near the example above, or other distances calculated (say) on google maps.
Can anyone see where I've gone wrong? 

--
you could compare your formula with the formula here http://www.movable-type.co.uk/scripts/latlong.html
also you can easily test the calculation on that page...

btw. an example of the bearing formula you can find here 

--
Using your own data
Note, this 2886 km compares favorably with the 2887 kilometers you posted using the online calculator Taifun mentioned    http://www.movable-type.co.uk/scripts/latlong.html
Your alogrithm appears to be working but the distance is LARGE.


Haversine is for SHORT distances.  To calculate distances like this (1793 miles if you convert); you should use a
Great Circle algorithm  or Vincenty's Algorithm.  

What distances are your other sources reporting?

Here is a Haversine calculation over a short distance with values to compare.... how does your algorithm compare?
--
Hi, thanks for the responses.

I tried my effort with the calculation of a short distance (which is its intended purpose) and got a result of 0.69435km, instead of 0.549 as seen in Steve's example.  Close - but no cigar, as I want this app to get me within around 25m of a downed quadcopter - at which point I'd be able to hear the beeper.

I was hoping that somebody might be able to spot an error in my implementation of the formula in my first post - I'm pretty certain that this formula is correct, and, if my coding of it accurate, should give closer results.  Either my replication in AI of the formula is still not quite right, or AI has some calculation issues...?

Thanks for the tip about bearing...however, my phone has no compass and therefore won't be able to provide azimuth - but I've got a workaround for that.

Thanks again - if I do manage to get it working correctly, I'll post the solution.

--
Hmmm.   Use an Earth's radius of 6363 instead of 6372.8  ..... see  http://andrew.hedges.name/experiments/haversine/  

Also, be aware, the LocationSensor has a property called Accuracy... read about it here http://appinventor.mit.edu/explore/ai2/location-sensor.html   The GPS receiver on the phone is never going to get you within 2 meters of where it says it is except occasionally.   The GPS can be off as much as 50 meters easily based on a single reading depending on......

Your Haversine code looks OK David (however my eyes just can not render those blocks any more and it is not clear what code you use in lat2rad or lon2rad.)

Try to calculate again with a skinnier Earth.  The Earth is not round, it is a geoid and generally an elllipsoid so the diameter of the Earth to use depends on your latitude... are you close to 39 degrees? or somewhere else   33 or 36?

You could calibrate your algorithm Earth radius by  measuring a distance on your side walk ... say 100 meters.  Note the start, note the end point using the GPS.  Note the start point coordinates, when you get to the 100 meter point, do your calculation.  If the answer is not 100, well, do what a guy's gotta' do.
Edit... OK I found this...

--
I think that I might have to try a different approach, and look into adapting the 'where's my car' tutorial.  I'd hoped to avoid the use of a data connection for google maps, but my current approach doesn't seem to be working and I'm short on time.  Meh, I hate it when I can't see where a problem lies...
I'm at about 53 degrees latitude btw (N.Wales, UK).

--
Finally cracked it.  The problem was that in all of my previous programming, the trig functions expected angles to be expressed in radians, whereas AI2 requires degrees.  By using the conversion functions, I've now got it working quite well, comparing the results against those from online calculators.  The attached snapshot shows the blocks of the calculation procedure, note that the coordinates have been converted to radians beforehand.  Also, the variable 'global b' is calculated in several steps because it's the only way that I could get the snapshot!


--

GPS


I had a question in regards to GPS. I would like to make a mileage tracker. So if I use two GPS location and try to calculate the distance between them is it calculated in a straight line? Can someone maybe give me a link where I could find some more information about this. Or maybe someone already made an app like this that I could play around with.

--
at great distances you can use the method of Haversine, you can download an app of this Spanish tutorial

Defining Procedures: Reusing Blocks (Distance between points)

-- 
if I use two GPS location and try to calculate the distance between them is it calculated in a straight line?      Yes unless you use something like Google's Map API to provide the Navigation information.    

You can calculate straight-line distance between two coordinates by use any one of several mathematical algorithms.  Which you use depends on how far apart 
the geocoordinates actually are.  For distances of up to several miles, you might use the haversine method (there are some blocks in this post Finding distance between 2 coordinates - Haversine implementation ) .   You can use simple trig as some loss of precision or for large distances you can use spherical geometry.   These methods always will show the minimum distance traveled in the case you are attempting to find the distance using roads and streets.

You might look at an app called greatCircleDistance in the MIT Gallery apps.

-- 
Here is a simple way to do it if you prefer to use something simpler than the Haversine formula
-- 
or if you want to Navigate, try the suggestions here Navegador GPS .
To do this one of the points has to be provided by the LocationSensor in an Android and the second can be anywhere you want.  This method will give you the driven or walked path distance, NOT the straight-line distance.

-- 
The later was exactly what I was looking for Steve. Thank you Juan and Steve for your help.

--
However the link doesn't seem to lead me anywere.

--

Defining Procedures: Reusing Blocks


Programming languages like App Inventor provide a base set of built-in functionality-in App Inventor's case, a base set of blocks. Programming languages also provide a way to extend that functionality by adding new functions (blocks) to the language. In App Inventor, you do this by defining procedures-named sequences of blocks-that your app can call just as it calls App Inventor's predefined blocks. As you'll see in this chapter, being able to create such abstractions is very important for solving complex problems, which is the cornerstone of building truly compelling apps.


When parents tell their child, "Go brush your teeth before bed," they really mean "take your toothbrush and toothpaste from the cabinet, squeeze out some toothpaste onto the brush, swivel the brush on each tooth for 10 seconds (ha!)," and so on. "Brush your teeth" is an abstraction: a recognizable name for a sequence of lower-level instructions. In this case, the parents are asking the child to perform the instructions that they've all agreed mean "brush your teeth."
In programming, you can create such named sequences of instructions. Some programming languages call them functions or subprograms. In App Inventor, they're called procedures. A procedure is a named sequence of blocks that can be called from any place in an app.
Figure 21-1 is an example of a procedure whose job is to find the distance, in miles, between two GPS coordinates you send to it.
Figure 21-1. Procedure for computing the distance between points
Don't worry about the internals of this procedure too much just yet; just realize that procedures like this let you extend the language by which you design and build programs. If every parent had to explain the steps of "brush your teeth" to his or her child each night, that kid might not make it to the fifth grade. It's much more efficient to just say, "Brush your teeth," and everyone can move on with getting to bed at a reasonable hour.
Similarly, once you define the procedure distanceBetweenPoints, you can ignore the details of how it works and simply refer to the procedure's name (or call it) when designing or coding a larger app. This type of abstraction is key to solving large problems and lets us break down a large software project into more manageable chunks of code.
Procedures also help reduce errors because they eliminate redundancy in your code. With procedures, you can put a chunk of code in one place and then call it from various places in your app. So, if you're building an app that needs to know the minimum distance between your current location and 10 other spots, you don't need to have 10 copies of the blocks shown in Figure 21-1. Instead, you just define the procedure and then call it whenever you need it. The alternative-copying and pasting blocks-is much more error-prone because when you make a change, you have to find all the other copies of those blocks and change each one in the same way. Imagine trying to find the 5–10 places where you pasted a particular chunk of code in an app with 1,000 lines or blocks! Instead of forcing you to copy and paste, a procedure lets you encapsulate blocks in one place.
Procedures also help you build up a library of code that can be reused in many apps. Even when building an app for a very specific purpose, experienced programmers are always thinking of ways to reuse parts in other apps should the need arise. Some programmers never even create apps, but instead focus solely on building reusable code libraries for other programmers to use in their apps!
Eliminating Redundancy
Take a look at the code blocks in Figure 21-2. See if you can you identify the redundant ones.




Figure 21-2. A Note Taker app with redundant code
The redundant blocks are the ones involving a foreach block (actually the foreach and the set NotesLabel.Text to above it). In all three foreachinstances, the block's job is to display the notes list. In this app, this behavior needs to take place when a new item is added, when an item is removed, and when the list is loaded from the database at application launch.
When experienced programmers see such redundancy, a bell goes off in their heads, probably even before they've copied and pasted the blocks in the first place. They know that it's best to encapsulate such redundancy into a procedure, both to make the program more understandable and so that changes will be much easier later.
So an experienced programmer would create a procedure, move the redundant blocks into it, and then call the procedure from the three places containing the redundant blocks. The app will not behave any differently, but it will be easier to maintain and easier for other programmers to work with. Such code (block) reorganization is called refactoring.
Defining a Procedure
Let's build a procedure to do the job of the redundant code blocks from Figure 21-2. In App Inventor, you define a procedure in a manner similar to how you define variables. From the Procedures drawer, drag out either a to procedure block or a to procedure result block. Use the latter if your procedure should calculate some value and return it (we'll discuss this approach a bit later in the chapter).
After dragging out a to procedure block, you can change its name from the default "procedure" by clicking the word "procedure" and typing the new name. The redundant blocks we're refactoring performed the job of displaying a list, so we'll name the procedure displayList, shown in Figure 21-3.


 Figure 21-3. Giving the procedure a name
The next step is to add the blocks within the procedure. In this case, we're using blocks that already exist, so we'll drag one of the original redundant blocks out of its event handler and place it within the to displayList block, as shown in Figure 21-4.
Figure 21-4. The displayList procedure encapsulates the redundant code
We can now display the notes list using a procedure that you can easily call from elsewhere in your app!
Calling a Procedure
Procedures, like displayList and "brush your teeth," are entities with the potential to perform a task. However, they'll only perform that task if they are called upon to do so. Thus far, we've created a procedure but haven't called it. To call a procedure means to invoke it, or to make it happen.
In App Inventor, you call a procedure by dragging out a call block from the Procedures drawer. Each time you define a procedure, a new block appears in that drawer. When you define a procedure, a call block is added, as shown in Figure 21-5.
Figure 21-5. A call block appears in the Procedures drawer when you define a procedure
You use call blocks all the time to call App Inventor's predefined functions, like Ball.MoveTo and Texting.SendMessage. When you define a procedure, you have in essence created your own block; you've extended the App Inventor language. The new call block lets you invoke your creation.
For the Note Taker app sample, you'd drag out three call displayList blocks and use them to replace the redundant code in the three event handlers. For instance, the ListPicker1.AfterPicking event handler (for deleting a note) should be modified as shown in Figure 21-6.

Figure 21-6. Using the displayList call to invoke the blocks now in the procedure
The Program Counter
To understand how the call block works, think of an app as having a pointer that steps through the blocks performing functions. In computer science, this pointer is called the program counter.
When the program counter is performing the blocks within an event handler and it reaches a call block, it jumps over to the procedure and executes the blocks in it. When the procedure completes, the program counter jumps back to its previous location (the call block) and proceeds from there. So, for the Note Taker example, the remove list item block is performed; then the program counter jumps to the displayList procedure and performs its blocks (setting the NotesLabel.Text to the empty text, and the foreach); and finally the program counter returns to perform the TinyDB1.StoreValue block.
Adding Parameters to Your Procedure
The displayList procedure allows redundant code to be refactored into a single place. The app is easier to understand because you can read the event handlers at a high level and generally ignore the details of how a list is displayed. It is also helpful because you may decide to modify how you display the list, and the procedure allows you to make such a modification in a single place (instead of three).
The displayList procedure has limits in terms of its general usefulness, however. The procedure works for a specific list (notes) and displays that list in a specific label (NotesLabel). You couldn't use it to display a different data list-say, a list of the app's users-because it is defined too specifically.
App Inventor and other languages provide a mechanism called parameters for making procedures more general. Parameters comprise the information a procedure needs to do its job-the specifics of how the procedure should be performed. In our bedtime tooth-brushing example, you might define "toothpaste type" and "brushing time" as parameters of the procedure "brush your teeth."
You define parameters for a procedure by clicking on the blue icon at the left-top of the procedure definition. For the displayList procedure, we would define a parameter named "list," as shown in Figure 21-7.
Figure 21-7. The procedure now accepts a list as a parameter
Even with the parameter defined, the blocks still refer directly to the specific list notes (it's plugged into the "in list" slot of the foreach). Because we want the procedure to use the list we send in as a parameter, we replace the reference to global notes with a reference to value list, as demonstrated in Figure 21-8.
Figure 21-8. Now the foreach will use the list sent in
The new version of the procedure is more generic: whatever calls displayList can now send it any list, and displayList will display it. When you add a parameter to a procedure, App Inventor automatically puts a corresponding slot in the call block. So, when the parameter list is added to displayList, the call blocks to displayList look like Figure 21-9.
Figure 21-9. Calling displayList now requires you to specify which list to display
The name list within the procedure definition is called a formal parameter. The corresponding slot within the call block is called an actual parameter. When you call a procedure from somewhere in the app, you must supply an actual parameter for each formal parameter of the procedure.
For the Note Taker app, you'd add a reference to the notes list as the actual parameter. Figure 21-10 shows how ListPicker.AfterSelection should be modified.
Figure 21-10. Calling the displayList with notes sent as the actual parameter
Now when displayList is called, the list notes is sent over to the procedure and placed in the parameter list. The program counter proceeds to execute the blocks in the procedure, referring to the parameter list but really working with the variable notes.
Because of the parameter, the procedure displayList can now be used with any list, not just notes. For example, if the Note Taker app was shared among a list of users and you wanted to display the list, you could call displayList and send it the user List, as shown in Figure 21-11.
Figure 21-11. The displayList procedure can now be used to display any list, not just notes

Returning Values from a Procedure

There is still one issue with the displayList procedure in terms of its reusability-can you figure out what it is? As it's currently written, it can display any list of data, but it will always display that data in the label NotesLabel. What if you wanted the list to be displayed in a different user interface object (e.g., you had a different label for displaying the userList)?
One solution is to reconceptualize the procedure-to change its job from displaying a list in a particular label to simply returning a text object that can be displayed anywhere. To do this, you'll use a procedure result block, shown in Figure 21-12, instead of the procedure block.
Figure 21-12. The procedure result block
You'll notice that, when compared to the procedure block, the procedure result block has an extra slot at the bottom. You place a variable in this slot and it's returned to the caller. So, just as the caller can send data to a procedure with a parameter, a procedure can send data back with a return value.
Figure 21-13 shows the reworked version of the preceding procedure, now using a procedure result block. Note that because the procedure is now doing a different job, its name is changed from displayList to convertListToText.
Figure 21-13. convertListToText returns a text object that the caller can place in any label
In the blocks shown in Figure 21-13, a variable displayText is defined to hold the text as the procedure iterates through each item of the list. This text variable replaces the overly specific NotesLabel component that was previously being used. When the foreach completes, the variable displayTextcontains the list items, with each item separated by a newline character, \n (e.g., "item1\nitem2\item3"). This displayText variable is then plugged into the return value slot.
When a procedure result is defined, its corresponding call blocks look different than those for a procedure. Compare the call to listToText with the call to the displayList in Figure 21-14.
Figure 21-14. The call on the right returns a value and so must be plugged into something
The difference is that the call listToText has a plug on the left. This is because when the call is executed, the procedure will run through its task and then return a value to the call block. That return value must be plugged into something.
In this case, the callers to displayList can plug that return value into any label they want. For the notes example, the three event handlers that need to display a list will call the procedure as shown in Figure 21-15.
Figure 21-15. Converting the list notes into text and displaying it in NotesLabel
The important point here is that, because the procedure is completely generic and doesn't refer to any lists or labels specifically, another part of the app could use listToText to display any list in any label, as exemplified in Figure 21-16.
Figure 21-16. The procedure is no longer tied to a particular Label component
Reusing Blocks Among Apps
Reusing code blocks through procedures need not be restricted to a single app. There are many procedures, like listToText, that could be used in just about any app you create. In practice, organizations and programming communities build up code libraries of procedures for their domains of interest-for example, a code library of animation procedures.
Typically, programming languages provide an "import" utility that allows for including library code in any app. App Inventor doesn't yet have such a utility, but one is being developed. In the meantime, you can create procedures in a special "library app" and begin new app development by saving a new copy of that app and working from it.
A Second Example: distanceBetweenPoints
With the displayList (listToText) example, we characterized procedure definition as a way to eliminate redundant code: you start writing code, find redundancies as you go along, and refactor your code to eliminate them. Generally, however, a software developer or team will design an app from the beginning with procedures and reusable parts in mind. This sort of planning can save you significant time as the project progresses.
Consider an app to determine the local hospital closest to one's current location, something that would come in very handy in case of an emergency. Here's a high-level design description of the app:
 When the app launches, find the distance, in miles, between the current location and the first hospital. Then find it for the second hospital, and so on. When you have the distances, determine the minimum distance and display the address (and/or a map) to that location.
From this description, can you determine the procedures this app needs?
Often, the verbs in such a description hint at the procedures you'll need. Repetition in your description, as indicated with the "so on," is another clue. In this case, finding the distance between two points and determining the minimum of some distances are two necessary procedures.
Let's think about the design of the distanceBetweenPoints procedure. When designing a procedure, you need to determine its inputs and outputs: the parameters the caller will send to the procedure for it to do its job, and the result value the procedure will send back to the caller. In this case, the caller needs to send the latitude and longitude of both points to the procedure shown in Figure 21-17. The procedure's job is to return the distance, in miles.
Figure 21-17. The caller sends four input parameters and receives a distance
Figure 21-18 shows the procedure we encountered at the start of the chapter, using a formula for approximating the mileage between two GPS coordinates.
Figure 21-18. distanceBetweenPoints procedure
Figure 21-19 shows blocks that make two calls to the procedure, each of which finds the distance from the current location to a particular hospital.
For the first call, the actual parameters for point1 are the GPS coordinates for St. Mary's Hospital, while point2 uses the current readings from the LocationSensor. The result value is placed in the variable distanceStMarys. The second call is similar, but instead uses the data for CPMC Hospital for point1.
The app goes on to compare the two distances returned to determine which hospital is closest. But if there were more hospitals involved, you'd really need to compare a list of distances to find the minimum. From what you've learned, can you create a procedure called findMinimum that accepts a list of numbers as a parameter and returns the index of the minimum?
Figure 21-19. Two calls to the distanceBetweenPoints procedure
Summary
Programming languages like App Inventor provide a base set of built-in functionality. Procedures let app inventors extend that language with new abstractions. App Inventor doesn't provide a block for displaying a list, so you build one. Need a block for computing the distance between GPS coordinates? You can create your own.
The ability to define higher-level procedure blocks is the key to engineering large, maintainable software and solving complex problems without being constantly overwhelmed by all of the details. Procedures let you encapsulate code blocks and give those blocks a name. While you program the procedure, you focus solely on the details of those blocks. But in programming the rest of the app, you now have an abstraction-a name-that you can refer to at a high level.