Space.as

From Organic Design
Jump to: navigation, search
Legacy.svg Legacy: This article describes a concept that has been superseded in the course of ongoing development on the Organic Design wiki. Please do not develop this any further or base work on this concept, this is only useful for a historic record of work done. You may find a link to the currently used concept or function in this article, if not you can contact the author to find out what has taken the place of this legacy item.

<as> // Liscenced under LGPL: www.gnu.org/copyleft/lesser.html // // 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); }; </as>