To set up for this example, at the top of ol_demo2.s, make sure that you have "initlist = ships_initlist". Assemble and run the code. You should see a nice background warpy layer (which is generated by using the blue-and-white source tile from the last example, and running it through ol_warps.s subtype 02, which is a fast warper, using the same innerloop developed in the optimization example), on top of which there are a number of spaceships, and a little character display showing the current joystate. Move the joystick and press the primary FIRE button, and you should see that all the ships have their own handling characteristics. The objective of the next set of examples is to show how to use the Command String to encode joystick-responsive behaviour into an Object.
First off, let's have a look at the simplest of the objects, the yellow, cross-shaped cursor that looks a bit like the aiming cursor out of Atari Star Wars, and makes a person think how nice it'd be to do a quick port of that game to Merlin with all these lovely antialiased lines. This cursor maps the analog joystick position directly to the screen position, and its definition is really simple:
; ; cursor1.moo = a MacrOObject that ; defines a simple cross cursor attached to the joystick. curs1: ; header .dc.s 0 ;Prev .dc.s 0 ;Next .dc.s $2000000 ;2 long secondary data .dc.s 0 ;Address of parameter block if not local .dc.s 0 ;Address of ranges table, if not local .dc.s 0 ;this'll be where the command string is, if not local .dc.s lineobj ;prototype to use .dc.s 0 ;not external secondary data .dc.s curs1_end-curs1 ;length .dc.s 0,0,0 .dc.s 0,0,0,0So far so bog-standard. A couple of longs of secondary data are used to hold a couple of consts, iz all.
; Ranges table .dc.s -$20 .dc.s $188 .dc.s $120,0 .dc.s 0,0,0,0 .dc.s 0,0,0,0 .dc.s 0,0,0,0An almost virgin ranges table, only the first three entries are defined.
; Secondary data .dc.s cursor1 ;Address of polyline definition .dc.s $00200010 ;ScaleAnd here are those couple of consts - the address of the polyline def of the cursor, and the scales.
; Command string .ascii "_a=h" ;set address of polyline in object .ascii "_b=e" ;set scale .ascii "@x[01]=a<" ;set xpos from stick .ascii "@y[02]=a>:" ;set ypos from stick and end. .align.v curs1_end:And here's the nub of the matter, the command string. The first two statements are pretty bog-standard, setting that address and pair of scales. The new stuff is in the last two lines, and it's really simple: "@x" refers to the X-axis of the joystick, and "@y" to the Y-axis (the "@" kinda looks like a little joystick viewed from above, if you have smoked enough Arcturan Narco-Weed or been staring into feedback for too long). Evaluating "@x" or "@y" returns a value scaled to the same range as a real waveform, with the most negative being the low extreme of the joystick travel on that axis, and the most positive being the high extreme. Because it's just like a waveform value, you can go ahead and map the joystick onto a range by just following the "@x" with the usual ranging command ("[01]" or "[02]" in this example). All we do next is just ram the result into the X and Y position of the cursor object, and Bob's your dingbat!
The motion of the object attached directly to the joystick position looks a bit jumpy, since the resolution of the screen is actually greater than that of the analog stick. To smooth it out, one needs to use the stick to act on the velocity of an object, rather than directly on the position. Consider the other, pink, cross-shaped cursor. Using the joysiick, you can smoothly alter its velocity in any direction. Its object definition is in cursor2.moo. The header is unremarkable, so I'll just show the naughty bits:
; variables .dc.s cursor1 ;Address of polyline definition .dc.s $71deca00 ;Colour .dc.s $00100010 ;Scale .dc.s $0I am using a dummy variable to hold a few constants. I think this is because this example was written before I implemented secondary data space.
.dc.s $b00000 ;pos .dc.s 0 ;vel .dc.s $10000 ;fr .dc.s $80000101 ;lim, type etc. .dc.s $780000 ;pos .dc.s 0 ;vel .dc.s $10000 ;fr .dc.s $80000102 ;lim, type etc.Two positional variables.
; ranges .dc.s 0 .dc.s $1680000 ;max X .dc.s $f00000 ;max Y .dc.s -$180000 ;min velocity .dc.s $180000 ;max velocity .dc.s $20000 .dc.s $00 .dc.s $000 .dc.s $20 .dc.s 0,0,0,0,0,0,0The interesting bits of the ranges table are entries 1 and 2 (the maximum X and Y boundaries) and 2 and 3 (the minimum and maximum velocity).
; command .ascii "A0=h" ;set address of polyline in object .ascii "A1=c" .ascii "c=d" ;set colour .ascii "A2=e" ;set scale .ascii "@x[34]=B1" ;set xvel from stick .ascii "@y[34]=C1" ;set yvel from stick .ascii "@x[05]=g" ;check it out! .ascii "B0!=a<" ;set xpos to int b-pos .ascii "C0!=a>:" ;set ypos to int c-pos, end.The first part of the command string just sets up some constants from the values stashed in the dummy variable. The "@x[34]=B1" translates to "map the X-axis of the joystick onto the range defined by ranges(3) and ranges(4), and jam the result into the velocity part of B". Since B is the X positional variable, this allows the joystick to directly control the X-position of the object. The following statement does the same for the Y-axis of the joystick and the Y-positional variable. I'll leave it up to you to see what the second statement referring to "@x" is doing! Finally, the last two statements get the integer parts of the position from the position variables, and bungs it into the position long of the OLR definition.
Cursors are all well and funky, but ships are much more interesting. Creating a ship using the command string is a little more complex, because although it is easy enough to map the angle of rotation of the ship-object onto a joystick axis, it is slightly more complex to make it move in the correct direction! We'll take a look at this in depth in the next example.