Ultimate Gear War
Join the alien war, prepare your gear and protect your base at all cost!
4.15 / 5.00 16,792 Views3d tutorial part one: wire frame
You know those days when you get really bored?
This is one of those days for me… So I decided to throw together this little tutorial on 3d wire frames.
Something you should know: I did not steal this tutorial, nor did I steal the .fla for it. I did read part of one of -dELta-‘s tutorials, but I got bored and made this engine from scratch over the course of about 15ish hours?.
If you know about matrixes and such feel free to visit -dELta-‘s tutorials:
http://www.newground../topic.php?id=323444
And
http://www.newground../topic.php?id=323755
Otherwise read on.
AS main:
http://www.newground..d=229808&page=45
Theoryish stuff:
Okay. The first thing that you need to know about 3d is how things are positioned. On a plane in 3d space (polygon) you have coordinates where the edges meet (vertices-these things only exist in computers and our heads in case you didn‘t know). In 3d space each vertice has 3 coordinates, one for each axis x, y ,z (I am not going to explain this, this tutorial is not for complete n00bs)
http://web.mit.edu/w..rc/3d/cart-proj.gift
Now with perspective:
The farther away something is the smaller it is. Period. Because things get smaller as they get farther away things that are parallel to one another will slope together.
http://pcssd.org/nwo..0perspective%201.jpg
We are looking at a 3d world through a 2d plane (monitor), so we have to convert 3d coordinates into 2d coordinates.
I couldn’t find a good image so imagine squishing a cube against a plane
We will be looking through the x, z plane (I don‘t care if it is usually x, y -now y is depth not height), so we have to scale things like this:
http://img348.images..348/9678/tut11sc.jpg
http://img336.images..336/7294/tut24si.jpg
http://img336.images..336/7236/tut39yz.jpg
Picture the same sort of y-transform for the z, y axis
x, z is not necessary since that is the plane we are looking through.
I did my perspective a bit oddly, there are many ways, they are all very easy. Chose the one that looks best.
Now onto the coding!:
The complete Code:
_x = 200;
_y = 200;
post = new Array();
post = ["p", 0, 2, 3, 0, "p", 0, 2, 1, 0, "p", 1, 2, 4, 1, "p", 4, 2, 3, 4];
vectorx = new Array();
vectorx = [0, 0, 50, 100, 100];
vectory = new Array();
vectory = [1100, 1200, 1150, 1100, 1200];
vectorz = new Array();
vectorz = [0, 0, -50, 0, 0];
var infinity:Number = 10000;
var slope:Number = 0;
var rotXY:Number = 0;
var rotZY:Number = 0;
var xplus:Number = 0;
var yplus:Number = 0;
var zplus:Number = 0;
var neg:Number = 0;
var drawit:Boolean = true;
getScalerX = function () {
newPostXR = (150/vectory[i]);
xpostr.push(vectorx[i]*newPostXR);
};
getScalerZ = function () {
newPostZR = (150/vectory[i]);
zpostr.push(vectorz[i]*newPostZR);
};
getRotXY = function () {
delete (xpostr);
xpostr = new Array();
for (i=0; i<vectorx.length; i++) {
if (vectorx[i] == 0) {
vectorx[i] = 0.0001;
}
if (vectory[i] == 0) {
vectory[i] = 0.0001;
}
hyp = Math.sqrt((vectorx[i]*vectorx[i])+(vectory
[i]*vectory[i]));
angle = Math.atan(vectory[i]/vectorx[i])/(Math.PI/
180);
if (vectory[i]<0 && vectorx[i]<0 or vectory[i]>0 && vectorx[i]<0) {
angle += 180;
}
newY = hyp*(Math.sin((rotXY+angle)*(Math.PI/180))
);
newX = hyp*(Math.cos((rotXY+angle)*(Math.PI/180))
);
vectorx[i] = newX;
vectory[i] = newY;
getScalerX();
}
};
getRotZY = function () {
delete (zpostr);
zpostr = new Array();
for (i=0; i<vectorx.length; i++) {
if (vectorz[i] == 0) {
vectorz[i] = 0.0001;
}
if (vectory[i] == 0) {
vectory[i] = 0.0001;
}
hyp = Math.sqrt((vectorz[i]*vectorz[i])+(vectory
[i]*vectory[i]));
angle = Math.atan(vectory[i]/vectorz[i])/(Math.PI/
180);
if (vectory[i]<0 && vectorz[i]<0 or vectory[i]>0 && vectorz[i]<0) {
angle += 180;
}
newY = hyp*(Math.sin((angle+rotZY)*(Math.PI/180))
);
newZ = hyp*(Math.cos((angle+rotZY)*(Math.PI/180))
);
vectorz[i] = newZ;
vectory[i] = newY;
getScalerZ();
}
};
getMove = function () {
if (Key.isDown(Key.UP)) {
yplus = -3;
} else {
if (Key.isDown(Key.DOWN)) {
yplus = 3;
} else {
yplus = 0;
}
}
if (Key.isDown(Key.RIGHT)) {
xplus = -3;
} else {
if (Key.isDown(Key.LEFT)) {
xplus = 3;
} else {
xplus = 0;
}
}
if (Key.isDown(90)) {
zplus = 3;
} else {
if (Key.isDown(88)) {
zplus = -3;
} else {
zplus = 0;
}
}
if (Key.isDown(65)) {
rotXY = 1;
} else {
if (Key.isDown(83)) {
rotXY = -1;
} else {
rotXY = 0;
}
}
for (i=0; i<vectory.length; i++) {
vectorx[i] += xplus;
vectory[i] += yplus;
vectorz[i] += zplus;
}
};
getWire = function () {
startoff = 0;
for (ii=0; ii<post.length; ii++) {
if (post[ii] == "p") {
startoff++;
drawit = true;
delete (poly);
poly = new Array();
for (neg=(ii+1); neg<(ii+4); neg++) {
trace(vectory[post[neg]]);
if (vectory[post[neg]]<0) {
drawit = false;
}
}
_root["square"+startoff].removeMovieClip()
;
_root.createEmptyMovieClip("square"+starto
ff, startoff);
with (_root["square"+startoff]) {
lineStyle(2, 0x000000, 100);
moveTo(xpostr[post[ii+1]], zpostr[post[ii+1]]);
}
}
if (post[ii] !== "p") {
with (_root["square"+startoff]) {
if (drawit) {
lineTo(xpostr[post[ii]], zpostr[post[ii]]);
}
}
}
}
};
onEnterFrame = function () {
getMove();
getRotXY();
getRotZY();
getWire();
};
don't get overwhelmed, everything is explaned below in the next post. If you copy that code and paste it in flash you will get a pyramid that can be controled with the arrow keys, A,S,Z,X.
If it does not work something is wrong with your flash compiler/you have and earlier version than flash 8.
_x = 200;
_y = 200;
The above sets the centre of the stage as 0,0
post = new Array();
post = ["p", 0, 2, 3, 0, "p", 0, 2, 1, 0, "p", 1, 2, 4, 1, "p", 4, 2, 3, 4];
vectorx = new Array();
vectorx = [0, 0, 50, 100, 100];
vectory = new Array();
vectory = [1100, 1200, 1150, 1100, 1200];
vectorz = new Array();
vectorz = [0, 0, -50, 0, 0];
Ok. The vector arrays store coordinates (five coordinates in a pyramid, five numbers in each array)
“post” stores the POSTition of the coordinates (the order needed to draw the pyramid). ”p” means start drawing a new polygon.
var slope:Number = 0;
var rotXY:Number = 0;
var rotZY:Number = 0;
var xplus:Number = 0;
var yplus:Number = 0;
var zplus:Number = 0;
Variables related to functions, I’ll go over this soon.
var neg:Number = 0;
var drawit:Boolean = true;
Variables related to drawing.
getScalerX = function () {
newPostXR = (150/vectory[i]);
xpostr.push(vectorx[i]*newPostXR);
};
getScalerZ = function () {
newPostZR = (150/vectory[i]);
zpostr.push(vectorz[i]*newPostZR);
};
Ignore this for now, we’ll come to it in a minute.
getRotXY = function () {
The function for rotation around the z axis
delete (xpostr);
xpostr = new Array();
xpostr is the position array, it is modified in the part I told you to ignore, we WILL get to it.
for (i=0; i<vectorx.length; i++) {
We want to modify every coordinate in the vectorx array
if (vectorx[i] == 0) {
vectorx[i] = 0.0001;
}
If vector x=0, program=dead. You CANNOT devide by zero.
if (vectory[i] == 0) {
vectory[i] = 0.0001;
}
Same as above.
hyp = Math.sqrt((vectorx[i]*vectorx[i])+(vectory
[i]*vectory[i]));
angle = Math.atan(vectory[i]/vectorx[i])/(Math.PI/
180);
if (vectory[i]<0 && vectorx[i]<0 or vectory[i]>0 && vectorx[i]<0) {
angle += 180;
}
This gets the angle between 0,0 and the coordinate on a 2d plane. If you don’t understand this, learn trig then return.
newY = hyp*(Math.sin((rotXY+angle)*(Math.PI/180))
);
newX = hyp*(Math.cos((rotXY+angle)*(Math.PI/180))
);
Finds the new coordinates through trig. Takes the global angle and the coordinates angle and adds them together to get the new coordinate. If you are going to say something like “this is unnecessary, matrixes work faster” yes they do, but the hypotenuse and angles are needed for shading and culling-which will be explored in the next tutorial.
vectorx[i] = newX;
vectory[i] = newY;
Changes the values of vectorx and vectory. Btw I know that a name like “coordx” makes more sence, but I don’t care.
getScalerX();
Muw ha ha the part I put off. Go up and look at the code then come back. Ok? Good. That code basically makes it so if the polygon is far away, it is small, if you don’t understand the specifics, try harder. It also adds the modified coordinates to the drawing array, which is in perspective.
}
};
getRotZY = function () {
Basically the same as above, I am not going over it.
delete (zpostr);
zpostr = new Array();
for (i=0; i<vectorx.length; i++) {
if (vectorz[i] == 0) {
vectorz[i] = 0.0001;
}
if (vectory[i] == 0) {
vectory[i] = 0.0001;
}
hyp = Math.sqrt((vectorz[i]*vectorz[i])+(vectory
[i]*vectory[i]));
angle = Math.atan(vectory[i]/vectorz[i])/(Math.PI/
180);
if (vectory[i]<0 && vectorz[i]<0 or vectory[i]>0 && vectorz[i]<0) {
angle += 180;
}
newY = hyp*(Math.sin((angle+rotZY)*(Math.PI/180))
);
newZ = hyp*(Math.cos((angle+rotZY)*(Math.PI/180))
);
vectorz[i] = newZ;
vectory[i] = newY;
getScalerZ();
}
};
getMove = function () {
This function controls the global movement. Its not that hard to figure out so just look over it.
if (Key.isDown(Key.UP)) {
yplus = -3;
} else {
if (Key.isDown(Key.DOWN)) {
yplus = 3;
} else {
yplus = 0;
}
}
if (Key.isDown(Key.RIGHT)) {
xplus = -3;
} else {
if (Key.isDown(Key.LEFT)) {
xplus = 3;
} else {
xplus = 0;
}
}
if (Key.isDown(90)) {
zplus = 3;
} else {
if (Key.isDown(88)) {
zplus = -3;
} else {
zplus = 0;
}
}
if (Key.isDown(65)) {
rotXY = 1;
} else {
if (Key.isDown(83)) {
rotXY = -1;
} else {
rotXY = 0;
}
}
for (i=0; i<vectory.length; i++) {
vectorx[i] += xplus;
vectory[i] += yplus;
vectorz[i] += zplus;
}
};
getWire = function () {
This is the drawing function. In the next tutorial I will expand it to include back-face culling and shading.
startoff = 0;
How many polygons there are at the beginning of the draw function, none.
for (ii=0; ii<post.length; ii++) {
“post” holds the shape of the polygon, so we have to draw every entry in it.
if (post[ii] == "p") {
If we need to draw a new polygon.
startoff++;
# of polygons goes up
drawit = true;
We assume that the polygon can be drawn
delete (poly);
poly = new Array();
for (neg=(ii+1); neg<(ii+4); neg++) {
trace(vectory[post[neg]]);
if (vectory[post[neg]]<0) {
drawit = false;
}
}
Tests to see if all the polygons coordinates are positive.
_root["square"+startoff].removeMovieClip()
;
_root.createEmptyMovieClip("square"+starto
ff, startoff);
with (_root["square"+startoff]) {
lineStyle(2, 0x000000, 100);
moveTo(xpostr[post[ii+1]], zpostr[post[ii+1]]);
}
}
Starts the new shape.
if (post[ii] !== "p") {
We don’t want to draw “p”’s.
with (_root["square"+startoff]) {
if (drawit) {
lineTo(xpostr[post[ii]], zpostr[post[ii]]);
Ok this is pretty cool. Xpostr contains the coordinates, but we are examining “post”. “post”’s entries correspond with xpost’s coordinates, so xpostr[post[ii]] gives you the next drawing coordinate.
}
}
}
}
};
onEnterFrame = function () {
getMove();
getRotXY();
getRotZY();
getWire();
};
Order in which things are done
Thanks for reading my tutorial, I hope it helps you. NG needs some 3d games. If you use this tutorial to create a game, please include me in the credits.
lol
i forgot to post an example:
http://img138.images..eframepyramid3pz.swf
up/down =yaxis
left/right=x axis
z/x=zaxis
q/w=xaxis rotation
a/s=yxais rotatrion
Jeeeez. Too long to read right now but looks like you did a great job. I'm surprised nobody posted yet! Awesome job =D
Very nice. I abit more about the axis than Delta's one. It'll propably go into AS:Main soon. Post about it there.
Did you know you can actually have link html on these forums?
Newgrounds
<a href="http://www.newgrounds.com/">Newgroun
ds</a>
for some reason it does not work with my browser.
At 7/8/06 01:13 PM, Disarray_yarrasiD wrote: for some reason it does not work with my browser.
it looks alittle off... like the perspective is off... but other than that looks awsome :D
btw what fps is that running at?