<html> <head> <title>How to create a simulation</title> <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> <link rel="stylesheet" href="highlight.css" type="text/css"> </head> <body bgcolor="#FFFFFF" text="#000000"> <p><font size="6"><i><b>How to create a Simulation</b></i></font></p> <p><font size="4">In this HowTo we will focus on the steps involved in creating a simulation. The truth is, we already have everything we need to know to create a simulation. We can build control aspects to implement the rules governing our simulation. We can implement agent aspects, which can interact with the world through perceptors and effectors. Now, all we have to do is bundle all this different things together into a simulation.</font></p> <p><font size="4">A simulation is comprised of two things. A bundle including all the custom elements making up the simulation (control aspects, agent aspects, custom perceptors and effectors) and a so-called assembly script, which builds the object hierarchy necessary to perform the simulation. As the first aspect, building a bundle has already been described in a previous HowTo, we will focus on the assembly script.</font></p> <p><font size="4">The assembly script is just like any other Ruby script. If we look at the Survival sample simulation, we see that a subdirectory 'survival' is created under the path of the simulator executable (app/simulator). It contains a script called 'survival.rb'. The name of the directory and the script MUST match (except for the rb-extension). The simulator is started with the command-line parameter 'survival', causing it to look for a survival.rb script in the survival subdirectory. We will now go through the survival.rb assembly script line by line:</font></p> <pre># Import classes of this simulation description importBundle('survival/survival'); </pre> <p><font size="4">First, we begin by importing the bundle containing our custom classes. This call adds them to the class object framework of the object hierarchy</font><font size="4">, making the classes available for future calls.</font></p> <pre># create the control aspect cd ('/usr/scene');</pre> <pre> controlAspect = new ('SurvivalControlAspect', '_control');</pre> <p><font size="4">Then we select the 'scene' object. The root of our hierarchical scene structure. It is always located at the path '/usr/scene'. There we create an instance of SurvivalControlAspect ... a class contained in the previously loaded bundle.</font></p> <pre># create world and space aspects cd ('/usr/scene'); world = new ('kerosin/World', '_world'); world.setGravity(0.0, -9.81, 0.0); new ('kerosin/Space', '../_space');</pre> <p><font size="4">Next, we create two important classes for the physics aspect: a world and a space. The world is where all dynamics objects (Bodies) live and the space is, where the geometry aspects can collide.</font></p> <pre># setup camera trans = new ('kerosin/Transform', '../camera'); trans.setLocalPos(0.0, 0.0, 10.0); new ('kerosin/Camera', 'camera'); body = new ('kerosin/Body', '../_physics'); body.useGravity(false); new ('kerosin/FPSController', 'fps'); collider = new ('kerosin/SphereCollider', '../_geometry'); collider.setRadius(2.0); light = new ('kerosin/Light', '../../_light'); light.setRadius(50.0); light.setDiffuseColor(1.0, 1.0, 1.0); </pre> <p><font size="4">The above calls add a camera object to the scene. This is necessary to be able to visualize the simulation. At first, we add a transform node. Under it we attach a kerosin::Camera object. It has a physics aspect (kerosin::Body), which in turn has an FPSController attached. This controller receives the key-presses and mouse movements and translates these to physical movements of the camera. Hence, the connection to the Body class. Our camera is also capable of colliding with other objects in the world, so we add a SphereCollider with radius 2. For some special FX we have also endowed the camera with a dynamic light.</font></p> <pre># add arena cd ('/usr/scene'); trans = new ('kerosin/Transform', 'arena'); trans.setLocalPos(0.0, 0.0, 0.0); mesh = new ('kerosin/StaticMesh', '_visual'); mesh.load('model/arena.void'); # floor pc = new ('kerosin/PlaneCollider', '../pc'); pc.setParams(0.0, 1.0 ,0.0, 0.0); #lights trans = new ('kerosin/Transform', '../../light0'); trans.setLocalPos(0.0, 15.0, 0.0); light = new ('kerosin/Light', '_light'); light.setRadius(80.0); light.setDiffuseColor(1.0, 1.0, 1.0);</pre> <p><font size="4">The above blocks load a very simple rectangular 'playing field' and add a planar collision geometry (geometry aspect), as well as another dynamic light. </font></p> <p># add slow<br> </p> <pre> cd ('/usr/scene'); trans = new ('kerosin/Transform', 'slow'); trans.setLocalPos(-12.5, 1.0, -12.5); visual = new ('kerosin/StaticMesh', '_visual'); visual.load('model/slow.void'); physics = new ('kerosin/Body', '../_physics'); physics.setSphere(1.0, 1.0); physics.setMass(1.0); physics.setMaxSpeed(3.0); geometry = new ('kerosin/SphereCollider', '../_geometry'); geometry.setRadius(1.0); agent = new ('SurvivalAgentAspect', '../_agent'); </pre> <p><font size="4">Here we add the first agent to the world. We begin by giving it a starting position (the transform node). Then we add the visual aspect (load the slow.void mesh), physics aspect</font><font size="4">, geometry aspect and agent aspect (SurvivalAgentAspect).</font><br> </p> <pre># add fast cd ('/usr/scene'); trans = new ('kerosin/Transform', 'fast'); trans.setLocalPos(12.5, 1.0, 12.5); visual = new ('kerosin/StaticMesh', '_visual'); visual.load('model/fast.void'); physics = new ('kerosin/Body', '../_physics'); physics.setSphere(1.0, 1.0); physics.setMass(1.0); physics.setMaxSpeed(10.0); geometry = new ('kerosin/SphereCollider', '../_geometry'); geometry.setRadius(1.0); agent = new ('SurvivalAgentAspect', '../_agent'); </pre> <p><font size="4">This adds the second agent to the world. Almost identical to the second agent, except it has a higher maximum speed and a different visual aspect. </font><br> </p> <pre> # add food cd ('/usr/scene'); trans = new ('kerosin/Transform', 'food'); trans.setLocalPos(0.0, 1.0, 0.0); visual = new ('kerosin/StaticMesh', '_visual'); visual.load('model/food.void');</pre> <p><font size="4">Last but not least, the 'food' object is added. As one can tell, it has only 'visual' character. The control aspect determines internally if one of the agents has reached the food (see SurvivalControlAspect).</font></p> <p><font size="4">As one can see, creating assembly scripts is straight-forward. One only has to keep track of what one is building up in the object hierarchy. After the script is executed, the simulation is run automatically.</font></p> <p> </p> </body> </html>