Slopes

From AlephWiki

Jump to: navigation, search

Potential Sloping Floor/Ceiling Implementations

Return to History

Nat

There has been much talk of sloping floors and ceilings recently, so my two cents may not neccesarily be very welcome or useful, but I think some of the things I have to say may have some use to those involved.

As with many things in Marathon, true 3D is a bit of an impossibility as there is so much jury-rigged 2D->2.5D Stuff that the whole, or large parts, of the engine would have to be overhauled to add many true 3D aspects including true 3D slopes. The result is a need for another 2D->2.5D solutions which can be tacked onto the engine fairly seamlessly. I admittedly have never had the time, the guts, or the programming experience to download and pick apart the engine for myself, but as a long time player, long time devellist listener, and a small time coder I think I have a good enough feel to make a plausable sloping hack.

As always the Marathon notion of polygons must be kept in Marathon, as the engine is hard-coded to work with them. Thus even for sloped polygons, one must still build the classic polygon "room" (has a floor, ceiling, and walls on all of its sides that do not connect to neighboring polygons or that are flagged as solid.) Then a fairly flexible sloping system can be applied to the floor and ceiling if intended, but the walls must remain vertical. This limitation can be compensated for with a zero height wall where a polygon's sloped ceiling meets its sloped floor, because zero height walls are supported by the engine.

2.5D Sloping Implementation: It is neccesary to have three points determine a plane. I briefly toyed with the notion of a two point based sloped polygon system for Marathon, but it was actually more complex then the more versatile three point implementation. Thus for any polygon's floor and or ceiling, either the classic flat floor height must be specified, or the height of the vertices must be specified, thus large flat areas can still be built with the same speed that made editing Marathon a breeze, but sloping can be done.

In the actual map file, all polygons will be stored only in the current method with a flat floor and ceiling hight, and those that are sloped, must have their slope data stored elsewhere to maintain conformity, perhaps in an MML file. To reduce the sloped polygons into the current manner of singular floor and ceiling height compliant with the map file, one uses the worst case scenario assumption, the polygons floor height in the map file = highest vertex in the polygon's floor specification with diagonals, and the polygons ceiling height = lowest vertex in the polygon's ceiling specification with diagonals. Or for example: (as veiwed as a vertical cross section of a level, ie up is up on the page)


EX1:               EX2:
actual level:      actual level:

------             ------
      \                  \
       \                  \
        ------             | 
                           |
                           ------

------
      \
       \                   ------
        |                 /
        |                /
        ------     ------

What the map file is told is there:

EX1:               EX2:
-------            -------
       |                  |
       |                  |
        --------           ---
                              |
                              |
                               ------
--------
        |
        |          --------
        |                  |
        |                  |
         --------           -------


The beauty of keeping this data in the map file, is that the map is backwards-compatible so older versions can run it, but of course in lacking diagonals, the map will be changed, and may not even be playable, but it will still be readable and will not crash the program, and that is what is truly important. For the current implementation we will need the worst case data stored in the map file to run the monster AI's component in dealing with diagonals. But if someone can figure out a better AI diagonal understanding then mine (which should not be hard, as I did not really work on much of one, just making one that worked at all.) then one can store the average heights for the floor and ceiling in the map file which will give a truer aproximation of the diagonals for those poor individuals running an older diagonal free version of Aleph One.

(For the following calculations, X and Y refer to the plane in the Marathon universe, while Z or H refer to the height of something) In the separate file to keeping track of slopes, one will need three numbers for each sloped polygon portion (floor and or ceiling) of a polygon: Sx, Sy, and offset (which I will refer to as B). To get these values, the editor, or person if one does not have an editor, must solve for the three vertices specified (X1,Y1), (X2,Y2), and (X3, Y3) with the three coresponding heights one wishes them to have H1, H2 , and H3 the vector in the matrix equation:


|X1 Y1 1| |Sx|   |H1|
|X2 Y2 1|*|Sy| = |H2|
|X3 Y3 1| |B |   |H3|


Then to get the values of the vertices one simply takes the vertices that are specified in the map file and calculates their Z (height component) by doing this: z = (Sx * x) + (Sy * y) + B, which is such a minimal calculation, that it can be done on the fly if one wishes. One could also do this calculation for all vertices of diagonal polygons when the level loads, then during the level could just feed the stored (x, y, z) components into OpenGL which would make adding diagonal polygons take no speed hit at all (with respect to graphics at least, physics will take a small hit) because the diagonal math can be done before hand.

Projectile and player physics require a minor rework, but it is not as bad as everyone seems to think. From my understanding, when Marathon goes to do the collision physics, it figures out if anything collided during the time it spent rendering the previous frame. This can still be done quite simply. For a projectile over a diagonal floor, one simply assumes it moves from its old position x0 y0 to its new position x1 y1 unhindered. Then one computes Hl = (Sx * x1) + (Sy * y1). If Hl is greater then the height of the projectile there is a huge probability that the projectile hit the floor. For speed one can always assume the projectile hit the floor, (and be right probably more than 95% of the time and only wrong around the edges of very steep and spiky polygons), or for accuracy, one can then compute the point of intersection by setting the projectiles equation equal to the polygon's slope equation, and if the intersection occurs outside of the polygons x, y bounds (because the sloped polygon must be a floor, and so we only have to check if the projectile is over the planer boundary, because z is irrelevant to my pseudo slope bounds) then the projectile squeaked around the edge, in such a case one still must do a little more computation to make sure it did not collide with the polygon it passed into after barely clearing the edge on this one. As for the ceiling, same math and rules apply, except the potential collision occurs when the computed Hl is less then the projectiles height. As for placement of the explosion effect, by the fast method one can run it at the old possition right before impact, x0 y0,H0 and for the accurate method, one has solved the point of intersection and can place it directly at the precise point of impact. To figure out passibility of the player is similar, but simple. One must get the floor height into which the player is attempting to pass by the same linear equation used for the vertices and projectiles, or the constant from the map file if it is flat, and then do the same with the ceiling. The player can pass to the new position if and only if player height < (ceiling height at the new x and y position) - (floor height at the new x and y possition.) Another player refinement that must be taken care of is the 2D run space problem. Even if a polygon is a mile long (just for the sake of assumption), the player will traverse it as if it were only two world units long if the polygons slope is steep enough. This is because the game's movement engine still sees these polygons as flat surfaces, and if it is only two feet along the x, even if it is miles long, the game feels you only need to traverse the x and y space, and you will magically gain the z distance. You also see this problem with staircases in Marathon. When running, the game does not slow you down going up stairs, because it magically gives you the z distance you have covered going up stairs by simply traversing the stairs x y space. Although people seem unbothered by this light violation of physics on stair cases, having it on diagonals will probably create a huge uproar, even though it is simply a smoothed out stair case. Although for ramps 45 degrees or less most people will probably not notice, one can compensate, simply by using my much used floor height equation to get out the z distance, and factor this in when computing the distance covered. It is just a bit of algebra, but if someone wants me to work out the equation, I can bang it out and submit it to the devel list.

To add even more realism, one can easily factor in the effect of gravity on the players actions within diagonal polygons with a little cost. Gravities effect on the player is (world gravity) * sin(inverse tangent(absolute value(Sx + Sy))) and it is in the direction created by normalizing the vector [Sx, Sy] (I think, I am just guessing about the vector part, but if that is not correct, I can not possibly imagine what is.). Adding this in will make it like quake where one slips off of sloped polygons, slows when running up hill, and accelerates when running down hill. To one up Quake, one can add in either a global coefficient of kinetic friction, or add them in polygon by polygon using MML or the like. This way, although movement is always influenced by diagonals on polygons, one will not slide along very weakly slanted polygons, or for that matter very strongly sloped ones if one jacks up the friction coefficient. Better still is if one calculates the friction realistically, using the normal force, in this case just the mass times the gravity times the sloping (the thing multiplied by the gravity in my gravity on a diagonal polygon equation), then on steeper inclines, heavy tank-like things will stick to the surface enough to climb them while lighter things will just slip off.

Monsters work the same as players, but their AI's are going to need some work so that they do not plan to traverse through an area which slowly pinches off leaving them stuck running in place against a sloped ceiling and or floor and an easy target. My quick fix solution, is to use the worst case data for the moster AI already stored in the map file. This means the moster AI does not need to be touched at all, and the monsters will never get stuck as they will avoid all even potentially limiting polygons. This is only a temperary fix though, because monsters will simply avoid narrow, steeply sloped hallways, even if they can actually pass through every single point in the hall's polygon unhindered, because they are assuming the worst case. It is a bad fix I know, but it is a free one, and you pay for what you get. A better AI should not be too hard to whip up.

There are many other little cool things one can do with this implementation as well. If the vertices are calculated on the fly as opposed to when the level loads, then one can use MML to change the slope equation at run time. What could one use this effect for? Switches that activate ramps, ripples and the like in liquids, doors that slowly slide and pinch shut, bizarre dynamic alien terrain, etc. . .. Also, if one solves a generalized version of the matrix equation I put up, and then adds some solvable nonlinear terms to the equation, one does not just get diagonally sloped polygons, but true curves! Of course this will never truly work, because although variants of all the previous math will hold with curves, I have no idea what type of divine intervention it would take OpenGL to render curved floors and ceilings with the curvature stored in such a 2D height mapped equation, but if you can think of it, it is there. If anyone wants me to clarify anything in here, like write out more explicitly some of the equations or explain anything farther just post the list. And for those of you doing the actual programming who are bothered by this smug little brat who shows up and ask more work of you, do not wory as I will not be asking for anything else or bothering anyone with this idea again. I hope this post is found useful though.

Personal tools