This is just a simple 3D tutorial on how to make extremely basic
wireframe objects. It is intended for a 400 x 400 screen.
Final product . Arrow keys to move.
Z-Axis:
The most critical part of anything 3D is the z-axis. The z-axis is the
depth of something -- how far back it is. Something with a big
z-coordinate will be farther away from you than something with a small
z-coordinate. No trigonometry is needed for something like this, but
if you want to make a more complex 3D engine you will need to use
trigonometry to more accurately simulate a z-axis.
Vantage Point:
The 3D object will be drawn as if a person standing in the middle of the
screen, which means an ( x, y, z ) coordinate of ( 200, 200, 0 ). The
person's view will be pyramid shaped.
The shaded part represents the screen. The line going from the base of
the pyramid to the eye represents a point in 3D space ( a specific 3D
coordinate on the entire pyramid ) being transferred to a 2D coordinate
( a 2D coordinate on the screen ). A view from one side of the pyramid
to see how the line is being plotted would look like:
The little arrows on the lines means that they are parallel. Using
basic geometry ( AAA similarity theorem ), you can deduce that a / b =
c / d, and that means that ( a + b ) / b = ( c + d ) / d. By just being
given a point on the pyramid, we know the length of a. So the first
thing we need to find is a + b.
Z represents the z-coordinate of the point, which is given. Using any
given angle, and a bit of trigonometry:
h = ( a + b ) / 2
tan( angle ) = h / z
h = tan( angle ) * z
The value of the tangent of the angle is irrelevent -- it will always be
the same as long as the angle does not change. So you don't need
trigonometry to find out what the tangent is -- you can just replace it
with a constant ( I used 2, but anything reasonable works ). Now that we
know a and a + b, and that a / ( a + b ) = c / ( c + d ), then we know
the value of c / ( c + d ). We already know the value of c + d, because
c + d just represents the width of the screen -- 400 pixels in this case.
So:
c / 400 = a / ( a + b )
c = 400a / ( a + b )
And now we have the x-coordinate of the point in 2D space. We can do the
same for the y-coordinate. Translating this into two AS functions :
function getXAtDepth(x, depth)
{
widthAtDepth = 2 * depth;
ratio = (x + ((widthAtDepth - Stage.width) / 2)) / widthAtDepth;
return ratio * Stage.width;
}
And:
function getYAtDepth(y, depth)
{
heightAtDepth = 2 * depth;
ratio = (y + ((heightAtDepth - Stage.height) / 2)) / heightAtDepth;
return ratio * Stage.height;
}
The AS functions are a bit more complicated than before because the top
left corner of the screen at depth 200 is ( 0, 0 ), while the top left
corner of the screen at depth 400 is ( -100, -100 ), so that has to be
taken into account when getting the ratio. In this, y isn't exactly
equal to a because it the distance from 0 to y, not from the start of the
base of the pyramid to a, which could be -100. That's basically the
entire 3D code. The rest is just making it work.
Variables:
These are just the three variables that I used.
array = [];
lines = [];
cAS = 0;
Array < http://newgrounds.co../topic.php?id=296610
> holds
all the points, lines will be used later, cAS is the current length of
the point array.
Plotting the Points:
The way I did it is that I had an array of point objects
that I plotted. So I used a very basic function for clarity:
function addPoint(x, y, z)
{
array.push(new Object());
array[cAS].x = x;
array[cAS].y = y;
array[cAS].z = z;
cAS++;
}
Basically, it takes the point, converts it to an object, and adds it to
the end of the point array. This serves no practical purpose, but it
makes the code more clear. Instead of array[ 3 ][ 2 ], you have
array[ 3 ].y.
function plotPoints(points)
{
for (i = 0; i < points.length; i++)
{
newPoint = attachMovie("point", "point" + i, this.getNextHighestDepth());
newPoint._x = getXAtDepth(points[i].x, points[i].z);
newPoint._y = getYAtDepth(points[i].y, points[i].z);
}
}
This physically puts a movie clip representing a point on the screen. In
this case, I added a movie clip called "point" to the library that was a
small circle. What the code does is go through all the points in the
array and uses getXAtDepth() and getYAtDepth() to place them at the
correct coordinates.
Plotting the Lines:
This is used to plot the lines that connect two points. The first
function takes a set of points denoted by numbers. It then adds the
respective point to an array. Instead of saying "point0", "point1", you
just say "0", "1" to save time.
function addLine(points)
{
pointArray = [];
for (i = 0; i < points.length; i++)
{
pointArray.push('point' + points[i]);
}
lines.push(pointArray);
}
Points is an array of points, like [ 0, 1, 2, 3 ]. The next function
connects all these points.
function plotLines()
{
for (i = 0; i < lines.length; i++)
{
lineStyle(2, 0x000000, 150);
moveTo(_root[lines[i][0]]._x, _root[lines[i][0]]._y);
for (j = 1; j < lines[i].length; j++)
{
lineTo(_root[lines[i][j]]._x, _root[lines[i][j]]._y);
}
}
}
Using the AS API , it draws a
line between any two given points in the array.
Clearing the Points:
You also need a function to clear all the points.
function removePoints()
{
_root.clear();
for (i in _root)
{
if (i.slice(0, 5) == "point")
{
removeMovieClip(_root.i);
}
}
}
First, it clears all the non-movie clip lines in _root, and then it
checks all movie clips in _root. If they start with "point", it means
that they should be removed.