I've been playing a bit with Stereo's Simca Aronde and the scripts in there. These things are nice to get into Onyx at some point, since that will be a more mature language (looking very much like C++). I've added some Onyx functions for v0.8.41 (not out yet) to make at least the Simca trunk/door opening possible.
The code looks like this (all based on Stereo's QScript code, although now enhanced with a common class to do the animation).
Issues:
- Onyx uses handles to hook the car inside Racer's engine, and also to get the generic models. Handles can be assigned to eachother, which is very dangerous for a scripting language. No solution yet (perhaps make handle assignments forbidden?). Onyx also knows the 'pointer' type, which is a bit the same but a different base type, so 'handle h; pointer p; h=p; ' is not allowed. Still, it kinda s*cks to expose this kind of flexibility, as it makes crashes quite easy.
- No constructors yet, so class creation is a bit hardcoded.
- An Onyx bug with variable offsets, the following does not work because of compiling issues:
Now for the Onyx code for the Simca (I added scripts.load in car.ini, setting it to car.oxs; this is v0.8.41 functionality though).
The code looks like this (all based on Stereo's QScript code, although now enhanced with a common class to do the animation).
Issues:
- Onyx uses handles to hook the car inside Racer's engine, and also to get the generic models. Handles can be assigned to eachother, which is very dangerous for a scripting language. No solution yet (perhaps make handle assignments forbidden?). Onyx also knows the 'pointer' type, which is a bit the same but a different base type, so 'handle h; pointer p; h=p; ' is not allowed. Still, it kinda s*cks to expose this kind of flexibility, as it makes crashes quite easy.
- No constructors yet, so class creation is a bit hardcoded.
- An Onyx bug with variable offsets, the following does not work because of compiling issues:
Code:
void OnFrame()
{
float t=123.0f;
echo(t);
if(1)
{
echo(t);
float v;
v=2;
echo(t); // Prints 2, not 123 (bug!)
}
}
Now for the Onyx code for the Simca (I added scripts.load in car.ini, setting it to car.oxs; this is v0.8.41 functionality though).
Code:
/*
* Car script, handling any added logic
* 08-06-2012: Created (based on Stereo's variant for the Simca Aronde in QScript)
* NOTES:
* - No constructors exist yet in Onyx; would be handy
*/
#include "racer.oxs"
// Objects
Car car; // The car we control
// Angle animation
class AngleAnimator
{
handle gm; // The generic model
Vector3 pos, // Position of model
rotMask; // Mask to define rotation (i.e. 0,1,0)
int open; // Desired state
float angle; // Current angle
void UpdateAngle(float incRate,float decRate,float minAngle,float maxAngle,float interval)
// Angle handler for a generic model.
//
// incRate: angular change (per ms) in radians when opening.
// decRate: angular change (per ms) in radians when closing. note: both should be positive.
// minAngle: min value for the angle
// maxAngle: max value for the angle
// 'interval' is the delta time since the last frame
//
// Returns the updated angle
{
float targetState=open;
// Figure out where we want to go
float targetAngle=targetState*(maxAngle-minAngle)+minAngle;
// Move towards target angle
if(targetAngle>angle)
angle=angle+incRate*interval;
if(targetAngle<angle)
angle=angle-decRate*interval;
// Clamp angle within a valid range
if(angle<minAngle) angle=minAngle;
else if(angle>maxAngle)angle=maxAngle;
// display the object correctly
GenModSetPosition(gm,pos);
GenModSetRotation(gm,angle*rotMask.x,angle*rotMask.y,angle*rotMask.z);
}
};
AngleAnimator trunkAnim,leftAnim,rightAnim;
// Generic
int keyPressed;
// Frame interval
float lastT;
void OnInit(handle h)
// Called when the car is created
{
echo("OnInit of car");
// This next line should change in the future
car.h=h;
// Trunk animation setup
trunkAnim.gm=car.GetGenericModel(8);
trunkAnim.pos.x=0;
trunkAnim.pos.y=0.35;
trunkAnim.pos.z=-1.31;
trunkAnim.rotMask.x=0; trunkAnim.rotMask.y=1; trunkAnim.rotMask.z=0;
// Doors
leftAnim.gm=car.GetGenericModel(9);
leftAnim.pos.x=0.739;
leftAnim.pos.y=-0.58;
leftAnim.pos.z=0.628;
leftAnim.rotMask.x=-1; leftAnim.rotMask.y=0; leftAnim.rotMask.z=0;
rightAnim.gm=car.GetGenericModel(10);
rightAnim.pos.x=-0.739;
rightAnim.pos.y=-0.58;
rightAnim.pos.z=0.628;
rightAnim.rotMask.x=1; rightAnim.rotMask.y=0; rightAnim.rotMask.z=0;
}
void OnFrame()
{
float t=GetSimTime(); // Milliseconds
t=t*0.001; // Time in seconds
float yaw,pitch,roll;
// Time since last frame
float dt=t-lastT;
lastT=t;
if(IsKeyPressed(KEY_T))
{
if(keyPressed==false)
{
echo("T pressed! Toggle trunk");
keyPressed=true;
if(trunkAnim.open)trunkAnim.open=false; else trunkAnim.open=true;
}
} else if(IsKeyPressed(37))
{
if(keyPressed==false)
{
echo("Left pressed! Toggle door");
keyPressed=true;
if(leftAnim.open)leftAnim.open=false; else leftAnim.open=true;
}
} else if(IsKeyPressed(39))
{
if(keyPressed==false)
{
keyPressed=true;
if(rightAnim.open)rightAnim.open=false; else rightAnim.open=true;
}
} else
{
keyPressed=false;
}
// Animate
trunkAnim.UpdateAngle(3.0,3.0, 0,1.2, dt);
leftAnim.UpdateAngle(2.0,2.0, 0,1.1, dt);
rightAnim.UpdateAngle(2.0,2.0, 0,1.0, dt);
}