3D Movement in a moving 3D Environment

3D Movement in a moving 3D Environment

With the code derived from the last post I wanted to try to get multiple (partly moving) objects into an environment that moves. Done. There are two “racers” on a plane. One of the racers is moving while the “camera” is panning around the plane.

Interested in the source? It would definitely look better if it wasn’t timeline code.

var world:MovieClip = new MovieClip();
world.x = stage.stageWidth*0.5;
world.y = stage.stageHeight*0.5;
addChild( world );

var focalLength:Number = 500;

var allPointsArray:Array = new Array();
var centerPointsArray:Array = new Array();

var triangleArray:Array = new Array();

var plane = new Object();
plane.center = make3DCenter( 0, 0, 0, plane );
plane.rot = make3DCenter( 0, 0, 0, plane );
plane.pointsArray = [
					make3DPoint(-200,-200,0, plane),
					make3DPoint(-200,200,0, plane),
					make3DPoint(200,200,0, plane),
					make3DPoint(200,-200,0, plane),
					];

plane.triangles = [
				   makeTriangle(plane.pointsArray[0], plane.pointsArray[1], plane.pointsArray[2], 0x000000),
				   makeTriangle(plane.pointsArray[0], plane.pointsArray[2], plane.pointsArray[3], 0xdddddd)
				   ];


var object1 = new Object();
object1.center = make3DCenter( 0, 100, 0, object1 );
object1.rot = make3DCenter( 0, 0, 0, object1 );
object1.pointsArray = [
					   make3DPoint( 30,  0,  0, object1),
					   make3DPoint(-30,  0,  -20, object1),
					   make3DPoint(-30,-20,  0, object1),
					   make3DPoint(-30, 20,  0, object1)

];
object1.triangles = [
					 makeTriangle( object1.pointsArray[0], object1.pointsArray[2], object1.pointsArray[1], 0xff0000),
					 makeTriangle( object1.pointsArray[0], object1.pointsArray[1], object1.pointsArray[3], 0x0000ff),
					 makeTriangle( object1.pointsArray[1], object1.pointsArray[2], object1.pointsArray[3], 0x00ff00)
					 ];
object1.vx = 5;
object1.vy = 5;

var object2 = new Object();
object2.center = make3DCenter( 100, 100, 0, object2 );
object2.rot = make3DCenter( 0, 0, 0, object2 );
object2.pointsArray = [
					   make3DPoint( 30,  0,  0, object2),
					   make3DPoint(-30,  0,  -20, object2),
					   make3DPoint(-30,-20,  0, object2),
					   make3DPoint(-30, 20,  0, object2)

];
object2.triangles = [
					 makeTriangle( object2.pointsArray[0], object2.pointsArray[2], object2.pointsArray[1], 0xff0000),
					 makeTriangle( object2.pointsArray[0], object2.pointsArray[1], object2.pointsArray[3], 0x0000ff),
					 makeTriangle( object2.pointsArray[1], object2.pointsArray[2], object2.pointsArray[3], 0x00ff00)
					 ];
object2.vx = 0;
object2.vy = 0;

function makeTriangle( p1, p2, p3, col)
{
	var triangle = new Object();
	triangle.points = [p1, p2, p3];
	triangle.col = col;
	triangleArray.push( triangle );
}

function make3DCenter ( x, y, z, o)
{
	var point = new Object();
	point.x = x;
	point.y = y;
	point.z = z;
	point.o = o;
	centerPointsArray.push(point);
	return point;
};

function make3DPoint ( x, y, z, o)
{
	var point = new Object();
	point.ox = x;
	point.x = x;
	point.oy = y;
	point.y = y;
	point.oz = z;
	point.z = z;
	point.o = o;
	allPointsArray.push(point);
	return point;
};

function make2DPoint (x,y, depth, scaleFactor)
{
	var point = new Object();
	point.x = x;
	point.y = y;
	point.depth = depth;
	point.scaleFactor = scaleFactor;
	return point;
};

function get3DPoints ( object )
{
	var sx = Math.sin(object.rot.x);
	var cx = Math.cos(object.rot.x);
	var sy = Math.sin(object.rot.y);
	var cy = Math.cos(object.rot.y);
	var sz = Math.sin(object.rot.z);
	var cz = Math.cos(object.rot.z);
	var x,y,z, xy,xz, yx,yz, zx,zy;
	var i = object.pointsArray.length;
	while (i--){
		x = object.pointsArray[i].ox;
		y = object.pointsArray[i].oy;
		z = object.pointsArray[i].oz;

		xy = cx*y - sx*z;
		xz = sx*y + cx*z;
		yz = cy*xz - sy*x;
		yx = sy*xz + cy*x;
		zx = cz*yx - sz*xy;
		zy = sz*yx + cz*xy;
		
		object.pointsArray[i].x = zx + object.center.x;
		object.pointsArray[i].y = zy + object.center.y;
		object.pointsArray[i].z = yz + object.center.z;
	}
}

function Transform3DPointsTo2DPoints ( points, axisRotations )
{
	var TransformedPointsArray = [];
	var sx = Math.sin(axisRotations.x);
	var cx = Math.cos(axisRotations.x);
	var sy = Math.sin(axisRotations.y);
	var cy = Math.cos(axisRotations.y);
	var sz = Math.sin(axisRotations.z);
	var cz = Math.cos(axisRotations.z);
	var x,y,z, xy,xz, yx,yz, zx,zy, scaleFactor;

	var i = points.length;
	while (i--){
		
		x = points[i].x;
		y = points[i].y;
		z = points[i].z;
		
		xy = cx*y - sx*z;
		xz = sx*y + cx*z;
		yz = cy*xz - sy*x;
		yx = sy*xz + cy*x;
		zx = cz*yx - sz*xy;
		zy = sz*yx + cz*xy;
		
		scaleFactor = focalLength/(focalLength + yz);
		
		x = zx*scaleFactor;
		y = zy*scaleFactor;
		z = yz;
		
		TransformedPointsArray[i] = make2DPoint(x, y, -z, scaleFactor);
	}
	return TransformedPointsArray;
};

var ballArray:Array = new Array();

for ( var i:int = 0; i < allPointsArray.length; i++){
	var ball:MovieClip = new MovieClip();
	var colors = [ 0xffffff, 0x990000 ];
	var fillType:String = GradientType.RADIAL;
	var alphas:Array = [1, 1];
	var ratios:Array = [0x00, 0xff];
	var matr:Matrix = new Matrix();
	matr.createGradientBox(-20*0.4, -20*0.4, 0, 0, 0);
	var spreadMethod:String = SpreadMethod.PAD;
	var interpolationMethod:String = InterpolationMethod.RGB;
	var focal:Number = -0.1;
	with(ball.graphics)
	{
		lineStyle( 1, 0x330000 );
		beginGradientFill( fillType, colors, alphas, ratios, matr, spreadMethod, interpolationMethod, focal );
		drawCircle(0,0,3);
		endFill();
	}
	world.addChild(ball);
	ballArray.push(ball);
}

var cubeAxisRotations = make3DCenter(0,0,0, world);

this.addEventListener( Event.ENTER_FRAME, enterFrameHandler);
function enterFrameHandler( event:Event )
{
	cubeAxisRotations.z += 0.5*Math.PI/180;
	cubeAxisRotations.y = - Math.sin( -cubeAxisRotations.z );
	cubeAxisRotations.x = - Math.cos( -cubeAxisRotations.z );
	
	object1.center.newX = object1.center.x + object1.vx;
	object1.center.newY = object1.center.y + object1.vy;
	
	var rz = Math.atan2(object1.vy, object1.vx);
	object1.rot.z = rz;
	
	if ( object1.center.newX < 200 && object1.center.newX > -200 )
	{
		object1.center.x = object1.center.newX;
	}
	else
	{
		object1.vx*=-1;
	}
	if ( object1.center.newY < 200 && object1.center.newY > -200 )
	{
		object1.center.y = object1.center.newY;
	}
	else
	{
		object1.vy*=-1;
	}
	
	get3DPoints(plane);

	get3DPoints(object1);
	get3DPoints(object2);
	
	var screenPoints = Transform3DPointsTo2DPoints(allPointsArray, cubeAxisRotations);
	screenPoints.sortOn("depth");
	for (i=0; i < screenPoints.length; i++)
	{
		var currBall = ballArray[i];
		currBall.x = screenPoints[i].x;
		currBall.y = screenPoints[i].y;
		currBall.scaleX = currBall.scaleY = screenPoints[i].scaleFactor;
		world.addChild(currBall);
	}
	world.graphics.clear();
	world.graphics.lineStyle(0,0x000000);
	for each ( var tri in triangleArray )
	{
		screenPoints = Transform3DPointsTo2DPoints(tri.points, cubeAxisRotations);

		if (
			( screenPoints[2].x - screenPoints[0].x ) * ( screenPoints[1].y - screenPoints[2].y ) >
			( screenPoints[2].y - screenPoints[0].y ) * ( screenPoints[1].x - screenPoints[2].x ) 
			)
		{
			with(world.graphics)
			{
				beginFill(tri.col, 0.75);
				moveTo(screenPoints[0].x, screenPoints[0].y);
				lineTo(screenPoints[1].x, screenPoints[1].y);
				lineTo(screenPoints[2].x, screenPoints[2].y);
				lineTo(screenPoints[0].x, screenPoints[0].y);
				endFill();
			}
		}
	}
}

Now, with a little sterring behaviour and terrain this could be really nice. Looking at the (to be released) Molehill API and the triangle methods in CS4 it may be not worth the effort, but it still is interesting.

Yoho!

This entry was posted in 3D, as3, mochiads. Bookmark the permalink.
Be Sociable, Share!

Leave a Reply

Your email address will not be published.