Flash Advisor logo
:: Desktop Shortcut
:: Flash Help
Advice from Experts

Closed Thread
Results 1 to 4 of 4
  1. #1
    Join Date
    May 2004
    Location
    U.S.A.
    Posts
    2,890

    Default How to create a 3D world

    Hi,

    As we all know, Flash is a vector art program and is limited to two dimensions....._x axis and _y axis. This thread will show one way to create a _z axis that will simulate a 3rd dimension....depth. This is not to be confused with the depth levels used in Flash. First thing to do is create a background. You can do this by simply creating a movieclip that uses a linear fill so that the bottom looks like ground and the top looks like sky....basically a linear fill of green to blue. However, I am an Actionscript junkie and discovered a way for the graphical world to be created with Actionscript. This particular project is geared toward Flash player version 6 r 65. Open a new movie and select the publish options. Select flash player version 6 and check the "optimize for flash6 r65. I am going to detail this project in a couple of posts as it will be rather lengthy. Here is what the linear world Actionscript looks like.....
    Code:
    /*
    TransformMatrix.as
    Matrix helper for Flash MX drawing functions
    Christopher Thilgen
    Macromedia
    */
    function TransformMatrix() {
    	this.empty = true;
    }
    TransformMatrix.prototype.isEmpty = function() {
    	return this.empty;
    }
    TransformMatrix.prototype.init = function(a, b, d, e, g, h) {
    	this.a = a;
    	this.d = d;
    	this.g = g;
    	this.b = b;
    	this.e = e;
    	this.h = h;
    	this.c = 0;
    	this.f = 0;
    	this.i = 1;
    	this.empty = false;
    }
    TransformMatrix.prototype.concat = function(m) {
    	if (this.isEmpty()) {
    		this.a = m.a;
    		this.d = m.d;
    		this.g = m.g;
    		this.b = m.b;
    		this.e = m.e;
    		this.h = m.h;
    		this.c = m.c;
    		this.f = m.f;
    		this.i = m.i;
    	} else {
    		var result = new TransformMatrix();
    		result.a = this.a*m.a+this.b*m.d+this.c*m.g;
    		result.b = this.a*m.b+this.b*m.e+this.c*m.h;
    		result.c = this.a*m.c+this.b*m.f+this.c*m.i;
    		result.d = this.d*m.a+this.e*m.d+this.f*m.g;
    		result.e = this.d*m.b+this.e*m.e+this.f*m.h;
    		result.f = this.d*m.c+this.e*m.f+this.f*m.i;
    		result.g = this.g*m.a+this.h*m.d+this.i*m.g;
    		result.h = this.g*m.b+this.h*m.e+this.i*m.h;
    		result.i = this.g*m.c+this.h*m.f+this.i*m.i;
    		this.a = result.a;
    		this.d = result.d;
    		this.g = result.g;
    		this.b = result.b;
    		this.e = result.e;
    		this.h = result.h;
    		this.c = result.c;
    		this.f = result.f;
    		this.i = result.i;
    	}
    	this.empty = false;
    }
    TransformMatrix.prototype.scale = function(sx, sy) {
    	var m = new TransformMatrix();
    	m.init(sx, 0, 0, sy, 0, 0);
    	return (this.concat(m));
    }
    TransformMatrix.prototype.translate = function(tx, ty) {
    	var m = new TransformMatrix();
    	m.init(1, 0, 0, 1, tx, ty);
    	return (this.concat(m));
    }
    TransformMatrix.prototype.rotate = function(r) {
    	// r is in degrees - must convert to radians
    	var rad = (r/180)*Math.PI;
    	var m = new TransformMatrix();
    	var cosVal = Math.cos(rad);
    	var sinVal = Math.sin(rad);
    	m.init(cosVal, sinVal, -sinVal, cosVal, 0, 0);
    	return (this.concat(m));
    }
    function TransformMatrix() {
    	this.empty = true;
    }
    TransformMatrix.prototype.isEmpty = function() {
    	return this.empty;
    }
    TransformMatrix.prototype.init = function(a, b, d, e, g, h) {
    	this.a = a;
    	this.d = d;
    	this.g = g;
    	this.b = b;
    	this.e = e;
    	this.h = h;
    	this.c = 0;
    	this.f = 0;
    	this.i = 1;
    	this.empty = false;
    }
    TransformMatrix.prototype.concat = function(m) {
    	if (this.isEmpty()) {
    		this.a = m.a;
    		this.d = m.d;
    		this.g = m.g;
    		this.b = m.b;
    		this.e = m.e;
    		this.h = m.h;
    		this.c = m.c;
    		this.f = m.f;
    		this.i = m.i;
    	} else {
    		var result = new TransformMatrix();
    		result.a = this.a*m.a+this.b*m.d+this.c*m.g;
    		result.b = this.a*m.b+this.b*m.e+this.c*m.h;
    		result.c = this.a*m.c+this.b*m.f+this.c*m.i;
    		result.d = this.d*m.a+this.e*m.d+this.f*m.g;
    		result.e = this.d*m.b+this.e*m.e+this.f*m.h;
    		result.f = this.d*m.c+this.e*m.f+this.f*m.i;
    		result.g = this.g*m.a+this.h*m.d+this.i*m.g;
    		result.h = this.g*m.b+this.h*m.e+this.i*m.h;
    		result.i = this.g*m.c+this.h*m.f+this.i*m.i;
    		this.a = result.a;
    		this.d = result.d;
    		this.g = result.g;
    		this.b = result.b;
    		this.e = result.e;
    		this.h = result.h;
    		this.c = result.c;
    		this.f = result.f;
    		this.i = result.i;
    	}
    	this.empty = false;
    }
    TransformMatrix.prototype.scale = function(sx, sy) {
    	var m = new TransformMatrix();
    	m.init(sx, 0, 0, sy, 0, 0);
    	return (this.concat(m));
    }
    TransformMatrix.prototype.translate = function(tx, ty) {
    	var m = new TransformMatrix();
    	m.init(1, 0, 0, 1, tx, ty);
    	return (this.concat(m));
    }
    TransformMatrix.prototype.rotate = function(r) {
    	// r is in degrees - must convert to radians
    	var rad = (r/180)*Math.PI;
    	var m = new TransformMatrix();
    	var cosVal = Math.cos(rad);
    	var sinVal = Math.sin(rad);
    	m.init(cosVal, sinVal, -sinVal, cosVal, 0, 0);
    	return (this.concat(m));
    }
    //-----------Create World-------------- 
    _root.createEmptyMovieClip("world", 100);
    //Create world atmosphere
    with (_root.world) {
    	colors = [0x0099FF, 0x006600];
    	alphas = [100, 100];
    	ratios = [0, 0xFF];
    	matrix = new TransformMatrix();
    	matrix.scale(400, 200);
    	matrix.translate(300, 300);
    	matrix.rotate(90);
    	beginGradientFill("linear", colors, alphas, ratios, matrix);
    	moveto(0, 0);
    	lineto(0, Stage.width);
    	lineto(Stage.width, Stage.height);
    	lineto(Stage.width, Stage.height);
    	lineto(Stage.width, 0);
    	endFill();
    }
    The above simply creates a world movieclip with a linear fill that covers the stage. In my next visit, I will describe how to create a 3rd dimension with Actionscript and place objects in the 3D world using arrays and for loops.

    Regards
    NTD
    A mind once stretched by a new idea never regains its original dimensions.
    - Oliver Wendell Holmes

  2. # ADS
    Join Date
    Always
    Location
    Advertising world
    Posts
    Many
     
  3. #2
    Join Date
    May 2004
    Location
    U.S.A.
    Posts
    2,890

    Default

    Part 2.....Actionscript

    The way I choose to approach this is to use the attachMovie method to attach objects to the world dynamically. Any object you want to place in the world needs to have a linkage identifier set and export for actionscript selected when the movieclip is created. You can then store the names of the objects to be placed in an array and use a for loop to cycle through the array. This saves LOTS of time over manually placing objects. The position of the mouse on the screen will determine motion speed and direction of movement in the world space. This could be converted to key motion but I like how the mouse method works. I use arrays extensivly to store data. Here is how I set up attaching objects in the 3D space...
    Code:
    //test code to demo object placement in world
    stop();
    WorldObjects = 1;
    ObjectName = ["cube"];
    MapItem = [0];
    MapItemX = [0];
    MapItemY = [100];
    The above simply places a single object in the 3D world and gives you an idea of how to structure the coordinates. Once I post the guts of the project, test out the above method by populating it with multiple objects and coordinates. Now we need an empty object to store data like names, x, y, and z location and a custom function to place the objects in the created 3D world...
    Code:
    //Object holder array to push the name,_x, and _y position of each object 
    _root.objectHolder = [];
    function placeObjects() {
    	//populate the objectHolder array
    	for (Mycount=0; Mycount<_root.WorldObjects; Mycount++) {
    		_root.objectHolder.push({objType:_root.ObjectName[_root.MapItem[Mycount]], X:_root.MapItemX[Mycount], Y:_root.MapItemY[Mycount]});
    		_root.hit = true;
    		//trace(_root.objectHolder[myCount].Y);
    	}
    	//place objects in the world
    	for (i=0; i<_root.objectHolder.length; ++i) {
    		worldObject = _root.attachMovie(_root.objectHolder[i].objType, "worldObject"+i, i);
    		worldObject._visible = false;
    		worldObject.X = _root.objectHolder[i].X;
    		worldObject.Y = _root.objectHolder[i].Y;
    		worldObject.Z = 0;
    		objName = _root.objectHolder[i].objType;
    		//rollover event for all objects
    		worldObject.onRollOver = function() {
    			//trace(this._name);
    			//trace("X= "+this.X+" Y= "+this.Y);
    		}
    		//set the objects to the moveWorld prototype     
    		worldObject.moveworld();
    	}
    	//initiate object placement on initial load
    	myInterval = setInterval(startMove, 100);
    }
    A couple more custom functions to monitor world events, motion and placement of objects......code comments on what is being done...
    Code:
    //function to clear the place objects initiator so the world wont auto scroll
    function startMove() {
    	_root.hit = false;
    	clearInterval(myInterval);
    }
    //control motion with mousedown and key event
    world.onMouseDown = function() {
    	_root.hit = true;
    }
    //stop motion of world 
    world.onMouseUp = function() {
    	_root.hit = false;
    }
    //monitor if motion is needed
    world.onEnterFrame = function() {
    	if (_root.hit == true) {
    		for (j=0; j<_root.objectHolder.length; ++j) {
    			_root["worldObject"+j].moveworld();
    		}
    	}
    }
    //enterframe event to power variable declarations
    this.onEnterFrame = function() {
    	if (!go) {
    		go = true;
    		X = -250;
    		Y = -1400;
    		angle = 2.935;
    		Z = 200;
    		hide_dist = 6000;
    		hide_dist1 = hide_dist/200;
    		pi2 = Math.PI*2;
    		hide_area = Math.PI/4;
    	}
    	if (_root.hit == true) {
    		angle = angle+(_root._xmouse-_root.world._width/2)/8000;
    		if (Math.abs(angle)>Math.PI) {
    			angle = -angle;
    		}
    		step = (_root._ymouse-_root.world._height/2)/10;
    		Y = Y+Math.cos(angle)*step;
    		X = X+Math.sin(angle)*step;
    	}
    }
    and finally, the guts of the project...
    Code:
    //Prototype moveworld function to control motion, fog, and hide distance
    MovieClip.prototype.moveworld = function() {
    	with (this) {
    		y1 = Y-_root.Y;
    		x1 = X-_root.X;
    		if (Math.abs(y1)>hide_dist | Math.abs(x1)>hide_dist) {
    			_visible = false;
    		} else {
    			//Variable = (condition) ? true actions: false actions)
    			angleAdjust = Math.atan(x1/y1)-((y1>0) ? Math.PI : 0);
    			hideObjects = _root.angle-angleAdjust;
    			hideObjects = (hideObjects>Math.PI) ? (hideObjects-pi2) : ((hideObjects<-Math.PI) ? (hideObjects+pi2) : hideObjects);
    			if (Math.abs(hideObjects)>hide_area) {
    				_visible = false;
    			} else {
    				distA = Math.sqrt(x1*x1+y1*y1)*Math.cos(hideObjects);
    				if (distA>hide_dist) {
    					_visible = false;
    				} else {
    					_visible = true;
    					_x = _root.world._width/2-_root.world._width*Math.sin(hideObjects);
    					ratio = _root.world._width/distA;
    					_y = _root.world._height/2-ratio*(Z-_root.Z)-100;
    					_xscale = _yscale=ratio*100;
    					swapDepths(hide_dist-distA+1000);
    					fog = new Color(this);
    					fog_density = [];
    					ca = 100-distA/(hide_dist1*2);
    					cb = distA/hide_dist1;
    					fog_density.ra = ca;
    					fog_density.rb = cb;
    					fog_density.ga = ca;
    					fog_density.gb = cb;
    					fog_density.ba = ca;
    					fog_density.bb = cb;
    					fog.setTransform(fog_density);
    				}
    			}
    		}
    	}
    }
    When combined, the 3D simulation works very well. I can forsee some performance issues if you get into large numbers of objects but if used creatively, it could be the base engine for any kind of first person shooter game or interactive application. My next post will simply be a demo of the code organized together.

    NTD
    Last edited by NTD; 03-14-2008 at 02:28 PM.
    A mind once stretched by a new idea never regains its original dimensions.
    - Oliver Wendell Holmes

  4. #3
    Join Date
    May 2004
    Location
    U.S.A.
    Posts
    2,890

    Default

    combined code...
    Code:
    /*
        3D World Demo
            By
         T.Norman
    http://ntdesigns.net
    */
    //Names of movieclips to be attached to world... export identifier names
    ObjectName = ["box", "ball", "triangle", "cube"];
    //Total objects to be placed in world...length will match the following 3 object arrays
    WorldObjects = 5;
    //Numerical value of ObjectName array items for easier world placement...0 = "box"...etc...
    MapItem = [1, 2, 3, 0, 2];
    //Object world _x position
    MapItemX = [0, 100, 200, 300, 400];
    //Object world _y position
    MapItemY = [0, 200, 400, 600, 800];
    //Object holder array to push the name,_x, and _y position of each object 
    _root.objectHolder = [];
    function placeObjects() {
    	//populate the objectHolder array
    	for (Mycount=0; Mycount<_root.WorldObjects; Mycount++) {
    		_root.objectHolder.push({objType:_root.ObjectName[_root.MapItem[Mycount]], X:_root.MapItemX[Mycount], Y:_root.MapItemY[Mycount]});
    		_root.hit = true;
    		//trace(_root.objectHolder[myCount].Y);
    	}
    	//place objects in the world
    	for (i=0; i<_root.objectHolder.length; ++i) {
    		worldObject = _root.attachMovie(_root.objectHolder[i].objType, "worldObject"+i, i);
    		worldObject._visible = false;
    		worldObject.X = _root.objectHolder[i].X;
    		worldObject.Y = _root.objectHolder[i].Y;
    		worldObject.Z = 0;
    		objName = _root.objectHolder[i].objType;
    		//rollover event for all objects
    		worldObject.onRollOver = function() {
    			//trace(this._name);
    			//trace("X= "+this.X+" Y= "+this.Y);
    		}
    		//set the objects to the moveWorld prototype     
    		worldObject.moveworld();
    	}
    	//initiate object placement on initial load
    	myInterval = setInterval(startMove, 100);
    }
    //function to clear the place objects initiator so the world wont auto scroll
    function startMove() {
    	_root.hit = false;
    	clearInterval(myInterval);
    }
    //control motion with mousedown and key event
    world.onMouseDown = function() {
    	_root.hit = true;
    }
    //stop motion of world 
    world.onMouseUp = function() {
    	_root.hit = false;
    }
    //monitor if motion is needed
    world.onEnterFrame = function() {
    	if (_root.hit == true) {
    		for (j=0; j<_root.objectHolder.length; ++j) {
    			_root["worldObject"+j].moveworld();
    		}
    	}
    }
    placeObjects();
    //enterframe event to power variable declarations
    //play around with some of these numbers for different perspectives
    this.onEnterFrame = function() {
    	if (!go) {
    		go = true;
    		X = -250;
    		Y = -1400;
    		angle = 2.935;
    		Z = 200;
    		hide_dist = 6000;
    		hide_dist1 = hide_dist/200;
    		pi2 = Math.PI*2;
    		hide_area = Math.PI/4;
    	}
    	if (_root.hit == true) {
    		removelaser();
    		angle = angle+(_root._xmouse-_root.world._width/2)/8000;
    		if (Math.abs(angle)>Math.PI) {
    			angle = -angle;
    		}
    		step = (_root._ymouse-_root.world._height/2)/10;
    		Y = Y+Math.cos(angle)*step;
    		X = X+Math.sin(angle)*step;
    	}
    }
    //Prototype moveworld function to control motion, fog, and hide distance
    MovieClip.prototype.moveworld = function() {
    	with (this) {
    		y1 = Y-_root.Y;
    		x1 = X-_root.X;
    		if (Math.abs(y1)>hide_dist | Math.abs(x1)>hide_dist) {
    			_visible = false;
    		} else {
    			//Variable = (condition) ? true actions: false actions)
    			angleAdjust = Math.atan(x1/y1)-((y1>0) ? Math.PI : 0);
    			hideObjects = _root.angle-angleAdjust;
    			hideObjects = (hideObjects>Math.PI) ? (hideObjects-pi2) : ((hideObjects<-Math.PI) ? (hideObjects+pi2) : hideObjects);
    			if (Math.abs(hideObjects)>hide_area) {
    				_visible = false;
    			} else {
    				distA = Math.sqrt(x1*x1+y1*y1)*Math.cos(hideObjects);
    				if (distA>hide_dist) {
    					_visible = false;
    				} else {
    					_visible = true;
    					_x = _root.world._width/2-_root.world._width*Math.sin(hideObjects);
    					ratio = _root.world._width/distA;
    					_y = _root.world._height/2-ratio*(Z-_root.Z)-100;
    					_xscale = _yscale=ratio*100;
    					swapDepths(hide_dist-distA+1000);
    					fog = new Color(this);
    					fog_density = [];
    					ca = 100-distA/(hide_dist1*2);
    					cb = distA/hide_dist1;
    					fog_density.ra = ca;
    					fog_density.rb = cb;
    					fog_density.ga = ca;
    					fog_density.gb = cb;
    					fog_density.ba = ca;
    					fog_density.bb = cb;
    					fog.setTransform(fog_density);
    				}
    			}
    		}
    	}
    }
    demo with a few additions such as a main character...

    Space bar + mouse down for movement....

    edit* I no longer maintain a website for this demo. Maybe will again if any interest.

    Hope it's useful
    Regards
    NTD
    Last edited by NTD; 01-12-2011 at 05:28 PM.
    A mind once stretched by a new idea never regains its original dimensions.
    - Oliver Wendell Holmes

  5. #4
    Join Date
    Jun 2009
    Location
    Houston, Tx
    Posts
    482

    Default

    Hello. Link isn't working anymore. Please fix!

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

     

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
Sponsors
Create Speaking Characters for your website and Flash movies. 15 Day Free Trial