TBD. Notes follow...
One of the joy's of Acorn is how straightforward it can be to animate a scene's parts. A few examples should help get this concept across.
Let's make the earth spin, by appending a few lines:
Scene[ name: 'Spinning Earth Scene' ambient: Color::Grey # Scene's objects $::me .position = Xyz[0, 47, 222] Object[ name: 'earth' mesh: Mesh::Sphere(60.) skin: @earth.jpg position: Xyz[0, 0, 0] spinrate: 0.628318 # Spin earth a bit every frame animate(dt):> .yaw += dt * ::spinrate
How does this animation work?
The browser re-draws the 3-D scene many times every second. Each drawing is called a frame. After it draws each frame, it will call the animate method for every scene part that has one, passing along how many seconds have elapsed since the last frame. For acceptable animation, this "dt" value should stay well below 0.04 seconds (and some would argue it should be well below half that number).
In the example, the animate method increments the earth's "yaw" rotation by a small amount, calculated by multiplying the elapsed time by the how fast we want the earth to spin (in radians per second). This technique ensures that the earth performs a complete rotation every 10 seconds, regardless of how quickly frames are getting drawn. The effect of a slowly increasing "yaw" is to rotate the earth a bit along the y (polar) axis.
A Silly Solar System
Wouldn't it be fun to broaden this example into a model of make-believe solar system? I thought so too!
A solar system needs multiple planets and other satellites, all with similar behavior. So, we need a new Type that creates such heavenly bodies. Let's call it Body. Here is its Type definition found in the resource body.acn:
### Creates a spherical heavenly body with these specified properties: - skin. The look of the body - radius. Size of the body - spinrate. How fast it spins around its axis: radians per second - position. Starting position - velocity. Starting velocity - gravity. G * mass ### Body = Type[ Object # Initialize created body begin:> ::mesh = Mesh::Sphere(::radius) ::velocity = Xyz[0, 0, 0] if ::velocity.null? # Define motion rules animate(dt):> # Spin it a bit .yaw += dt * ::spinrate # Calculate new velocity & orbital position, based on owner's gravity oldvel = ::velocity ::velocity += -::position.normalize * (dt * ::owner::gravity/::position.sqlength) ::position += (::velocity + oldvel)*(dt/2)
The comments at the top are a good reminder of what properties we will need to specify when we use the Type to create new heavenly bodies.
We are using another method called "begin" which can be specified in any part. Its purpose is to initialize the part once its content has been fully loaded by the loader and resource manager. We use it here to specify that all bodies use a spherical mesh, whose size is determined by the body's radius. The begin method also ensures that velocity has a default value, if left undefined.
The animate method still spins the body. It also updates the body's velocity and position based on some crude physics formulas that simulate the effect of gravitational attraction from its owner. These formulas will break down badly the higher the orbital speed. This is a pretty fixable problem, but not worth the time for a simple example.
If these formulas make your head spin, don't worry. You don't really need to understand the formulas here to get the basic message: with Acorn you can do any sort of calculation that modifies an object's position or other properties on a real-time basis. If you ever need to do this sort of math (which is pretty rare), just make friendly with someone that loves this sort of thing.
Now that we have a general-purpose heavenly body type, let's use it to assemble a small, mythical solar system scene with a few orbiting bodies.
# We must ensure the Body type is loaded require Body = @body.acn Scene[ name: 'Solar System Scene' ambient: Color::Grey gravity: 20000. # Scene's objects $::me .position = Xyz[0, 47, 222] Body[ name: 'Sun' skin: @sun.jpg radius: 30. spinrate: .05 position: Xyz[0, 0, 0] # Earth's system Body[ position: Xyz[70,70,0] velocity: Xyz[0,0,-10] gravity: 30000. # Create the earth Body[ name: 'Earth' skin: @earth.jpg radius: 10. spinrate: 2. # Create the moon Body[ name: 'Moon' skin: @moon.jpg radius: 5. spinrate: 3. position: Xyz[-15,0,0] velocity: Xyz[0,-30,0] # Create Jupiter Body[ name: 'Jupiter' skin: @jupiter.jpg radius: 20. spinrate: 1. position: Xyz[-110,-30, 0] velocity: Xyz[0,1,8]
It should make sense that we created the earth and Jupiter inside the Sun, so their orbits are calculated based on the Sun's gravity. Similarly, the moon was created inside the earth, as it orbits around the earth.
Feel free to play with this model by adding more planets and satellites. Try leaving out the velocity property, and notice how the body accelerates towards its owner. Then notice what doesn't happen when they collide.