Animated Campus Vehicles

From CS486wiki
Revision as of 20:40, 15 May 2012 by Core (talk | contribs)
(change visibility) (diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigationJump to search

This page describes how EZScript was used to animate campus vehicles


Project Description

The Animated Campus Vehicles project is a subproject of the Virtual BU project. This project's goals were to:

- Create a campus maintenance vehicle (Humvee golf cart)

- Build a program or script to have the vehicle follow a given path

General Solution

The general solution can be called the Hansel and Gretel approach. The path that the vehicle will follow is layed out using a set of objects called "way markers" (bread crumbs). The way markers are consecutively numbered to give an ordering to the path to be followed. The way markers are placed at ground level on typically a campus roadway, the vehicle seeks out the starting way marker and then moves from that way marker to the next higher numbered way marker. This continues until it reaches the last way marker and then it moves to the first way marker and continues (for ever).

How to use

The javascript file below acts as the EZScript for any cell/object you want to have move around a path. Building the path is simple, just create a marker (little 2d square, for example) and name it something like mywaypoint-1, then duplicate it and move it to the next position and name the duplicate mywaypoint-2. Do this over and over until you are satisfied with the path created. After completing the path, open the javascript file and at the top of the file is a global array named Paths, add the name "mywaypoint" to this array to represent the path you just added. The vehicle will infinitely follow the paths in the array in the given order, example: Paths = new Array("firstpath","secondpath"); the vehicle will follow all points with the naming scheme firstpath-[0 through n], then when there are no points remaining in "firstpath", the vehicle will move to the point "secondpath-1". A working snapshot can be found on vbu.binghamton.edu in the snapshot named "Car Demo".

EZScript Usage

Our Implementation

The EZScript module is responsible for the vehicle movements within the world. EZScript cell-scripting allows for a JavaScript based script file to be executed on a cell. More documentation can be found here. For this motion to function, the vehicle which is being moved must have the motion module attached to it and all way point objects must have EZScrpit enabled so that they can be interacted with using commands from the vehicle. It is further essential that the latest version of EZScript build be used which can be accessed from the googlecode repository.

To create a path the user must place down a series of objects in the world and name them given a the scheme <Group_Name>-<WayPoint_Number>. WayPoint Numbers also start at 1 and not 0 (as would be conventional for an array). Using this scheme one can use basic string concatenation and a loop to iterate through all of the way points in a given group.

Where to download

Professor Steflik has been given a copy of EZScript compatible with the script written. However, openwonderland can be checked out via subversion from googlecode and built on linux using ant. Instructions can be found here.

Future Development

If this project is to be continued in the future, make note that Jagwire has added EZScript functionality very recently (see rotate and GetCellRotation) that will help aid the addition of a smoother motion around corners. Unfortunately, these updates weren't pushed to subversion in time to make the stable final script.

Vehicle Development

The Binghamton University maintenance vehicle was developed using Google SketchUp 8. The basis for this vehicle is a military humvee which was then stripped down and rebuilt to resemble one of the maintenance vehicles. Some changes include remodeling the rear axle and addition of a drop in trunk, remodeled front axle and front end, new color to both interior and exterior model faces and addition of transparent windows to the model. The vehicle was oriented in Sketchup such that positive motion on the Z-axis in OpenWonderland represents the vehicle driving straight (when there is no rotation on the Y-axis).

Bugs/Fixes

Bug found with EZScript when using the EZScript function GetCellRotation when used at a high rate. Jagwire, the creator of EZScript, continuously fixes and updates EZScript. All bugs and possible fixes we found have been reported to him.

Source Code

// VirtualBU Vehicle Animation

// Collin Stowell

// Jason Morrison

// This script assumes 1 thing. That when Y rotation is 0, that increasing the Z value will move the object forward in it's look direction.

// These are our globals

// Our set of paths, our vehicle will travel these in the order specified infinitely

// A pathname requires that

Paths = new Array("wp");


var speed = 10; // This will be the speed of the vehicle throughout its motion

var height_offset = .7; // This will add this value to the y value of the vehicle as it moves from point to point (points may be under ground)


function getTurned() {

// This function will fetch the Y rotation of this object

var a = GetCellRotation(cell);

var deg = quatToDeg(a.y);

return deg;

}

function quatToDeg(x) {

// EZScript quaternions store values in 2*asinx for rotations. This will convert them into degrees

var rad = 2 * Math.asin(x);

var deg = rad * (180 / Math.PI);

deg = Math.round(deg * 1000) / 1000;

return deg;

}

function degToQuat(deg) {

// Input is 0 - 360

// Output will be the quaternion angle

var ret = Math.sin(deg * Math.PI / 360);

return ret;

}

function pointTo(destObj) {

// This function will point the current cell to the destination object

curPos = GetCellPosition(cell);

nexPos = $(destObj).getPosition();

// These 4 statements combined will figure out the degrees off the Z axis from the curPos the nexPos is (0-360)

var nexDeg = 0;

// Quadrant 1 (Angles 0-90)

if ((nexPos.z > curPos.z) && (nexPos.x > curPos.x)) {

nexDeg = Math.atan((nexPos.x - curPos.x)/(nexPos.z - curPos.z))*(180 / Math.PI);

}

// Quadrant 2 (Angles 90-180)

if ((nexPos.z < curPos.z) && (nexPos.x > curPos.x)) {

nexDeg = 90 + Math.atan((curPos.z - nexPos.z)/(nexPos.x - curPos.x))*(180 / Math.PI);

}

// Quadrant 3 (Angles 180-270)

if ((nexPos.z < curPos.z) && (nexPos.x < curPos.x)) {

nexDeg = 180 + Math.atan((curPos.x - nexPos.x)/(curPos.z - nexPos.z))*(180 / Math.PI);

}

// Quadrant 4 (Angles 270-360)

if ((nexPos.z > curPos.z) && (nexPos.x < curPos.x)) {

nexDeg = 270 + Math.atan((nexPos.z - curPos.z)/(curPos.x - nexPos.x))*(180 / Math.PI);

}

// After we figure out how many degrees from 0 this item is with our object being point 0,0,0. We can rotate to it's direction

var a = GetCellRotation(cell);

var rot = new Quaternion();

rot.x = quatToDeg(a.x);

rot.y = nexDeg;

rot.z = quatToDeg(a.z);

rotate(cell,rot.x,rot.y,rot.z);

}


function isValidWP(scheme,num) {

// Check to see if cell with name <scheme>-<num> exists

var nextname = scheme + "-" + num;

try {

$(nextname).getPosition();

return true;

} catch(err) {

return false;

}

return false;

}

function getNextWP(current) {

// Waypoint naming scheme <group>-<wp #>

// Waypoints start at <group>-1

var pieces = current.split("-");

var next = parseInt(pieces[1]) + 1;

return isValidWP(pieces[0],next); }

function moveTo(destObj) {

// destObj is the name of the cell to move to

try {

var a = $(destObj).getPosition();

var b = GetCellPosition(cell);

a.y = a.y + height_offset;

var toSqrt = Math.pow((a.x - b.x),2) + Math.pow((a.y - b.y),2) + Math.pow((a.z - b.z),2);

var distance = Math.sqrt(toSqrt);

var time = distance / speed;

animateMove(cell, (a.x - b.x), (a.y - b.y), (a.z - b.z), time);

} catch (err) {

//ShowHUDMessage("destObj: " + destObj + " - Error: " + err);

}

}

function main() {

// This is where the fun happens (sort of)

while (1) {

for (var i = 0; i < Paths.length; i++) {

for (var n = 1; isValidWP(Paths[i],n); n++) {

var name = Paths[i] + "-" + n;

pointTo(name);

moveTo(name);

}

}

}

}


main();