Kurzinfo

# Thyme startup

We were asked to give some useable Thyme wiki in the Algodoo-Forum forum11139. This is a quickly compounded work, so please dont expect too much, though i have an open ear on your requests for concrete questions in this Forum-thread.

To get into, start algodoo, create an object, like a circle, right-click on it, choose the last line (scriptmenu) and the scriptmenu is opened: You see a lot of properties of that circle, like its position pos, velocity vel, angle, anglevelocity angvel, color, density, restitution, radius, attraction, friction, refractiveIndex, reflectiveness, collideSet. All these values you can change with your thyme-script!

And more to it, you can code under which conditions these values should be changed.

## How to write a script

There are several ways to write a script, but for simplicity we do an example only for the most easy method. Other methods are using the top left corner of the scriptmenu, using the Function-key F10 to open the console, or hacking the .phz file.

So, let us make some breathing circle out of the simple circle: into the curly brackets of update in the scriptmenu, type in: radius = 0.2 + 0.1 * sin(sim.time)

so that the black region behind update reads now:

``` (e)=>{
radius = 0.2 + 0.1 * sin(sim.time)
}
```

and start the simulation with a click on the green triangle. The circle breathes in and becomes bigger, then it breathes out and becomes smaller, then the process repeats again and again. How did it work? The time elapsed in the simulation is contained in the variable sim.time, and the mathematical function sin converts this into a smoothly alternating value between -1 and +1. Finally the radius changes this way between 0.1 and 0.3, as i added the offset of 0.2 to make sure that the radius is allways positive.

### Exercise 1: attract and repulse

Try on your own to make other objects beeing attracted or repulsed by your circle. Hint: deactivate gravity by click on red apple, fix the circle with Fixation (F) and add small other circles. Add to your existing script a ; (colon) and in the next line attraction=sin(sim.time), so update reads then:

``` (e)=>{
radius = 0.2 + 0.1 * sin(sim.time);
attraction=sin(sim.time)
}
```

To prevent the small balls from fleeing out of range, you can add some barriers around your visible area of the scene.

### Exercise2: change color

Try to change the color with

``` color = [0.5 + 0.5 * sin(sim.time), 0.0, 0.5 - 0.5 * sin(sim.time), 1]
```

How does it work? color consists of [red,green,blue,visibility]. If visibility is 0, its translucent, here it's 1 all the time. The green value stays 0 all the time, but red and blue vary from 0 to 1 and 1 to 0 respectively.

Your script didnt work? Did you make sure to have a colon ( a ; ) at the end of each line, except the last line of script?

## React with a script

onClick is activated if the user klicks on it with the mouse.

onSpawn is done at the creationprocress of the whole scene at the startup, at time 0.

onDie is executed when the object is deleted, his last action, like a testament, last will.

onCollide whenever an other object hits this object.

onHitByLaser when a laser hits the object.

Events (e) that consist of two partners like a collision seem to have the same variable-structure: to access values you will have to do

e.this.property to get the property of the same object where the script is executed and

e.other.property to get the ones of the interaction-partner.

## Do things on each simulation step

I think there are several simulationsteps done until one update of the picture happens. so if you want to get sure to perform the script at each little step, then use poststep.

## Your own variables and functions

These are specially usefull for controlling and setting relationships and reactions, which are not built in. You will find them in 99% of the algodoo models which use thyme.

### scene.my. namespace

To make variables, which have the same value in all objects of your scene, you must make them "global". Declare them once after pressing F10 to enter the console by typing for example

```sence.my.a3
```

and if you want to take its value e.g. for the strength of a truster, then in the thruster-script you write into the postscript-section of the thruster

``` (e)=>{
force = scene.my.a3
}
```

If you have an other thruster somewhere else and you want to have it the double strength of your first thruster, then you can enter in its postscript

``` (e)=>{
force = 2 * scene.my.a3
}
```

Not only variables can be declared but also functions, as it is done in the section "Loops for i=1 to 10 do... end" below.

### local variables and functions

Why does it make sense that objects have their own variables, instead of just using the scene.my....? To understand it, i will describe in detail a functionality, where this is very usefull: Think of a bumper in pinball, like in Xray's scene 86013. It should push away the ball, that hit it, so its restitution shall be 2.5, so it runs away with 2.5 times more velocity after hitting it. But the bumper needs a certain time (say: 0.5 seconds) to recharge its power until it is ready for the next usage, and while it is loading, it should not bump hard, but just reflect, so its restitution shall be 1.0 in that case. So the logical structure would be:

``` is the bumper ready to bump? If yes, then { restitution = 2.5; } If not, then { restitution = 1.0}
```

The time, where the last bump has happened, needs to be saved, so you can compare this with the actual time "sim.time" so you set the local variable _timer=sim.time in case of bumping. Note that there is an "underscore", a "_" at the beginning of this variable, wich makes it permanent even if you end the whole scene and reload it later. To decide now if the bumper is ready, you just compare the actual time with the _timer +0.5 like in

``` sim.time > _timer + 0.5
```

and if it is true, you do the bump, else not. So far, so good... you could do all this with a global variable scene.my.timer as well. BUT, and here comes the usefullness of local variables to its full extent: You dont wish only one bumper in your scene, but 8 bumpers. So after you coded the script for the original bumper, you wish to copy the whole bumper-object and just make 7 copies of it. But note that each bumper needs his own recharging time now, just like in real life. So if you do it with global variables, you had to change in every bumper the name of the variables e.g. scene.my.timer2 for the second bumper, scene.my.timer3 for the third bumper, etc. etc. at each usage of the variable. This would work too, but it it is MUCH WORK. Instead, if you use the local variable _timer instead, you can just copy and paste and no need to alter any script, the different bumpers then have all different local variables availlable with different values at the same time automatically! The complete script for this bumper-recharging-time is listed below in the section "Control-structures".

Not only variables can be local, but also functions, which was used in noonans scene 124016, where he declared

``` _abs:=(x)=>{ x < 0 ? {-1.0 * x} : {x}}
```

to have f(x)=|x| =abs(x) availlable in his hinge-script where he used that more often, to get positive numbers.

## Destroy an object

If you set the density of an object to NaN ( Not a Number) , it vanishes! This is not a clean code though, as it will not free the storage-space, but it works, and of you dont destroy and create more then 1000 objects, you dont have to bother at all about storage-space. Clean code will be described in the sophisticated methods at entityByGeomID.

## Create a new object

If you insert

``` (e)=>{ Scene.addCircle({ radius := 0.02;vel := [2, 2] })}
```

into the poststep-section, this will allready create a neverending bunch of circles, that spread from the origin, and move towards the top-right direction. As no color is specified, they will have all nice different colors.

Also other geometries can be created this way. Kilinich creates a fountain of water by coding the poststep as

```   sim.tick % 2 == 0 ? {
pos := [0, 1];
vel := [0, 30];
size := [0.3, 1];
angle := rand.normal / 50
});
v.liquify
} : {}
```

and added a killer-plain, so there wont be too much water, as too much water is slowing the scene.

## Control structures

### if condition, then... else...

The structure for this is

```{}?{}:{}
```

more precisely

```{condition}?{do_this_if_its_true}:{else_do_this}
```

There dont have to be a command in the then-block or in the else-block; if nothing is to be done, then leave it empty.

As condition you can even use a variable that is either true or false, correct me if i am wrong here.

One example: change the color of the circle to blue, if its on the right hand side ( x-position is greater then 0 ) else set it to red.

The black region behind update should read:

``` (e)=>{
{pos(0)>=0}?{color=[0,0,1,1]}:{color=[1,0,0,1]}
}
```

An example how to liquify an object if its height is above 3, you can see in the liquify-explaination below.

The example of Xrays bumper ( see the section "local variables and functions" above ) is here:

``` sim.time > _timer + 0.5 ? {
restitution = 2.5;
_timer = sim.time
} : {
restitution = 1.0
}
```

### Loops for i=1 to 10 do... end

For the loop for integer n1,n2 with n1<n2 Kilinich created a nice script which reads

```scene.my.xFor = (n1, n2, code) => {
n2 > n1 ? {
m := (n1 + n2) / 2;
scene.my.xFor(n1, m, code);
scene.my.xFor(m + 1, n2, code)
} : {code(n1)}
}
```

So open the console with F10, copy the above code, insert it into the console, press enter, and after that also in the console execute

```scene.my.xfor(0,5,(i)=>{print (i)})
```

which willthen print out the numbers from 0 to 5 into the console.

But you can also use it for very accurate creating of things on determined properties, for example if you want to have 50 parallel lasers then you just can do

```scene.my.xfor(0,49,(i)=>{scene.addlaserpen({pos=[0.0,0.1*i]})})
```

One can give to them defined color and direction etc. but i skipped that for simplicity, so their color will come out on random.

## Liquify an object

If an object hits your circle, the other object should be liquified. This is done by the small script: into the curly brackets of onCollide in the scriptmenu, type in: e.other.liquify so that the black region behind onCollide reads now:

``` (e)=>{
e.other.liquify
}
```

It is also nice to liquify an object, if it meets a certain condition, like if the height above the floor is greater then 3, it will transform into rain. The black region behind update should read:

``` (e)=>{
{e.this.pos(1)>=3}?{e.this.liquify}:{}
}
```

Here, we use the fact that pos(0) is the x-value of the position, and pos(1) the y-value of the position.

If you want to make a raindrop, whenever you click on an object, then write into his onClick =

```(e)=>{
pos := e.pos + (0.2, 0);
postStep := (e)=>{
e.this.liquify
}
})
}
```

If you want to create a cyan-colored ice-crystal, that melts to water after 2 seconds, then write into the onClick =

```(e)=>{
drawCake := false;
color = [0.0, 1.0, 1.0, 1.0];
pos := e.pos + (0.2, 0);
timeToLive := 2;
onDie := (e)=>{
e.this.liquify
}
})
}
```

## Control with keys of the keyboard

Some keys are open to press, like "x". So if you hit the x on the keyboard, something can happen, if you make the script. In the same manner as the ice-cystal gives water above in the "liquify"-subsection, you enter in the onKey =

```(e)=>{
{
e.keyChar == "x"
} ? {
drawCake := false;
color = [0.0, 1.0, 1.0, 1.0];
pos := e.this.pos + (0.2, 0);
timeToLive := 2;
onDie := (e)=>{
e.this.liquify
}
})
} : {}
}
```

so that it will rain down ice-crystals, which melt to water, if you press and hold the "x"-key.

## Using the Laser

If an object, that is hit by a laser, should transform its color to the color of the laser, then insert into the scriptmenu of the laser into the section "onLaserHit"

```e.geom.color = e.this.color
```

cause e.geom stays for the "hit" geomentry, and e.this is for the laser itself.

Other way around: If you want that the laser becomes of the color of the object that the laser hit last, then put into the scriptmenu of the laser

```e.this.color = e.geom.color
```

To prevent that the laser hits multiple times or an object that is far away, set its range to a certain amount, e.g. to 1.

## Using the Mouse

app.mousePos(0) for x-Value of the mouseposition,

app.mousePos(1) for x-Value of the mouseposition,

mouse_left mouse_middle mouse_right mouse_wheel_up mouse_wheel_down

## Hack the .phz

The .phz file is just a renamed zip-file. So rename it back to .zip and you ll be able to unzip it with a usual unzip-program. After unzipping, you ll see some of its ressources, like used textures and of cause its script with the .phn extension, probably called scene.phn, as well as the thumb.png and checksums.txt.

To open the scene.phn to edit it, first make a copy of it and rename it to scene.txt. Then use a free program like Notepad++ to open this file and work in it. After your work is done, i recommend to save it under a new name, say myscene.phn and doubleclick on it, so it will be opened with algodoo.

Save then this algodoo-scene again and you have your fully working modified scene.

# Sophisticated methods

## Write to file, read from file

```System.WriteToFile("myfile.txt, variable +";\n")
```

will write (append!) the value of the variable into an existing textfile, and gives back the value "true" if this worked, and if it didn't work ( e.g. if there is no such file ) then "false".

Where has the file to be located? At my PC its in

Bibliotheken\Dokumente\Algodoo in english probably \libraries\documents\algodoo which is a folder that is created by algodoo itself, whenever it is installed. For example in the subdirectory of it is the folder "scenes" where usually your own created scenes are stored.

System.ReadWholeFile and string.Split are to be commented later too..

## textureMatrix

If you want to put into a Square a texture, like "_pasted_0034.png", open the scriptmenu and in the black box beneath "texture" you enter the name of the picture with fileextension and with the quotationmarks. So far, quite easy. But it is not an easy topic, if you want to change the size of a texture in a rectangle or circle. I have done by try and error quite some hours, until i got some nice results, like in scene 85564.

where i used

```textureMatrix = [1 / size(0), 0, 0.5, 0, 1 / size(1), 0.5, 0, 0, 1]
```

in the update-sript.

you can even run a video of sequenced pictures using the texture, as i have done in "video by texture2" ( scene 122754 ). You can even cut the Object in pieces, the video still remains active, which is marvelous to see!

# A real play mode

For performing quests and reach achievements or merrits, it is vital that the conditions of the scenes are not destroyed or cheated.

The trick of homieeee is to implement a script into an object, which becomes invisible intangible (collideset=0) and which permanently sets sim.running=true and App.GUI.playMode=true If you wish to select the drag-tool with a certain maximal-strength, so that the user can only drag moveable things around with his mouse, then

```     Tools.DragTool.strength = 100000;
Tools.DragTool.maxForce = 10000;
Tools.DragTool.SelectTool;
```

could be added to this object-script.

# Algodoo Mod System

It is possible to contact outside-running programs with the help of the read and write to file commands. Whenever something new is written, an external program checks it and performs some actions outside, giving back a changed file, which is then read by algodoo, and which can perform algodoo-actions!

A first nice application of this is to play music and sounds whenever objects with a certain script collide.

This way you can create own instruments.

See the forum for further details.

# List of event-variables

This list was found out by FRA32, and published in the Algodoo-Forum.

Poststep: float dt - The elapsed time since the last scene frame

Update: float dt - The elapsed time since the last update;

OnCollide: array normal: The collision normal array pos: The point of collision float soundGain: Appears to scale with collision impact force.

onClick: array pos: Position of the cursor int clickCount: how many clicks have occured in short succession bool handled: still unsure about this

OnKey: bool pressed: True when a key was pressed, false when released string keyCode: The name of the key being held string keyChar: The text symbol created by the key(If no symbol exists, i.e. arrow keys, this value does not exist either) bool handled: Unsure about this

OnLaserHit: array normal: normal of the hit surface array pos: Point of hit

OnHitByLaser: Identical to above