Welcome to the Second Life Forums Archive

These forums are CLOSED. Please visit the new forums HERE

Any good non-physical vehicle scripts available?

Erratic Rambler
Registered User
Join date: 27 May 2005
Posts: 4
07-17-2005 01:15
I'd like to make a large vehicle; one that has too many parts to make it physical.

For the moment, I'm not worrying about vehicle velocity or acceleration. I'd be happy if I can get the thing moving forwards and backwards, turning, and staying on the ground.

Has anyone had much success in scripting a non-physical vehicle?

This is what I have so far, and it kind of works, but not all that well:
CODE
// Script for moving a non-physical vehicle
// author: Erratic Rambler

// notes:
// - Uses separate scripts for doing movement and rotation, since those operations cause delay.
// Link messages to communicate with movement and rotation scripts.
// - Keeps track of current position and rotation instead of using llGetPos / llGetRot,
// because the movement is done in separate scripts and current values may not be
// the correct target values.


// constants
vector SIT_POS; // sit offset
vector SIT_ROT; // sit rotation
vector CAMERA_POS; // offset of camera when avatar sits
vector CAMERA_LOOK_AT; // where camera looks when avatar sits
integer CONTROLS; // list of control keys to use
vector FORWARD_MOVE; // forward movement rate
vector BACK_MOVE; // backwards movement rate
float TURN_RATE; // turn rate
float TIMER_DURATION; // timer delay
integer MOVER_MAX_INDEX; // number of movement listeners - 1
integer TURNER_MAX_INDEX; // number of turn listeners - 1

// globals
integer forwardKeyPressed = FALSE; // true when forward key pressed
integer backKeyPressed = FALSE; // true when back key pressed
integer leftKeyPressed = FALSE; // true when left key pressed
integer rightKeyPressed = FALSE; // true when right key pressed
integer moverIndex = 0; // current mover script
integer turnerIndex = 0; // current turner script
vector currentPos; // current position
vector currentRot; // current rotation

// from LSL wiki
// AXIS_* constants, represent the unit vector 1 unit on the specified axis.
vector AXIS_UP = <0,0,1>;
vector AXIS_LEFT = <0,1,0>;
vector AXIS_FWD = <1,0,0>;

// from LSL wiki
// getRotToPointAxisAt()
// Gets the rotation to point the specified axis at the specified position.
// @param axis The axis to point. Easiest to just use an AXIS_* constant.
// @param target The target, in region-local coordinates, to point the axis at.
// @return The rotation necessary to point axis at target.
// Created by Ope Rand, modifyed by Christopher Omega
rotation getRotToPointAxisAt(vector axis, vector target) {
return llGetRot() * llRotBetween(axis * llGetRot(), target - llGetPos());
}

default
{
state_entry()
{
// initialize global 'constants'
SIT_POS = <0.0, 0.0, 0.5>;
SIT_ROT = ZERO_VECTOR;
CAMERA_POS = <-10.0, 0.0, 5.0>;
CAMERA_LOOK_AT = <0.0, 0.0, 0.0>;
CONTROLS = CONTROL_FWD | CONTROL_BACK | CONTROL_ROT_LEFT | CONTROL_ROT_RIGHT | CONTROL_LEFT | CONTROL_RIGHT;
FORWARD_MOVE = <2, 0, 0>;
BACK_MOVE = <-1, 0, 0>;
TURN_RATE = 7.2;
TIMER_DURATION = 0.1;
MOVER_MAX_INDEX = 1;
TURNER_MAX_INDEX = 1;

// initialize global variables
currentPos = llGetPos();
currentRot = RAD_TO_DEG * llRot2Euler( llGetRot() );

// set up vehicle parameters
llSetSitText( "Drive" );
llCollisionSound( "", 0.0 );
llSitTarget( SIT_POS, llEuler2Rot( DEG_TO_RAD * SIT_ROT ) );
llSetText( "", <1,1,1>, 1.0 );
llSetStatus( STATUS_PHYSICS, FALSE );
llSetCameraEyeOffset( CAMERA_POS );
llSetCameraAtOffset( CAMERA_LOOK_AT );


// disable timer
llSetTimerEvent( 0 );

}

// sit / unsit / etc
changed( integer change )
{
if( change & CHANGED_LINK )
{
key agent = llAvatarOnSitTarget();
if( agent )
{
if( agent != llGetOwner() )
{
// only let owner drive vehicle
llSay( 0, "Only the owner can drive this vehicle." );
llUnSit( agent );
llPushObject( agent, <0, 0, 10>, ZERO_VECTOR, FALSE );
}
else
{
// take controls
if( llGetPermissions() & PERMISSION_TAKE_CONTROLS == PERMISSION_TAKE_CONTROLS )
llTakeControls( CONTROLS, TRUE, FALSE );
else
llRequestPermissions( agent, PERMISSION_TAKE_CONTROLS );

// read position and rotation
currentPos = llGetPos();
currentRot = RAD_TO_DEG * llRot2Euler( llGetRot() );

// enable timer
llSetTimerEvent( TIMER_DURATION );
}
}
else
{
// release controls
llReleaseControls();

// disable timer
llSetTimerEvent( 0 );
}
}
}

// permissions granted to take controls
run_time_permissions( integer perm )
{
if( perm )
{
llTakeControls( CONTROLS, TRUE, FALSE );
}
}

// control input
control( key id, integer level, integer edge )
{
// set key press status variables based on control input
if( edge & level & CONTROL_FWD ) forwardKeyPressed = TRUE;
if( edge & ~level & CONTROL_FWD ) forwardKeyPressed = FALSE;
if( edge & level & CONTROL_BACK ) backKeyPressed = TRUE;
if( edge & ~level & CONTROL_BACK ) backKeyPressed = FALSE;
if( ( edge & level & CONTROL_ROT_LEFT ) || ( edge & level & CONTROL_LEFT ) ) leftKeyPressed = TRUE;
if( ( edge & ~level & CONTROL_ROT_LEFT ) || ( edge & ~level & CONTROL_LEFT ) ) leftKeyPressed = FALSE;
if( ( edge & level & CONTROL_ROT_RIGHT ) || ( edge & level & CONTROL_RIGHT ) ) rightKeyPressed = TRUE;
if( ( edge & ~level & CONTROL_ROT_RIGHT ) || ( edge & ~level & CONTROL_RIGHT ) ) rightKeyPressed = FALSE;

}

// timer event runs while vehicle is active
timer()
{

// cause vehicle to remain upright
// llLookAt does not work correctly here, but getRotToPointAxisAt
// function from wiki in combination with llRotLookAt does.
// (llLookAt seems to do rotation around z axis for some reason??)
vector up = currentPos + llGroundNormal( ZERO_VECTOR );
llRotLookAt( getRotToPointAxisAt( AXIS_UP, up ), 1.0, 1.0 );


// do movement
if( forwardKeyPressed && !backKeyPressed )
{
currentPos += FORWARD_MOVE * llEuler2Rot( DEG_TO_RAD * currentRot ); // move forward
currentPos.z = llGround( ZERO_VECTOR ) + 1.0; // stay on ground
string targetPosString = (string)currentPos; // convert position to string
llMessageLinked( LINK_THIS, moverIndex, "move", (key)targetPosString ); // call move script
}
if( backKeyPressed && !forwardKeyPressed )
{
currentPos += BACK_MOVE * llEuler2Rot( DEG_TO_RAD * currentRot ); // move backward
currentPos.z = llGround( ZERO_VECTOR ) + 1.0; // stay on ground
string targetPosString = (string)currentPos; // convert position to string
llMessageLinked( LINK_THIS, moverIndex, "move", (key)targetPosString ); // call move script
}

// do turning
if( leftKeyPressed && !rightKeyPressed )
{
currentRot.z += TURN_RATE; // rotate left
string targetRotString = (string)llEuler2Rot( DEG_TO_RAD * currentRot ); // convert rotation to string
llMessageLinked( LINK_THIS, turnerIndex, "rotate", (key)targetRotString ); // call rotate script
}
if( rightKeyPressed && !leftKeyPressed )
{
currentRot.z -= TURN_RATE; // rotate right
string targetRotString = (string)llEuler2Rot( DEG_TO_RAD * currentRot ); // convert rotation to string
llMessageLinked( LINK_THIS, turnerIndex, "rotate", (key)targetRotString ); // call rotate script
}

// increment indices of movement scripts to use
moverIndex++;
turnerIndex++;
if( moverIndex > MOVER_MAX_INDEX ) moverIndex = 0;
if( turnerIndex > TURNER_MAX_INDEX ) turnerIndex = 0;

}

}

CODE
// script which does movement
// have N of these in the object, with consecutive 0-based indices
string ACTION_TYPE = "move";
integer INDEX = 0;

default
{
state_entry()
{
}

// listen for link messages
link_message( integer sender_num, integer num, string str, key id )
{
// if message is for this script
if( str == ACTION_TYPE && num == INDEX )
{
string val = (string)id;
llSetPos( (vector)val );
}
}
}

CODE
// script which does rotations
// have N of these in the object, with consecutive 0-based indices
string ACTION_TYPE = "rotate";
integer INDEX = 0;

default
{
state_entry()
{
}

// listen for link messages
link_message( integer sender_num, integer num, string str, key id )
{
// if message is for this script
if( str == ACTION_TYPE && num == INDEX )
{
string val = (string)id;
llSetRot( (rotation)val );
}
}
}


If I can't get a non-physical vehicle working well, the next thing I plan to try is multiple small physical vehicles which all follow the main vehicle (making it essentially 1 large multi-part vehicle). That seems kind of messy though, so I'd much rather get a non-physical vehicle that works nicely.
Johnny Noir
Registered User
Join date: 5 Jan 2004
Posts: 28
07-17-2005 13:53
The biggest hassle I'd forsee in a non-physical vehicle is that there is no way to smoothly move it. The only position function available is setpos, and since that can only be run once each "cycle' of the script, you could have your object jumping quite a bit.
Erratic Rambler
Registered User
Join date: 27 May 2005
Posts: 4
07-17-2005 17:36
From: Johnny Noir
The biggest hassle I'd forsee in a non-physical vehicle is that there is no way to smoothly move it. The only position function available is setpos, and since that can only be run once each "cycle' of the script, you could have your object jumping quite a bit.

I think that if I could get the vehicle moving at about 10 updates/second, that would be smooth enough for my purposes. The vehicle that I'm trying to create should move rather slowly, so 10 moves/sec would probably seem fairly smooth.

That's the speed at which my above script attempts to run. If I'm remembering correctly from my testing, it actually seems to work fairly well going forward or backwards, but turning doesn't work as nicely. It does not turn smoothly, sometimes does not turn at all when it should, and often continues to turn well after the key has been released. The part that makes the vehicle follow the contour of the land also works erratically; at times the vehicle would even flip upside down!

edit: I just realized that in my original post, one of the scripts is the wrong one. I had two copies of the mover script, and none of the rotator script. Fixed now.