racer home

Onyx Tutorial - Opening doors/trunks

 

Home A simple start.


Dolphinity Organiser - free planning, project management and organizing software for all your action lists

Introduction

This tutorial is reasonably complex; it helps if you've programmed in C++ or Java before.

23-08-2013: Updated; OnFrame() is now OnPreFrame().

The goal here is to create generic models for a car, and make them openable using keys. The example is a bit simple, in that it responds to keystrokes even when you're typing in the console. And it uses handles in a reasonably free way. Still, it might provide a good example of how to get things done in Onyx. Note that this tutorial was written with Racer v0.8.41; newer versions may still change interfaces, as it's a work in progress language.

The Car

The example car is Stereo's Simca Aronde; get it here. It contains a number of generic models; the trunk and doors are separated 3D models.

The Code

To get the code running, you need to load the Onyx script. In car.ini, set scripts.load to car.oxs and use the following script:

/*
 * 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.
  //
  // targetState: usually 0 (closed) to 1 (open), where 0 represents the smaller angle.
  // 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
// 'h' is the handle to the car
{
  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 OnPreFrame()
{
  float t=GetSimTime();     // Milliseconds
  t=t*0.001;                // Time in seconds

  // Time since last frame
  float dt=t-lastT;
  lastT=t;
  
  if(IsKeyPressed(KEY_T))
  {
    if(keyPressed==false)
    {
      echo("T pressed! Toggle trunk");
      keyPressed=true;
      trunkAnim.open=1-trunkAnim.open;
    }
  } else if(IsKeyPressed(37))
  {
    if(keyPressed==false)
    {
      echo("Left pressed! Toggle door");
      keyPressed=true;
      leftAnim.open=1-leftAnim.open;
    }
  } else if(IsKeyPressed(39))
  {
    if(keyPressed==false)
    {
      keyPressed=true;
      rightAnim.open=1-rightAnim.open;
    }
  } 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);
}

 


Dolphinity Organiser - free planning, project management and organizing software for all your action lists

(last updated August 23, 2013 )