Difference between revisions of "Space.as"

From Organic Design wiki
m
Line 1: Line 1:
// Liscenced under LGPL: www.gnu.org/copyleft/lesser.html
+
// Liscenced under LGPL: www.gnu.org/copyleft/lesser.html{{as}}
 
//
 
//
 
// space.as - 3D space with dynamics and recursion
 
// space.as - 3D space with dynamics and recursion

Revision as of 08:32, 20 October 2007

// Liscenced under LGPL: www.gnu.org/copyleft/lesser.htmlTemplate:As // // space.as - 3D space with dynamics and recursion // Nad - 2003 for Amanda's SIC-Games project //

// Initialise passed movieclip as a 3D space create.space = function( name, layer ) { this.createEmptyMovieClip( name, layer ); var newSpace = this[name]; newSpace._x = _root.width / 2; newSpace._y = _root.height / 2; newSpace.create = _root.space.create; newSpace.reduce = _root.space.reduce; newSpace.space = newSpace; // create() function used at all levels expects space to be this.space; newSpace.rotation = 0; // global rotation of space newSpace.zbuff = []; // Z ordered symbol-refs of all 3D objects newSpace.zbLength = 0; // Since zbuff is sorted, we can use an end-ptr instead of pushing/splicing newSpace.children = []; // Top layer children newSpace.template = _root.template; // Template object for creating new symbols into the space newSpace.zSCREEN = 1000; // Distance from origin (eye) to screen // Sort function for zbuff array newSpace.zcmp = function( a, b ) { return a.az < b.az; }; return newSpace; };


// SPACE.CREATE // Method: The space and all its objects inherit this method for creating child objects // Creates a symbol for the 3D-object (spacer is used if classes[thisClass].symbol == null) // The passed data object extends the space.template used to initialise the new object space = {}; space.create = function( parameters ) { var space = this.space; var time = _root.time; var instanceName = parameters[1]; if ( instanceName == null ) instanceName = 'i' + int( 1000000 * Math.random() ) + getTimer(); var symbol, hasSymbol = false; var class = parameters[0]; var classRef = _root.classes[class]; if ( class == 'obj' ) symbol = parameters[2]; else symbol = classRef.symbol; // Create new child symbol using the 3D-object template (space.template) space.createEmptyMovieClip( instanceName, space.zbLength ); var child = space[instanceName]; if ( symbol != null ) { _root.createSymbol( child, symbol, 'swf', 0 ); child.hasSymbol = true; } else child.hasSymbol = false; var template = space.template; for ( var i in template ) child[i] = template[i]; this.children.push( child ); // object available in hierachical update tree of reduce() calls space.zbuff[space.zbLength++] = child; // place object into z-buffer for layer sorting // Populate new child symbol/object for ( var i in classRef ) child[i] = classRef[i]; child.space = space; child.class = class; child.parent = this; child.children = []; child.time = time; child.colour = new Color( child.swf ); child.die = false; // Set the objects' dynamics() and call its init() - parameters[0] is 3DO-class if ( classRef.init != null ) classRef.init.call( child, parameters ); return child; };


// SPACE.REDUCE space.reduce = function() { var space = this.space; var zbuff = space.zbuff;

// Execute the template.reduce() of each top-level child for ( var i = this.children.length-1; i >= 0; i-- ) { var obj = this.children[i]; obj.ax = obj.ay = obj.az = 0; obj.reduce(); // delete from this child list if marked for death if ( obj.die ) this.children.splice( i, 1 ); }

// Reduce the 3D coordinates to 2D for *ALL* objects with symbols (ie all layers, empty) // - ax,ay,az are absolute positions calculated in child reduce() exec layers for ( var i = 0; i < space.zbLength; i++ ) { var obj = zbuff[i]; if ( obj.die ) obj.az = -100000000; // dead ones will get sorted to the end else { // Global rotation if ( space.rotation != 0 ) obj.rotate( 'ax', 'az', space.rotation ); // Reduce 3D ( x,y,x -> _x,_y,scale ) var m = space.zSCREEN / obj.az; obj._x = obj.ax * m; obj._y = obj.ay * m; if ( m < 0 ) m = 0; else if ( m > 10 ) m = 10; obj._xscale = obj._yscale = obj.scale * m; // Lightness ( based on 3D scale multiplier ) if ( m < 0.5 ) light = 0.5; else if ( m < 1.5 ) light = 0.5 + ( m - 0.5 ); else light = 1; obj.colour.setTransform( { ra:obj.ra * light, ga:obj.ga * light, ba:obj.ba * light, ab:obj.alpha } ); } }

// Sort zbuff, set depths and remove dead children zbuff.sort( space.zcmp ); while ( zbuff[space.zbLength-1].die ) zbuff[--space.zbLength].removeMovieClip(); for ( var i = 0; i < space.zbLength; i++ ) zbuff[i].swapDepths(i);

};


// TEMPLATE // - Create a set of methods and properties inherited by all symbols created in the space // - various dynamics() and effects() can add and maintain other properties template = {}; template.space = null; // set by create() A ref to the space object template.create = space.create; // Inherits generic create() method template.parent = null; // Set by create(), a ref to the parent of this object template.children = null; // Children of this object (must be initialised by create) template.die = false; // Object deletion must be handled ny the space.reduce() template.motion = []; // Motion functions to call in reduce() template.colour = null; // Set by create() - objects colour transform template.scale = 100; // symbol scale template.alpha = 100; // symbol scale template.time = 0; // Objects' absolute birth time template.x = 0; // Objects relative position (ie relative to birth location and time) template.y = 0; // template.z = 0; // template.ra = 100; // Colour transform properties template.ga = 100; // template.ba = 100; //

// per-frame method for 3D-objects (not the space itself which has its own frame function) // - reduce() calculates the absolute position from the relative positions in the parent-child chain of each object template.reduce = function() { var t = _root.time - this.time;

// Update objects dynamic properties if ( !this.die ) { if ( this.dynamics != null ) this.dynamics(t); // Execute this objects' current motion effects x += f(t) for ( var i = 0; i < this.motion.length; i++ ) this.motion[i].call( this, t ); // Update absolute location for space.reduce() to render this.ax += this.x; this.ay += this.y; this.az += this.z; }

// Execute the reduce() of each child // - if this is dead, propagate death to descendents for ( var i = this.children.length-1; i >= 0; --i ) { var obj = this.children[i]; if ( this.die ) obj.die = true; else { obj.ax = this.ax; obj.ay = this.ay; obj.az = this.az; } obj.reduce.call(obj); } };

// Rotate an object template.rotate = function( x, y, a ) { a += Math.atan2( this.y, this.x ); var r = Math.sqrt( this.x*this.x+this.y*this.y ); this.x = Math.cos(a)*r; this.y = Math.sin(a)*r; };


// 3D OBJECT CLASSES

// NOTE: (Not using languages' classes here as actionscript too lame-arse) // Each class has: // - init(data) used to create and layout child objects within itself (and can instantiate an asscoiated symbol too) // - dynamics() called from it's reduce() which then also calls space.update // each dynamics can call a set of effects functions depending on its state and time // NOTE: dynamics must base all changes on time // NOTE: dynamics are responsible for their coordinates being relative to parent // - this is because some dynamics update their own coodinates and some their childrens // - classes may has only a symbol and no init() or dynamics()

// these phases and layers should be tree nodes classes = {};


// SPARK classes.spark = {}; classes.spark.init = function(parameters) { this.lat = parameters[2]; this.lon = parameters[3]; }; classes.spark.symbol = 'radial';


// BALL

  1. include "ball.as"

classes.ball = {}; classes.ball.init = function(parameters) { this.lat = parameters[2]; this.lon = parameters[3]; this.motion = [ _root.motion.float ]; }; classes.ball.symbol = 'ball';


// STAR-BURST CLASS classes.starBurst = {}; classes.starBurst.symbol = 'radial'; classes.subBurst = {}; // starBurst: stars,force,x,y,z classes.starBurst.init = function(parameters) { var guid = parameters[0]; this.stars = parameters[2]; this.force = parameters[3]; this.x = 1.0 * parameters[4]; this.y = 1.0 * parameters[5]; this.z = 1.0 * parameters[5]; this._visible = false; var ri = this.time; for ( var i = 0; i < this.stars; i++ ) { var lat = _root.rnd( ri, 1 ) * 2 * Math.PI; var lon = _root.rnd( ri + 10, 1 ) * 2 * Math.PI; ri += 20; var obj = this.create( [ 'subBurst', null, 4, 1.5, 500, lat, lon, ri ] ); } }; // subBurst: stars,force,start,fadeout,lat,lon classes.subBurst.init = function( parameters ) { this.stars = parameters[2]; this.force = parameters[3]; this.start = parameters[4]; this.lat = parameters[5]; this.lon = parameters[5]; var ri = 1 * parameters[7]; for ( var i = 0; i < this.stars; i++ ) { var lat = _root.rnd( ri, 3 ) * 2 * Math.PI; var lon = _root.rnd( ri + 31, 3) * 2 * Math.PI; ri += 51; var obj = this.create( [ 'spark', null, lat, lon ] ); obj.index = i; } }; classes.subBurst.symbol = 'radial'; classes.starBurst.dynamics = function(t) { var onlyOne = true; // This is a subBurst if (this.start != null) { this.swf.gotoAndStop(4); if (t > this.start) { this.radius = (t-this.start)*this.force; onlyOne = false; } } else { this.swf.gotoAndStop(1); this.radius = 100+t*this.force; } this.force = this.force*0.97; if (this.alpha < 0) this.alpha = 0; var a = 100-(t/30); if (a < 0) { if (this.parent == this.space) this.die = true; a = 0; } // Update child positions: x = 0 + f(t) stylz for (var i = 0; i < this.children.length; i++) { var star = this.children[i]; var s = this.radius*Math.cos(star.lon); star.x = s*Math.cos(star.lat+t/500); star.y = this.radius*Math.sin(star.lon)+t*t/8000; star.z = s*Math.sin(star.lat+t/500); if (onlyOne && (i>0)) star.alpha = 0; else star.alpha = a; } }; classes.subBurst.dynamics = classes.starBurst.dynamics;


// TORUS CLASS classes.torus = {}; classes.torus.init = function( parameters ) { this.points = 1 * parameters[2]; this.radius = 1.0 * parameters[3]; this.speed = 1.0 * parameters[4]; var arc = 2 * Math.PI / this.points; for ( var i = 0; i < this.points; i++ ) { obj = this.create( [ 'ball', null, 50 ] ); obj.arc = arc * i; obj.floatOffset = Math.random() * 2 * Math.PI; j = i + 1; //obj.ra = (j & 1) ? 0xff : 0; //obj.ga = (j & 2) ? 0xff : 0; //obj.ba = (j & 4) ? 0xff : 0; } }; classes.torus.dynamics = function(t) { this.x = _root._xmouse - _root.width / 2; this.y = _root._ymouse - _root.height / 2; this.Z = 1000; for ( var i = 0; i < this.children.length; i++ ) { var point = this.children[i]; var angle = point.arc + this.angle / this.children.length + t / this.speed; var r = this.parent.radius + this.radius * Math.sin( angle ); point.x = this.x + r * Math.cos( this.angle ); point.z = this.z + 5 * this.radius * Math.cos( angle ); point.y = this.y + r * Math.sin( this.angle ); } };


// IMPLODE CLASS classes.implode = {}; classes.implode.init = function( parameters ) { this.stars = 25; this.radius = 200; this.x = 1.0 * parameters[2]; this.y = 1.0 * parameters[3]; this.z = 1.0 * parameters[4]; var ri = this.time; for ( var i = 0; i < this.stars; i++ ) { var lat = _root.rnd( ri, 1 ) * 2 * Math.PI; var lon = _root.rnd( ri + 10, 1 ) * 2 * Math.PI; var obj = this.create( [ 'spark', null, lat, lon ] ); obj.v = _root.rnd( ri + 20, 1 ) * 100 + 10; obj.scale = 50; ri += 30; } }; classes.implode.dynamics = function(t) { this.radius = 500 - t / 3; if ( this.radius < 100 ) this.radius = 100; var a = t / 10; if ( a > 200 ) this.die = true; if ( a > 100 ) a = 200 - a; for ( var i = 0; i < this.children.length; i++ ) { var star = this.children[i]; var r = this.radius * star.v / 50; var s = r * Math.cos( star.lon ); star.x = s * Math.cos( star.lat + t / star.v / 2 ); star.y = r * Math.sin( star.lon); star.z = s * Math.sin( star.lat + t / star.v / 2 ); star.alpha = a / 2; } };


// STARFIELD CLASS classes.starField = {}; classes.starField.init = function(parameters) { this.stars = 100; this.radius = 2000; var ri = this.time; for ( var i = 0; i < this.stars; i++ ) { var lat = _root.rnd( ri, 1 ) * 2 * Math.PI; var lon = _root.rnd( ri + 10, 1 ) * 2 * Math.PI; var obj = this.create( [ 'spark', null, lat, lon ] ); obj.v = _root.rnd( ri + 20, 1 ) * 100 + 10; obj.scale = 50; ri += 30; } }; classes.starField.dynamics = function(t) { this.radius = 500 - t/3; if ( this.radius < 100 ) this.radius = 100; var a = t / 10; if ( a > 200 ) this.die = true; if ( a > 100 ) a = 200 - a; for ( var i = 0; i < this.children.length; i++ ) { var star = this.children[i]; var r = this.radius * star.v / 50; var s = r * Math.cos( star.lon ); star.x = s * Math.cos( star.lat + t / star.v / 2 ); star.y = r * Math.sin( star.lon ); star.z = s * Math.sin( star.lat + t / star.v / 2 ); star.alpha = a / 2; } };


// 3D MOTION f(t) CLASSES // - 3D Motion functions called by an objects' reduce() if in its motion[] list

// Float // - Adds the metaparticles movement to passed object motion = {}; motion.float = function(t) { var a = this.floatOffset + t / 400; var m = ( this._width + this._height ) * this.scale / 1000; var api4 = a * Math.PI / 4; var api8 = a * Math.PI / 8; var cospi4 = Math.cos( api4 ); var cospi8 = Math.cos( api8 ); var sinpi4 = Math.sin( api4 ); var sinpi8 = Math.sin( api8 ); this.x += m * cospi4 * sinpi8; this.y += m * cospi4 * cospi8; this.z += m * sinpi4; };

// Square-sine motion.squareSine = function(t) { var i = Math.floor( t/Math.PI ) % 6; if ( (i == 1) || (i == 2) ) return -1; if ( i > 3 ) return 1; return Math.cos(t); };