Figure 11. Theory 423 Scripting Assignment #2

Fun With Numbers

We are going to create a stack that uses arithmetic calculations within repeat loops to move buttons around the screen. First, we will give you background information, then we will write scripts that move buttons in one direction only (horizontally or vertically), and then combine this information to move along a straight line between any two points.

READ: Goodman, Chapter 44 (Operators): carefully read pp. 809­814 (arith. operators), scan p. 817­825 for general familiarity, and read pp. 825­826 (precedence).


Suppose we want to calculate n equally spaced "steps" along a line from point A to point B.

1. The distance D from point A to point B is calculated by subtracting A from B. For our purposes, we will be measuring D in pixels. (Remember, the standard card width is 512 pixels and its height is 342 pixels. These are often given as x, y coordinates; the upper left-hand corner of the screen is 0,0 and the bottom right-hand corner is 512, 342.) We want to move along this line in n "steps."

2. If there are n points along this line, the fraction F of the distance D at any point i, is (i / n) * D. Thus when i is 0, F is 0/n * D ( = 0); when i = n, F is (n / n) * D (= 1 * D = D). At any arbitrary point i, the distance traversed is (i / n )* D. As a concrete example, imagine that point A is 0 and point B is 100; thus the distance (D) from A to B is 100 pixels, and that we want 10 steps (n) along this line. The step number, i , will vary from 0 to 10. At the beginning, when i = 0, the portion of the distance traversed is (0/10) * 100 (= 0); after the first step it is 1/10 * 100 (= 10 ); after the second step it is 2/10 * 100 (=20). After 10 steps whole distance has been traversed: 10/10 * 100 (= 100).

3. Since the starting point A usually isn't 0, the actual point P (where P is between A and B) is the partial distance F (which we calculated above) added to starting point A.

Let's take a simple example: Point A is 10, B is 30, and the number of steps n is 10:

The distance (D) from 10 to 30 equals 20. At the beginning of the line (i = 0) we are at point 10 [(0/10) * 20 + 10]. At point 1 we are at 12 [(1/10) * 20 + 10]; at point 5 (half way there) we are at point 20 [(5/10) * 20 + 10], and so on. The last point (point 10) is (10/10) * 20 + 10 = 30. Plug some numbers into these equations and satisfy yourself that this is true, even if point A is greater than point B, i.e., we are going in a negative direction.

Task 0 -- Warm-Up; Trying It Out

We will now write a handler to test the simple math described above. Create a new stack, and set the userlevel to 5. Place the following handler in the background script of the stack (remember that you get the background script via option-command-B):

----------------------------   calc  ------------------------------
-- Calc calculates n points on the straight line between points  --
-- a and b. Note that round(<expression>) rounds <expression> to --
-- the nearest integer (whole number value). The values are      --
-- written into the message box so we can see them.              --
on calc a, b, n
  put a into message
  put b - a into difference
  repeat with i = 1 to n
    put round((i / n) * difference + a) into newvalue
    put " " & newvalue after message
  end repeat
end calc

Now create a button called "Try Calc" and put the following into the button script:

------------------  Script for button "Try Calc"  ------------------
-- Asks for two points and the number of steps, then passes these --
-- values to the calc handler                                     --
on mouseUp
  ask "Point A" with "10"
  put it into startpoint
  ask "Point B" with "30"
  put it into endpoint
  ask "How many steps?" with "10"
  put it into steps
  calc startpoint, endpoint, steps
end mouseUp

Test the button and the calc handler by clicking on the button, entering numbers, and examining the results in the message box.

Hint: The font characteristics of the message box can be set just like a field or button. If you want to see more information in the message box, enter the command "set the textsize of message to 9" in the message box.

Task 1 - Moving Sideways

Now we are going to use our new skills to create "button animation." First use the button tool to make a new button called "x". Make it fairly small and roughly square, set its style to shadow, and disable it. We are now going to write scripts to make the button move. The handler moveh will move the button horizontally (from left to right or vice versa).

Recall that locations in HyperCard are given as comma separated values, e.g., '20,30', and that item 1 is the first value and item 2 is the second value. Add the following handler to the background script, replacing <expression> with the appropriate arithmetic expression to calculate the new value, based on the arithmetic we reviewed on page 1:

----------------------------- moveh -------------------------------
-- This handler moves the a button or field (obj) horizontally   --
-- to point "newloc", using "n" steps. The second part of        --
-- "newloc", the y co-ordinate, is ignored. Note that a point is --
-- expressed as (x,y); item 1 is the x value, and item 2 is the  --
-- y value. Replace <expression> with the correct arithmetic     --
-- expression                                                    --
on moveh obj, newloc, n
  put item 1 of loc of obj into firstx
  put item 2 of loc of obj into yvalue
  put item 1 of newloc into lastx
  put lastx - firstx into xdifference
  repeat with i = 1 to n
   put <expression> into xvalue
   set the loc of obj to xvalue,yvalue
  end repeat
end moveh

Test this handler in the message box by entering lines such as

moveh "cd btn x", "256,200", 10

in the message box. (For now, type just as shown above-don't put quotes around "x"). Note that the first two arguments to moveh must be in quotes. For the command shown just above, the moveh handler will use "cd btn x" as the value of obj, "256,200" as the value of newloc, and 10 as the value of n.

Now, make a new button named "horizontal" and put the following handler into its button script:

on mouseUp
  ask "New Location" with the loc of cd btn "x"
  put it into newloc
  ask "How many steps" with "10"
  put it into steps
  put "card button" && quote & "x" & quote into object
  moveh object, newloc, steps
end mouseUp

When you click on the "horizontal" button, this handler will ask you for a new location and then move card button "x" to this location. Note that the handler uses the current location of the card button as the "default" value. Now test the "Horizontal" button and the "moveh" handler to be sure that they work properly. Note: if you move the button off of the card, just click on "horizontal" again, and enter more reasonable values for the new location.

Task 2 -- Moving Up and Down

In the background script, make a copy of the moveh handler (select the text, then command-c to copy and command-v to paste). Name the new handler "movev" (for move vertical). Remember to use change the last statement to "end movev" as well. Modify the handler to make it move the button in the vertical direction using the second (y) values and ignoring the first value (x).

Test the handler in the message box. After you get it working correctly, copy the "horizontal" button, rename it "vertical" and modify the button script of the new button so that it calls "movev" instead of "moveh."

Task 3 - Going "around the corner"

Make another copy of the "Horizontal" button, name it "MoveX". The script of this button should call both moveh and movev to place button "x" in a new location using a "city-block" route, i.e., getting to the new location by going around the corner.

Task 4 - The Direct Route

Write a final version of the handler (on move ... end move) in the background script, that moves an object in a straight line to its new location.

This handler will combine elements of moveh and movev, i.e., for each point i, it will calculate a new xvalue and a new yvalue, and then set the loc of the button to (xvalue,yvalue). Test the handler in the message box, then make a card button that calls this handler to move card button "x". Note that since we defined the handlers with parameter "object" instead of using card button "x", you could use it to move any button or field to a new location. Experiment with this if you have time. Since the scripts are in the background, you can call them from other cards if you need more room to experiment.

Extra Credit

If you have had lots of previous experience or you found the above easy, feel free to design another task of your own that uses the techniques learned in this assignment.