[EDIT]
JosephB caught an error in my original distance function where I mistyped the variable time (not defined integer) where I should've had time# (defined float). I changed the snippet a bit and added another distance function. This was actually the formula that the sim was using due to my typo, so I thought I would include it and use it instead of the original. This is distance_2(). The difference between the functions distance_1() and distance_2() is that distance_1 accounts for an acceleration or deceleration. In the sim, because I am accounting for gravity with fvel#, if I use distance_1, gravity would be applied TWICE to the cube which would just be too much!
Feel free to experiment and use either function in the sim to see what results work best. If you use distance_1(), you will have to adjust the bounce loop to test for the y# distance differently.
[orig]
I was answering a question on another forum and wrote up a script of a sphere that bounced up and down using gravity. I looked at the code, changed the sphere to a cube, added a few random elements and came up with what I think is a pretty interesting looking cube that bounces around and spins and such.
I also included a bunch of physics functions at the end that are basically inversions of each other that someone might find useful.
If you use any of the code in your programs, just credit me. Hope it's interesting and useful.
`**************************************
`* Title : bouncing physics cube
`* Author : Latch Grapple
`* Date : 10/7/2006
`* Update : 10/11/2006
`* Version: v 0.2
`**************************************
rem ------ Set Up Display -------------
autocam off
set display mode 800,600,16
sync on:sync rate 60
randomize timer()
rem ------ make matrix ------
make matrix 1,1000,1000,50,50
rem ------ make ball --------
make object cube 1,25
position object 1,500,get ground height(1,500,500)+25,500
rem ------ position camera ------
position camera 500,50,400
do
rem ----- set up our initials and constants ---------
mass#=10
sideways=rnd(4)-2
frontways=rnd(2)-1
force#=rnd(500)
accel#=accel_2(force#,mass#)
ivel#=vel_2(0.0,accel#,1.0)
fvel#=0
time#=0
gravity#=-9.8
x#=object position x(1)
y#=object position y(1)
z#=object position z(1)
rem ------ the actual "bounce" loop change in velocity and distance ----
rem ------ affected by gravity
while fvel# >= 0
inc time#,.05
fvel#=vel_2(ivel#,gravity#,time#)
distance#=distance_2(fvel#,time#)
set cursor 0,0
print "Popping Force : ";force#
print "final velocity : ";fvel#
print "distance : ";distance#
if distance# < 0 then distance# = 0
x#=x#-sideways
z#=z#+frontways
rot#=wrapvalue(rot#-sideways)
if x#>=1000 then sideways=-1*sideways
if x#<=0 then sideways=-1*sideways
if z#>=1000 then frontways=-1*frontways
if z#<=0 then frontways=-1*frontways
position object 1,x#,y#+distance#,z#
rotate object 1,rot#,rot#,wrapvalue(rot#*-2)
position camera x#,camera position y(),z#-100
sync
endwhile
loop
end
rem ------------------- Force, Acceleration, Velocity equations ----------------
function vel_2(ivelocity#,acceleration#,time#)
v#=ivelocity#+(acceleration#*time#)
endfunction v#
function vel_1(distance#,time#)
v#=distance#/time#
endfunction v#
function force(mass#,acceleration#)
f#=mass#*acceleration#
endfunction f#
function accel_1(vel1#,vel2#,time#)
a#=(vel2#-vel1#)/time#
endfunction a#
function accel_2(force#,mass#)
a#=force#/mass#
endfunction a#
function distance_1(ivelocity#,time#,acceleration#)
s#=(ivelocity#*time#)+(acceleration#*(time#^2))/2
endfunction s#
function distance_2(velocity#,time#)
s#=velocity#*time#
endfunction s#
[EDIT]
A couple of people asked me how this works, I'll try to explain it.
First thing, I set up the display and seed the random generator with the timer. This is so that when I use the rnd() function later, it likely won't be the same value everytime I run the program.
Next, I make a matrix, 1000,1000 untis across and up, and 50x50 tiles. Nothing too spectacular.
Next I create the cube that I'm going to bounce around:
rem ------ make cube --------
make object cube 1,25
position object 1,500,get ground height(1,500,500)+25,500
25 seems to be the size from the center of the cube out so when I position it, I'm positioning it in the middle of the grid and I want to account for the 25 units on the y axis so the cube isn't cut in half by the grid. I know the matrix is 1000x1000 so therefore to place the cube in the middle, I have to set x and z to 500. I get the ground hieght of the matrix at that location and add 25 to it. This will be the y position of the cube so that the cube is in the middle and right on top of the grid.
Next I position the camera lined up with the cube on the x, 50 units up on the y, and 400 units on the z (100 units away from the cube so that we can see it).
Now we get into the fun stuff! We want to treat the cube somewhat like it's in the real world so I want to assign it a mass. For this example, the mass becomes extremely important because it influences the affects of any forces I apply to it.
The idea of this simulation is to apply a random upward force to the cube - a "popping" force if you will. This will be sort of a bounce, but it will be different everytime the cube lands.
rem ----- set up our initials and constants ---------
mass#=10
sideways=rnd(4)-2
frontways=rnd(2)-1
force#=rnd(500)
accel#=accel_2(force#,mass#)
ivel#=vel_2(0.0,accel#,1.0)
fvel#=0
time#=0
gravity#=-9.8
The next series of variables that follow mass in this section are:
Sideways = this is a random X value between -2 and 2. This will control which sideways direction the cube will go in once the popping force is applied.
Frontways = this is a random Z value between -1 and 1. This controls how the cube moves into the foreground or background.
Force# = just a random number (force) between 0 and 500 that tells how much "umph" to give the cube.
Accel# = this is where I use one of the acceleration functions to get the acceleration of the cube when it is launched. I chose the specific function accel_2() because that uses force# and mass# to find the acceleration of the object, and I have those so accel# can be solved for.
Ivel# = initial velocity of the cube. I use vel_2() because that function contains the elements I need to solve for ivel#. Since it is assumed that the cube has no velocity before it is launched, and we are assuming an instantaneous velocity after the force is applied we have a starting velocity of 0, and acceleration of accel#, and a time# we'll set at 1 for instantaneous launch - thus the equation looks like
ivel#=vel_2(0.0,accel#,1.0)
Fvel# = this is the velocity of the cube as it is affected by gravity. At the initial launch, this is 0 because we only care about ivel# when we start.
Time# = time. Set to zero to refresh the sim at every bounce
The bounce loop:
rem ------ the actual "bounce" loop change in velocity and distance ----
rem ------ affected by gravity
while fvel# >= 0
inc time#,.05
fvel#=vel_2(ivel#,gravity#,time#)
distance#=distance_2(fvel#,time#)
set cursor 0,0
print "Popping Force : ";force#
print "final velocity : ";fvel#
print "distance : ";distance#
if distance# < 0 then distance# = 0
x#=x#-sideways
z#=z#+frontways
rot#=wrapvalue(rot#-sideways)
if x#>=1000 then sideways=-1*sideways
if x#<=0 then sideways=-1*sideways
if z#>=1000 then frontways=-1*frontways
if z#<=0 then frontways=-1*frontways
position object 1,x#,y#+distance#,z#
rotate object 1,rot#,rot#,wrapvalue(rot#*-2)
position camera x#,camera position y(),z#-100
sync
endwhile
I start off with checking fvel# against falling below zero. In the real world, this would happen when the object got as high as it could and then started falling. But because I'm using a displacement equation later, if fvel# falls below zero then the object has dropped back to the height from which it launched.
We need to keep track of time so that everything can change (velocity and distance). I didn't want time# to be the loop in which everything happens but I wanted time# to change, so I increment it within the main While Loop so that time# is actually influenced by where the object is, as opposed to the other way around.
The next two functions really do all the work. I'm making gravity -9.8 which represents the acceleration rate towards -y or downward in this example.
fvel# will change as time# changes.
fvel#=vel_2(ivel#,gravity#,time#) takes ivel (the launch velocity) and calculates it against gravity as time changes. Since gravity is in the opposite direction of ivel#, as time increases, gravity (-9.8) will influence the acceleration in the opposite direction... this means fvel# will continue to slow down until it stops, then it will decrease at the rate of gravity. In the sim, you see the cube rising and slowing down.
distance# calculates how far the cube is traveling from it's launch point along the y axis. It is greatly influnced by fvel#. Of course gravity and time# play important roles also. If fvel# didn't change, the cube would just keep rising, but at a fixed speed determined by gravity.
distance# is the real work horse and is the value I add to the cubes original y position to actually make it move. Very much like fvel#, distance# value inceases as the cube goes up, but once the cube reaches it's peak height, the influence of gravity is too much and the cube will fall at a velocity realtive to gravity. This displacement with each time iteration increase, so we see the cube speed up as it get's closer to the ground.
All of the x#, z#, and rot# calculations are based on the sideways and frontways variables I created earlier. These are just added to or subtracted from, or rotated within, x#, z# y# - to make the cube move side to side, from to back, and to spin. The numbers I chose don't have any real significance, they are just low, and a little different from each other to try and make the tumbling look a little more real.
Essentially the whole simulation is brought together by position the object according to the new values calculated from distance#, sideways, and frontways - then rotating the object with rot#. I want to keep the camera at a z distance 100 units less than the cube so the camera follows the cube around while it bounces but never changes it's orientation.
I put a couple of limits on the x# and z# directions based on the size of the matrix so the cube doesn't go out of bounds.
I actually only use three of the motion equations. The rest I included so anyone could use them as variations on the methods I used in this example.
Enjoy your day.