Coronavirus (Covid-19): Latest updates and information
Skip to main content Skip to navigation

Lab 2 Exercises

Today's lab will involve constructing a model of a lift. (This will be topical in connection with the next lecture.) We will be working entirely in DASM, with the cloning and construction of objects as well as animation being the key focus. Some supplementary notes relating to the Lab exercises can be found here.

Begin by loading up a blank environment with a window to work in by invoking Cadence:

~empublic/bin/cadence

and loading the WGD library module from the DASM input window:

%include "wgd/wgd.dasm";


Objects, Prototypes and Cloning

The first thing you might wish to do when making a lift model is make a lift and place it on the screen. The best way to do this is to take some existing object that is similar to what we want and then change it a bit. For this purpose there are some prototype objects that are incomplete but provide a template. Prototypes already exist for image objects and we have provided an image called 'lift.png' so all we need to do is make a clone of that prototype and make a few changes.

@lift = (new union (@prototypes image)
    filename = "liftPope2009/lift.png"
    x = 100
    y = 100
    width = 100
    height = 100
);

What we have done here is make a new object, combine that with an existing image object and then change a few parameters. 'union' is what does the copy of everything in the object on the right-hand-side to the object on the left. You can chain several unions together to combine lots of objects. x and y give the position on the screen of the top left corner of the image in pixels (as measured from the top left corner of the screen). Now let's put this on the screen:

@screen = (.widgets root children);
@screen mylift = (@lift);

At this point, you can change the focus of the browser, as in Lab 1:

@ui browser root = @screen;

We have also provided an image called 'floor.png'. It is possible to clone the lift to make a floor:

@screen floor1 = (new union (@lift)
    filename = "liftPope2009/floor.png"
    x = 200
    width = 400
);

Now clone this floor and change y to make 4 other floors. It would be a good idea to give y a definition such that each floor is always below the other.


Making the Lift Act Like A Lift: Animation

Since we are making a lift we would like it to be controlled and behave like a lift. So instead of having to worry about its pixel position we simply want to control which floor it is on. This can be done by giving y a definition that depends on some floor observable by converting a floor into pixels. There are a few ways to do this but try the following first and see if you can think of a better way:

@lift offsety = 100;
@lift floor = 0;

The observable '@lift floor' is intended to specify which floor the lift is currently at.  It needs to determine the position of the image of the lift correctly. We need to work out the pixel location of each floor:

@lift floor_pix is { 400 - (.floor * 100) + (.offsety) };

To locate the lift image at the appropriate floor, use:

@lift y is { .floor_pix };

offsety is used to give the distance the top floor is from the top of the screen (you could give this a definition to actually link it with the top floor's position). Now try changing the value of floor to check that the lift jumps around correctly. Let's try and get this more realistic before adding buttons and doors. What we really need is for the lift to move smoothly at a certain speed between floors instead of teleporting.

So when floor is changed the lift will need to move up or down at a certain speed until it reaches that floor. Eventually this will involve modifying the definition of y but first we need to know things like desired speed, direction and whether it has arrived at the floor or not:

@lift speed = 20.0;

Has it arrived at the floor?:

@lift atfloor is {
    .y < (.floor_pix + 2) and (.y > (.floor_pix -2))
};

Something else we need to know is the direction the lift should move in:

@lift direction is {
    if (.y < (.floor_pix)) {1.0} else {-1.0}
};

Finally, we can now re-define y using the above to make it move smoothly between floors:

@lift y := {
    if (.atfloor not) {
        ..y + (..direction * (..speed) * (@root itime))
    } else {
        ..y
    }
};

Try this out by changing the floor observable. Also try changing floor before it has reached the floor you last sent it to and see what happens. Each individual definition above has been kept small because of the way it has been split up into several smaller and meaningful observables. The similarity to spreadsheet modelling can be seen with this example. The most important definition to understand is the final one for y. This 'willbe' definition refers to itself but what it is actually doing is refering to the last known value of itself and then using that in a formula to calculate its next value. Such a definition will update constantly as fast as the machine can do it because one of the things it depends on will always change (viz. itself). For this reason we use itime which is the time in seconds between each update cycle so that we can control how fast it appears to move independent of how fast the machine is.

A more advanced exercise: Extend the Lift Model

Extend the model to include buttons on each floor and 5 buttons in the lift. Come up with definitions for floor which decide, based upon which buttons have been pressed, which floor to go to next. You may also want to add doors and people.

In preparation for this exercise, it is useful to inspect the code for the 'dial' button that features in the Stargate model you studied in Lab 1. To this end, close Cadence, then restart and load the Stargate model. Things you should seek out are the observables that correspond to the mouseover and mousedown conditions for the dial button, and the observables associated with  the mouse. You can find these by looking in the context ' .widgets  root chidren cam1 children' and the context '.input' respectively. If you open these contexts in the browser, you will be able to observe directly how these observables are changed when the mouse is used.

In extending the lift model, you can set up a button that can respond to mouse clicks by using the following definition:

@screen button_1 clicked is { .mouseover and (@mouse buttons left) };

This definition expresses the fact that the mouse button at floor 1 is being clicked. You will also need to consider how to create an observable to reflect the fact that the mouse button has been clicked. A 'willbe' definition is useful in this connection.

Experiment and ask questions.