Tower Unite

Tower Unite

80 ratings
Official Guide: Laser Expression Editor Walk-through
By MacDGuy and 2 collaborators
This guide will cover the basics of the Laser Projector expression editor and how to use its various functions! It's an exciting guide filled with drama, betrayal, brotherhood, power, and other names for sadness.
Brief Overview of the Laser Expression Editor
The laser expression editor allows you to write math expressions to control the projection pattern on the laser projector.
Expression Reference
The outputs are the parameters that control the look and behaviour of each individual beam. This includes where they point at, as well as their colours. Be sure to define each of the following outputs in your expressions.
The output horizontal coordinate of the laser beam, ranging from -100 (left) to 100 (right).
The output vertical coordinate of the laser beam, ranging from -100 (down) to 100 (up).
The beam hue, ranging from to 360°. This value is wrapped, so the value is always remapped to this range. 0 means red, 120 means green, and 240 means blue. All values inbetween are interpolated, so you can pick any colour in the spectrum.
The beam saturation, ranging from 0 to 1. 0 results in a white beam, and 1 results in a fully saturated colour.
The beam value (brightness), ranging from 0 to 1. 0 results in the beam being invisible, and 1 results in a fully visible beam.

These are parameters that you can feed into the output expressions. Some of the parameters give an indication of which laser beam it is, while others can be used to cause the beams to move dynamically.
The input horizontal coordinate taken from the projection base (shape or grid), ranging from -100 (left) to 100 (right).
The input vertical coordinate taken from the projection base (shape or grid), ranging from -100 (down) to 100 (up).
The unique number associated with the current beam. The index on the first beam is 0, and the last beam equal to the number of beams minus 1.
The total amount of laser beams in the current projection. In most shapes this is equal to 32.
This is equal to the index of the beam divided by the total amount of beams.
Two times pi. Useful for quickly converting radians per second to Hertz, when using functions such as sin(), cos(), and tan().
The current time, in seconds, on the local system (your computer).
The time, in seconds, since the expression was activated.
The local time, in seconds, when the expression was activated.

Returns the sine of 'angle'.
Returns the cosine of 'angle'.
Returns the tangent of 'angle'.
Returns the arcsine of 'float'.
Returns the arccosine of 'float'.
Returns the arctangent of 'float'.
atan2(<x>, <y>)
Returns the arctangent of 'y'/'x' with consideration for divide-by-zero edge cases.
Returns the square-root of 'float'.
Returns the smaller value of 'a' or 'b'.
Returns the larger value of 'a' or 'b'
Returns the value 'float' rounded down to the nearest whole number less than 'float'
Returns the value 'float' rounded up to the nearest whole number greater than 'float'
Returns the value 'float' rounded to the nearest whole number.
Returns the absolute value of 'float' ('float' < 0 ? -'float' : 'float').
Returns a random number between 0.0 and 1.0.
if(<float>, <a>, <b>)
Returns 'a' if 'float' is 1 or greater otherwise returns b.
lerp(<frac>, <a>, <b>)
Interpolates between 'a' and 'b' using 'frac' (a*frac + b*(1-frac)).

Maths and logic. What more is there to say?
Equal. Assigns the value of the right operand to the left operand. You can use this to declare your own variables.
Add. Returns the sum of the left and right operands.
Subtract. Returns the left minus the right operand.
Multiply. Returns the product of the left and right operands.
Divide. Returns the left divided by the right operand.
Exponent. Returns the left operand to the power of the right operand.
Modulo. Returns the remainder of the left operand divided by the right operand.
Less than. Returns 1 when the left operand is less than the right, otherwise returns 0.
Greater than. Returns 1 when the left operand is greater than the right, otherwise returns 0.
Less than or equal. Returns 1 when the left operand is less than the right, otherwise returns 0.
Greater than or equal. Returns 1 when the left operand is greater than the right, otherwise returns 0.
Equal to. Returns 1 when the left operand is equal to the right, otherwise returns 0.
And. Returns 1 if both the left side and right side are true.
Or. Returns 1 if either the left side and right side are true.
Not. Returns 1 if the expression is false and 0 if the expression is true (inverts the value).
Comment. Allows you to put plain text behind it, without getting compiled.
Example Expressions
Simple sine wave
A sine wave is added to the vertical output component of the projector.
#wave parameters: phase = tau*time; #wave movement (1 cycle per second) frequency = 0.05; #wave width amp = 10; #wave height #output: x' = x; y' = y + amp * sin( frequency*x + phase );

Scales the shape up and down instantaneously.
#cycle duration in seconds rate = .2; #wrap time to cycle duration (ramainder of time / rate) wraptime = time % rate; #'>' operator gives 1 if wraptime > rate/2, otherwise 0 isscaleddown = wraptime > rate/2; #do scaling scaledownamount = .5; scale = 1 - isscaleddown * scaledownamount; #output: x' = x * scale; y' = y * scale;

Color wheel
Changes the color of each laser based on its angle from center.
#atan2 returns the angle between 0,0 and y,x #atan2's range is (-pi,pi], here we convert to (0, 1] #we first divide by 'pi' to give us the range (-1, 1] #then we add 1 to get (0, 2] #finally, we divide by 2 to get (0, 1] diskposition = ( 1+atan2(y,x)/pi ) / 2; #scale diskposition by 360 for hue output: colordisk = diskposition * 360; #add time to get the disk rotating #200time is a shortcut for 200 * time: huerot = colordisk + 200time; #output: x' = x; y' = y; h = huerot; s = 1;
Advanced Expressions
3D Rotation
Rotates (x, y, z) by angles (rx, ry, rz)
You can use z' to simulate depth in any way you like.
#projector doesn't have a z value, make one up or set to 0 z = 0; #rotation around each axis: rx = time; ry = time/2; rz = time/4; #cosine and sine values for each rotation axis: cx = cos(rx); sx = sin(rx); cy = cos(ry); sy = sin(ry); cz = cos(rz); sz = sin(rz); #result vector: x' = x*(cz*cy) + y*(cy*-sz) + z*sy; y' = x*(-sx*-sy*cz+sz*cx) + y*(-sx*-sy*-sz+cx*cz) + z*-sx*cy; z' = x*(cz*cx*-sy+sz*sx) + y*(-sz*cx*-sy+cz*sx) + z*cx*cy;

Waving three-colour flag
Be a nationalist.
#first we define the three colors: h1 = 0; s1 = 1; v1 = 1; #red h2 = 0; s2 = 0; v2 = 1; #white h3 = 240; s3 = 1; v3 = 1; #blue #masks for each stripe: mask1 = y > (100/3); mask2 = (y < (100/3)) * (y > (-100/3)); mask3 = y < (-100/3); #wave stuff: angle = (time + fraction * 18) * tau; #output: x' = x + sin(angle) * 4; y' = y + cos(angle) * 4; h = h1 * mask1 + h2 * mask2 + h3 * mask3; s = s1 * mask1 + s2 * mask2 + s3 * mask3; v = v1 * mask1 + v2 * mask2 + v3 * mask3;

Analog Clock
A clock!
# Construct 3 linearly increasing waves, one for each hand extent = (fraction % (1/3)) * 100; # Convert the seconds to radians on a clock angle = -floor(time) * pi * 2 ; # Calculate the angle of each hand secondAng = angle / 60 + pi/2; minuteAng = angle / (60^2) + pi/2; hourAng = angle / (60^2 * 12) + pi/2; # Plot out the lines for each clock hand secondX = cos(secondAng) * extent; secondY = sin(secondAng) * extent; minuteX = cos(minuteAng) * extent * .8; minuteY = sin(minuteAng) * extent * .8; hourX = cos(hourAng) * extent * 0.5; hourY = sin(hourAng) * extent * 0.5; # Choose the colors for each of the hands secondH = extent; minuteH = 100 + extent; hourH = 200 + extent; # Check if the current beam should be a part of the second, minute, or hour hand isSecond = fraction < (1/3); isMinute = if(isSecond, 0, fraction < (2/3)); # Select the position based on the criteria above x' = if(isSecond, secondX, if(isMinute, minuteX, hourX)); y' = if(isSecond, secondY, if(isMinute, minuteY, hourY)); # And the same for the color h = if(isSecond, secondH, if(isMinute, minuteH, hourH)); s = 1; v = 1;

A rainbow tornado
size = 500; # Plot the tornado points in 3d sidx = index * 0.15; spin = sidx + (time / (sidx ^ 1.2)) * 50; heightRand = (sidx ^ 0.6) * 10 -sin(sidx * 10000) * 8; xp = cos(spin) * sidx; yp = heightRand; zp = sin(spin) * sidx + 500; xp = xp + sin(sidx/10 + time) * 10; zp = zp + cos(sidx/10 + time) * 10; x' = xp; y' = yp + 100; z = zp; x' = x' * size / z; y' = y' * size / z - 145; h = -time*100 + fraction*350; v = 2.5 - z/300; s = v;
< >
Pythva Jun 16 @ 4:23pm 
Can you add this color changing beam code?

rate = 10000;

wraptime = time % rate;

x' = x
y' = y
h = wraptime * 170;
s = 1;
v = 1000;
Krystal Disc Feb 1 @ 6:49pm 
Where do I put the code?
Pigeon Dec 14, 2017 @ 8:56am 
How can I make the loss meme in this becouse I don't understand a single thing. :slimehungry:
OwnedMyBe Nov 19, 2017 @ 3:47am 
how can i write R A K U N with lazer, can someone teach me
Left_Gangster Oct 6, 2017 @ 4:38pm 
Are there bugs or something? When I try to do this "y'=y+time" nothing happens.
Zak  [author] Oct 1, 2017 @ 7:33pm 
Expression reference updated to reflect new features.
Added some advanced expressions created by Foohy.
✯Radek Oct 1, 2017 @ 10:21am 
oh well that will take me some time to comprehend
POMP Sep 24, 2017 @ 5:56am 
thank you for the awnser! i was wondering if you are ever planning to add a system where it projects what you draw and stuff?
Kesh Sep 24, 2017 @ 12:28am 
Should make it interact with various sound components, so you could make something like an oscilloscope, as a DJ light or something like that. Would work beautifully with a couple smoke machines, dim lights and a sick ass synth lead, lol
Zak  [author] Sep 19, 2017 @ 8:01am 
@Chef: the laser projector dots are gone temporarily because we has to restructure the component. We're adding new rendering code to make the dots more efficient soon.