Let's Play
Done Properly
KWRPG Stealth, or rather, Kirby Warrior's Revolving Projectile Gear Mk. III: Deception Extreme (KWRPGIII:DE) was an alright game. A little hard, maybe, but it'll only punish the hasty. I made it over the span of two weeks in response to LDM's own "KWRPGIII" parody directed at me (and others), in the hopes I could make a parody game directed at him (and others). Sadly, it never did evolve beyond a tech demo. That's probably for the better, given how much of a vanity project it was.
That said, I still enjoyed a tiny bit of glee when Avlein finally got around to playing it all those years later; and even though he's a dirty cheat, I still got a faint sense of sadistic elation awash over my entire being when he stepped on that one landmine when oh-so-close to the goal. It was much worth the wait.
That said though, I've been doing a lot of practice coding since I last made it, and you know what? While watching it, I kept getting this other feeling... I could've done it better. So much better.
RPG Maker 2003 ain't the most versatile game system out there. I'm really tired of it by this point. However, it does conform to a lot of people's expectations of what a "game" exactly is. It is unlike Game Maker where it could emulate a generalized object-oriented blank canvas upon which anything can happen, but it does allow people to make a lot of specific one-time things to custom craft an experience as they imagine it - without the needed building time. RPG Maker is unique this way, even if it is at the cost of genre flexibility.
By now, it is, sadly, also horribly outdated. A year after its release, around 02004, microprocessor manufactures were having trouble keeping pace with Moore's Law due to the excess heat high frequency clock cores were generating, thus shifting away from single mega-core systems to weak-cored multiprocessor systems. This led the way to multithreaded programming practices and the like. RPG Maker 2003 exists entirely before that operating environment, and is thus a single-threaded program engine with a very definite cap on work throughput. I compared it to having the operational power of an old NES, and after the graphics are taken care of, that's more or less the case on many ~1.8ghz systems.
But, just because it's a bit of a stick in the mud, doesn't mean it is exempt from best practices found in other areas of gaming. While it's directly against the EULA, certain patches did exist for a while which could expand RPG Maker's capabilities, including Cherry's Powermode Patch, Dynpatcher, and even the editor extension known as RPG Maker 2009. These added the ability to use custom title screens, read full keyboard input, and some other things not immediately apparent to a regular hobbyist. It gets around engine's assumption of itself as just a simple novelty and allows for much more. KWRPG Stealth thrives on these extensions, but at the time, I never quite managed to understand the full extent of it.
While the game's code made a lot of sense, it was never really optimized fully. One of the reasons Av got lost in the first video is that I assumed I could have around 10 active patrols on a map, and thus designed with that in mind. Due to lag, I had to later reduce it to 5. The reason was the hitbox code which each of the guard used as a cone of vision, excerpted here:
To imagine what it does, it essentially projected a big ol' square box right in front of wherever they were facing. If Solid MW was in that box, an alert was raised. Very logical, almost simplistic design. But even at its cleanest, the code is a complete mess. It was difficult to prototype, had to be hand-tweaked even after copypasting, and ran a lot of calculations per patrol. Keep in mind, this code had to run at least once per each frame of video. By the time I got to my 8th patrol, the framerate began to slow. It was simply too much code, and even required a lot of upkeep on my own end.
Only five patrol a map? This simply will not do! I wish to make my dear Avlein even more of a nervous wreck! What could I have done to optimize the process?
Turns out, hitboxes suck - at least on systems not designed for 'em in the first place. They're a common staple of a lot of things in game programming, especially in 2D with sprite-based graphics, but they're clunky sometimes. At minimum, they need at least four values (two X and two Y) and trying to brute force intersections on 'em usually results in a huge nest of IF statements. The basic algorithm goes like this:
- Figure out the height and width of each box. (X2 - X1 = Width, Y2 - Y1 = Height)
- If the the first X of the second box is inbetween the first X of the first box AND the first box's X + Width,
- AND if the the first Y of the second box is inbetween the first Y of the first box AND the first box's Y + Height,
- ... then detect a collision.
- Else if the the second X of the second box is inbetween the first X of the second box AND the second box's X + Width,
- AND if the the second Y of the second box is inbetween the first Y of the second box AND the second box's Y + Height,
- ... then detect a collision.
- Else, no collision.
In a system where you have to input all IF statements via an editor window, this is awful. Completely so. It's also aesthetically unpleasing. Seriously, look at that. It's just repeating the same sentences over and over again, but only swapping a few words around. Also try to imagine how many calculations and comparisons that's generating on the assembly level. RPG Maker was almost deliberately designed against this sort of thing.
If hitboxes were out, what do we have left?
Surprisingly, hit spheres are a great alternative. They seem unintuitive, but they actually require less in terms of both memory and processing. As opposed to the hitbox four, a hit sphere requires only a minimum of three variables: the X and Y of its centre, and an R (radius) for how far it reaches around that point.
While the process for finding out if two circles are colliding with each other isn't as immediately obvious as it would be, it is surprisingly elegant:
- Draw a line from the centre of one circle, to the centre of the other circle.
- Measure how long it is.
- Get another value and add the how long the radius of one circle to the radius of the other.
- If the measured line is longer than the two radii combined, the circles are not overlapping.
- If the measured line is shorter than the two radii combined, the circles are colliding.
Here is an example of these hitspheres in action. When Solid MW's hitsphere is colliding with one of the guard's, the guard will change sprite.
And here is the code. It is not excerpted.
Even better, it's completely portable. Only requires two control values: Iterator Starting Position and Iterator Number of Objects.
Let's go over it in a little more detail, ar?
Step One: Get the player's screen relative positions. Set the player's radius size.
The player needs a hitsphere to use in addition to the patrolling guards. So it's important to set the values for it too.
RPG Maker has two location variable systems. The first is the obvious one associated with the map data. It is a series of 16 by 16 pixel tiles which form the level design, and each one are numbered with an X going to the right and a Y going downwards, increasing by 1 each time. This is what gives RPG Maker that "grid-like" system of movement.
The second variable system is a little bit more hidden, and by far much more powerful. It is the screen relative coordinate system, and it can be accessed by using this:
What it will do is return a value that will tell you where on the game screen an object is, in pixels. If the values are between (0,0) and (320, 240), that means whatever is there is getting drawn to the screen. Moreover, it will also return negative values for things outside of the range of view to the left or the above, and things larger than (320, 240) for things to the right and below.
(Note: Remember kids, computer math is different from the math you learned in school. The X, Y graph on computers is mirrored along the Y axis. This screws a lot of things up. Even after knowing this, those math classes were still a waste of time. Keep this in mind for later, since it will come up again.)
With screen relative positioning, the Pictures rendering in RPG Maker becomes a lot more powerful, as you could then anchor very large picture graphics to map events where you would otherwise be limited to a 24 by 32 sprite.
A very simple use of this for your own RPG would be a compass or something. If you have an overworld map, and there is a town in the distance that is your player's current destination, you could fetch the screen relative X and Y of that town's event object, and draw an arrow graphic slightly above it. It also allows you to escape the 16 by 16 grid and get pixel-controlled graphical animation. It also can allow you implement auto-scrolling levels, where you continually pan the screen in one direction. Read for the Hero's screen relative positions and if they are too far outside the (0,0) thru (320, 240), then they've fallen off the map. It's very useful like that!
There is only one caveat to 'em. The screen relative X gives you a value ready to use, however the screen relative Y is a little off by design. It will return the point that is right at the event sprite's feet. This would be great in a 3D world, but less so with 2D. To fix it, you'll need to move the value up a little to match it with the sprite's centre of gravity. If the sprite is 24 pixels tall, subtract 12. If 32, subtract 16. This will make drawing pictures over it much easier.
Step Two: Set up the Iterator Values
RPG Maker can be compared to an old NES or SNES in more than one respect. One aspect is its memory storage.
On modern operating systems, resource allocation like RAM storage is usually handled by the OS and not the game. The game would simply request it, and the OS handles the request. Many operating systems allocate memory based on efficiency. Since RAM is just one very long line of ones and zeros with a starting point and an end, the operating system simply gets the request for N number of bits, and finds the best fit unused hole in memory to store it. The game doesn't necessarily know where the data is stored, it simply gets it through an indirect pointer table. The game might be using three different integers all in tandem, but those integers might be stored megabytes apart from each other depending on how congested the RAM is. (You never notice this in action because access time to RAM is all the same. It's only when RAM runs out and the computer needs to overflow to virtual memory on a mechanical HDD when you might feel the effects.)
Old consoles like the NES and SNES didn't have this level of indirection. The games had to sort out their own memory. And the way RPG Maker sets up its variables and switches is largely based on the same design practice. Everything is stored in this large, seemingly atomic array. You can see this in action if you press F9 during test plays through the editor.
It's less efficient, but I kind of like this approach when it comes to game-important values. The vast majority of all RAM is stored for the purpose of graphical data. In small, 2D games like ours, the amount of important data out there is probably no more than 32 maybe 16 KB. (It really is a shame RPG Maker didn't allow for multiplayer, since syncing two game worlds at this small amount of value would've been pretty simple in this setup.)
So, since we know where all of our own data is, what can we do with that knowledge?
Introducing: the pointer.
Pointers are an old concept in programming that are a bit dangerous as far as "safe" programming practices go. When used properly, they can accomplish amazing feats. When used improperly, they could corrupt your game's entire data structure. They are a major concept in the C and C++ programming languages, but only exist at the meta level in other languages like Java, Javascript, and PHP. The translations of both RPG Makers 2000 and 2003 never quite got 'em right, but make no mistake - these are pointer values.
Simply put, they are an indirect variable access. If \v[40] had the number 16 in it, and \v[16] had the number 861 in it, if I wrote out the text code \v[\v[40]] it would print out 861. If I said \n[\v[40]], it would print the name of the 16th playable character in the database.
I find RPG Maker's pointers are actually much easier to use than C/C++'s pointers, but that's mostly due to their odd * and & syntax. Either way, their function is the same. You know the name entry screen shown off in the KWRPGIII debug mode? That was implemented using eight variables for each letter, and one variable as pointer. The pointer started at the variable position for the first letter, and every time Power Mode detected a keydown, it would write the value to the position the pointer pointed at, and then increased the pointer by one to move onto the next letter.
Because of this, the memory layout in RPG Maker is very important. This example only uses 3 hit sphere objects, but I imagine I could probably support up to 20 or 30, but only as long as this memory pattern repeats for that long, uninterrupted:
This is the data structure for a hit sphere in full. The X and the Y for its position; the R for how large it is; and a "detect" semaphore for if it is not colliding at the moment (zero) or if it is indeed colliding (non zero). You can use this semaphore to detect if an object is colliding with multiple different type of hit spheres, like 1 if it collides with the player's hit sphere, or 2 if it is colliding with a banana peel on the ground, and so on. For this example, we'll only be using 1 and 0.
Repeat the memory allocation in a long, atomic, uninterrupted line to form your data structure. The only downside is, you'll need to make sure your working variables are off in a safe location, as they are here:
Use variables like mad; just plan out how you're going to organize 'em! As long as they are properly laid down, you can use a concept introduced into C++ 02011 called Iterators. (Well... They might not be the exact same thing, since this isn't Object Oriented, but you'll see how iteration works.)
Once all that is assumed, to complete this step simply set the number of active hitspheres you want to account for (in our case, just 3) and the variable index at the start of the data structure (in our case, 60, since the first data variable is at 61).
Step Three: Set up a loop.
You're only gonna want to write out the code once, but still have it apply to all the different hitspheres.
Aside from our loop, we also set the iterator position to the starting point. This'll become important in step five.
Step Four: Check to see if still inside the loop. Break if otherwise.
As long as there are still hit spheres we want to scan, we must remain inside the loop.
If the number of hitspheres left is zero, break. Else, decrease the amount left by one.
Step Five: Have the iterator copy the values from the other sphere object.
This is where the iterator shines. Using pointer addition to navigate through the data structure, the iterator copies the values in each hit sphere, so that it may do work on the values elsewhere.
The only difference is that the detection semaphore is not copied. Rather, its location is remembered as a pointer pointing back at the hitsphere object. This will become important in step nine.
Step Six: Draw a line between the centres of both circles and measure its length.
Remember how I said that all those math classes you took in school were useless then and are still useless now? Well, here it comes. We've got to use some math now, but don't expect your math teacher to feel vindicated just yet. In fact, they're a real nuisance when it comes to this.
You could sort of interpret the line we create as the hypotenuse of a right triangle. We can measure it using the pythagorean theorem. Think of it that way if it is easier to understand, but before doing that, I prefer to just use vector algebra here since that helps get the numbers more malleable.
(vector 2) - (vector 1) = (a new vector)
(x2, y2) - (x1, y1) = (x', y')
(160, 120) - (100, 100) = (60, 20)
This gives you a new line, specifically a line which would connect the centre of one circle with the centre of another. Don't worry if the answer is negative, since that'll cancel out later on. Now is when you're going to want to use the pythagorean theorem to measure it.
If you recall from math class, the pythagorean theorem is as thus:
This sucks and I hate it. You should hate it too.
Not just because I despise math, mind you. I have a very good reason. It's because of the square root involved. See that √ ? It is the devil. It is Waddle Duu incarnate. Never mind the fact that Power Mode gives support for it, if that √ got into your code, your game would lag your computer to the frozen fires of computational Hell.
The algorithmic complexity of the square root function is really awful. Like, somewhere between O(n2) and O(2n). The larger the number is, the more time it takes the CPU to output an answer. Keep in mind, RPG Maker 2003 ain't multithreaded, so if the CPU has to time out because of a square root call, the entire game will freeze until the CPU can finish. That ain't something you want running every frame of video.
If you implemented the pythagorean theorem just as your math teacher told you to, your game would be nigh-unplayable. I'm talking a framerate in the decimals here. It's that bad. (I rue the day I once asked a math tutor to help me implement a custom arctangent function. Not only did it not bloody work, it also nearly melted my old CPU.)
Instead, we gotta get around it. You know I said we gotta find the length of that line? Well... sort of. Not quite the "I love you, sort of" or "You're going to live, sort of," but just... sort of, okay? We gotta find something that can be sort of interpreted as the length of the line. We gotta use this:
It's only sort of the pythagorean theorem now. It's a little incomplete. However, this form goes by another name in vector algebra: the squared magnitude. It's useless to us now, but we'll get around it in step seven.
So, get the (x', y') from the last formula, and get this value from it in RPG Maker:
line_length = x*x + y*y
Step Seven: Add the values of both radii together and square the result.
You saw from that diagram that the two circles will overlap if the line connecting the centres is shorter than the radius of each circle combined. Getting the value for comparison is easy here.
radius_value = radius1 + radius2
However, we also have that squared magnitude thing from the previous step. As a result, we need to take it one step further:
radius_value = radius_value * radius_value
This should even things out.
Step Eight: Subtract the line length from the radii.
We're getting close to the moment of truth here...
result = line_length - radius_value
If the result is positive, that means the line length is larger than the radius value and the circles are not colliding. If it is negative else, however, that means we have a collision on our hands.
Step Nine: Use the iterator's detect pointer to write a value back into the hit sphere's detection semaphore.
This is the reason why we didn't have the iterator copy the hit sphere data structure all the way. With this small change, we have a pointer pointing back to the hit sphere data structure, and we can tell it if it is colliding or not.
End the loop here, and we're done.
***
And that's that. A much speedier hit detection algorithm and much more elegant too. If I were to implement it, I could probably get about 30 hit spheres in RPG Maker without lag. On a 3.7ghz system, I tested well up to 60 hitspheres and only got a very faint hint of framerate drop.
I would give each guard three hit spheres: a small one for right in front of 'em, a middle one for further away, and a large one for as far as they could see. This would give them a more cone-like field of vision. I could also put another hit sphere directly on top of them, but have that one only respond to a special 'an odd sound was made' hit sphere. I also could probably make the player hitboxes much more variable too, instead of locking the player out of using the boxing gloves or the star rod if they laid a banana down. I probably could also get still active guards to poll for seeing any of their downed comrades and rasing a caution that way, but without A* pathfinding it would be troublesome to get them to return back to their patrol routes. Oh well.
For what it's worth, a similar algorithm exists for hit boxes, but it is still a bit more of an expensive operation. Upon each orienting axis, you first take the four values corresponding to the lengths of each side of the box and figure out what value is the largest and then the smallest. If the distance between those two values is less than the sum of the two box heights/widths added together, they are overlapping. Sadly, you need to execute this process twice in order to be absolutely sure: once upon the widths and once upon the heights. Even then, it still requires more memory to enact, since you require not only the four (x,y) points which make up each box, but also the dimensions of each box. You could speed up the computation a little by precomputing the dimensions, but that would make each box eat up six variables, which is twice the memory required for a sphere. It really does surprise me how a sphere, which normally is a much trickier concept to compute, ends up being more efficient in both computation time and in memory requirements. It's just something you'd never intuitively expect.
So all in all, I could probably squeeze an extra two guards out of this, all while making the game system considerably more advanced as well as giving it less code to ultimately keep track of. Not a bad tradeoff, if I do say.
... but I'm not satisfied. Not by a long shot. Avlein must be made to suffer. Suffer much more. I do so enjoy his screams of frustration and terror. They are the sweetest music to ever grace my spiteful, spiteful ears. What else could be done? What could I have to elicit more delicious tears?
Hrm. Yes, I'll take a few of those.
Oho. Aimed bullets? Don't mind if I do!
Yes, these will do perfectly. I'll be drinking Avlein's tears in the gallons with these. So how do we implement 'em?
Let's talk about Power Mode. It was one of the most widely used patches in RPG Maker 2003, expanding the engine functionality by a lot. Most people only used it for the custom title screens and the ability to play the more compact OGG sound files over the MP3 or WAV defaults. But it offered a lot more than that
Power Mode claims the first eight variables of the system. They are used as such:
- CR0
- Control Register Zero, contains custom title screen functions.
- MCOORDX
- MCOORDY
- The X and Y coordinates of the mouse cursor.
- KEY
- Used to read keyboard input.
- FVALUE1
- FVALUE2
- FCODE
- Now these are the important bits. These three variables contained mathematical functions that RPG Maker 2003 didn't naturally offer.
- You write two values into FVALUE1 and FVALUE2, and by writing one of these numbers into FCODE, it will do these operations:
- Sine and Cosine of an angle in FVALUE1.
- Result: 0005:FVALUE1 = sine, 0006:FVALUE2 = cosine.
- Tangent of an angle in FVALUE1.
- Result: 0005:FVALUE1 = tangent.
- Square root of FVALUE1.
- Result: 0005:FVALUE1 = natural part of a sqrt, 0006:FVALUE2 = fractional part.
- Divide FVALUE1 by FVALUE2.
- Result: 0005:FVALUE1 = natural part of a quotient, 0006:FVALUE2 = fractional part.
- Sine and Cosine of an angle in FVALUE1.
- We'll be using them to accomplish our evil plans.
- SPECIAL
- Was supposed be used for picture rotation, but doesn't really work all that well in my experience. Retrospectively, I think I know how it works, but I've never tested it properly.
One of RPG Maker's biggest limitations is that it never quite allowed for floating-point values, like 0.8328923 or 11.4392. You guys now using RPG Maker VXAce not only now have that, but also you get access to a Ruby-styled scripting language. You guys don't need Power Mode, but we stuck-in-the-past 2003 folk do. Power Mode gets around those limitations by allowing the natural part of a floating-point value (the 12 of a 12.34) to be stored in one variable, and the fractional part of a floating-point value (the 34 of 12.34) in another. However, the catch is it mutliplies all fractional numbers in this manner by 1000000, so that makes things a little tricky.
So, off the bat, we got access to Sine, Cosine, Tangent, Square Root, and Natural Division. We'll be using each of these except the tangent, which we have to reverse-engineer.
You're probably wondering why I'm considering using the square root function after I went on such a long oratory about how it murdered everyone in the countryside and is solely responsible for global warming. Well, sometimes you can't quite get around it, and when you can't, it's important to only use it as little as possible. It's like flirting with alcoholism: drink every day will kill ya, but only once in a while ain't so bad. (See kids? Math is bad for you.)
An example of using the square root function properly can be found here:
It's a very simple platforming script. The hero object is invisible and can only move left and right. A hitsphere normally designed for the hero is then placed at the position of the hero's screen relative X, and the hero's screen relative Y subtracted by another variable called Y Offset. The offset is how far away the hero's platforming spiritual otherkin stands from the invisible hero object. A new picture graphic is drawn over that position. Move left and right to move the hero normally, and have two states switched by a jump button: on the ground and airbrone.
When airborne, the Y offset should then become modified by this function until it collides (equals) with the screen-relative of one of your solid platforms that the player's X is nearby:
The RPG maker function for it is:
jump_value = jump_time * jump_time
jump_value = jump_value / jump_length
jump_value = jump_value * -1
jump_value = jump_value + jump_height
Which is roughly the same as:
y = (-x2)/k + h
In order for it to work through, we need to find a good value to set jump_time at the point when the player hits the jump button. After that jump_time would increase by one each second, but if we don't place the starting value correctly, all the hero would do is just fall.
Do to that, we need to find the negative root of the function, and that uses the square root.
jump_time = jump_height * jump_length
IF (jump_time < 0) then jump_time = jump_time * -1
FVALUE1 = jump_time
FCODE = 3
jump_time = FVALUE1
IF (jump_time > 0) then jump_time = jump_time * -1
It is in a case like these when calling the square root function is fine; when the player is on the ground the the jump button is pressed. Just once, at a very specific event. If the square root function got called more than eight times in a frame is when the game will start to lag.
A smart person here might ask the question: Why not get around the square root by using the derivative? My answer here is that the derivative would likely be a fractional function, like -x/(k/2), which we couldn't support fully without floating point values. It might also make collision detection with the terrain a bit more difficult given our very simple view of physics. A proper game would definitely use the "location += speed" model for updating position, but since this is RPG Maker, this ain't a proper game.
That covers using the square root. Let's move onto the Sine and Cosine. They're basically the only two trigonometry functions that are mildly useful in any way. I've yet to find a good use for tangent, cotangent, secant, or co-secant. It's gotten to the point where I will be genuinely surprised when I do find a use for 'em.
For Power Mode and our purposes, we'll be using them with degrees. Most proper programmers use radians instead, since dividing a circle up into 360 parts is pretty arbitrary and it'll really show if we need to draw one utterly massive circle. Sadly, to use radians would require floating point values and π, and we don't have access to either one. Besides: degrees are a bit easier to communicate with. You know what a 45° slope is, not a π/4 slope. For you guys on RMVXAce, Ruby's math library defaults to radians, so remember to convert your inputs.
I don't really need to describe the mathematical theory behind this one. Frankly, it's a little too involved. Here are the graphs of each sinusoid just for reference. They go from 0° to 360° and repeat in a cycle.
π/2 = 90°, π = 180°, 3π/2 = 270°, 2π = 360°
This is what we're going to use it for:
And this is how it will work:
Well, that saved me a lot of explaining. Anyway, let's make some circles. Here is what variables we will need.
- Origin X: The screen-relative X of the event it is linked to.
- Origin Y: The screen-relative Y of the event it is linked to.
- Angle: The 360 degree angle of the circle at any moment.
- Radius: How far the circle stretches out, in pixels.
- Speed: For auto-rotation. Also specifies the direction in negative or positive.
- Draw X: The screen-relative X of where the point of the circle will go.
- Draw Y: The screen-relative Y of where the point of the circle will go.
- Sine: For the sine.
- Cosine: For the cosine.
- Divider: To figure out the radius length.
You guys on RM VXAce have access to floating-point values, so you don't need the divider variable. Instead, just multiply the sine/cosine by your radius to get the line length you want. We in Power Mode, however, do need the divider. Sine and Cosine normally return values between 1 and -1, and in order to work Power Mode multiplies whatever that is by 1000000. We need the divider to reset the values.
Here's the process you'll want to follow:
angle = angle + speed
if (angle >= 360) then angle = angle - 360
if (angle < 0) then angle = angle + 360
FVALUE1 = angle
FCODE = 1
sine = FVALUE1
cosine = FVALUE2
divider = 1000000 / radius
draw_x = sine / divider
draw_y = cosine / divider
draw_x = draw_x + origin_x
draw_y = draw_y + origin_y
Run this on a parallel process, and this is what you'll get:
Here, WK is the anchor event. The number at the bottom is the angle at the current moment. Awesome, ar? This is great for all sorts of special effects.
However, you need to be careful. Sine and Cosine are a bit slow. Not quite as slow as sqaure root, but enough to be worrisome. At best, I'd recommend having no more than 8 of 'em active at the same time. Unlike the sqaure root, though, it's kinda hard not to use these.
The odd part is, you don't actually need Power Mode for these either. Power Mode helps a little on the code, sure, but old NES and SNES games managed to get a similar effect to these, using a much lesser processor to boot. In fact, it might even be slightly more efficient to just precompile a trig table of the values you need ahead of time, which was the technique old Nintendo games used.
To precompile a trig table, we simply find out all the values we need ahead of time, and make a function where we have one input angle variable and two output variables. If the input angle variable is 32, then the output would be Sine = 5299192 = (0.52991926423 * 1000000) and Cosine = 8480480 = (0.84804809615 * 1000000).
It would be a pretty massive table of IF statements, so you'd best make sure to divide it up into nested quadrants by 90 degrees. Precomputing 360 values is time consuming, but all you need is just a calculator with a sin, cos, and tan button. It'll be pretty worth it since the processing time would be slightly lower, and you'll also be able to get this effect in RPG Maker 2000 even if you wanted.
For our last example, we're actually going to need to make a table. Not for sine or cosine, and not quite for tangent either. We need one for inverse tangent, or rather, arctan.
We want to have great balls of fire aimed directly at the hero's position. The algorithm for it is exactly the same as our auto-rotating elliptical, but with one catch: instead of using the speed variable on the angle, add it to the radius! And instead of resetting it at 360, instead reset it when it has reached how far a shot can travel in pixels. This way, our drawn point won't go in a circle, but just move on an ever-expanding line.
Of course, do to this, we still need to find the proper angle that will aim the shot at the hero. Trigonometry is easy when the angle is known, but when the angle is unknown, we need to use trig's inverse function to find it.
Those of you using RM VXAce's Ruby script, you got direct access to Math.atan(y, x); so count your blessings. We on the other hand, have to precompile 90 values. Power Mode comes with tangent, but not arctangent, which is what we need.
When you have a spare hour, take a calculator with a trig tan button, and precompute values 0 through 90. Record the first seven fractional decimal places of each number and begin to construct this kind of table:
This is where we will use the natural division component of Power Mode. If you write 4 to FCODE, it will divide FVALUE1 by FVALUE2, storing the natural part in FVALUE1, and the expanded fractional part in FVALUE2. To get the tangent of a line normally, you divide how tall a line is (opposite) by how long a line is (adjacent). (This is the toa of the sohcahtoa.) What we're going to do is draw a line from the origin point of our laser to its intended target: the hapless, defenceless Avlein. I can taste the tears already!
Using FCODE4 to divide the line's height by its width, we will be able to find what angle the line is at. So we have two (x, y) values now. You can use the same vector algebra method from our hit spheres to figure out how long the line is, but we also need to figure out general direction it is facing, or what quadrant of the axis it is headed. Is it between 0° and 90°? Between 90° and 180°? Between °_° and °^°? We need to do this in order to figure out: A) what part of the line is the opposite and what part is adjacent, and B) how many times we need to add 90° to the result in order to get the right answer. Even though we don't know the angle yet, we can figure this out depending on if the X or the Y of our line is positive or negative, and in what order.
As a final note, you only need to compute the arctangent when the shot is first fired -- when the radius size is reset to zero. The arc value is saved from there out. This way, instead of being limited to only 7 or 8 auto-rotating ellipticals, you can have anywhere from 9 to 15 aimed shots on the screen at once, well before any lag starts to occur.
That's about it to my advanced RPG Maker usage. Hindsight is always 20/20, ain't it? You'd think I would be lamenting the fact that the game never got finished, but I somehow ended up lamenting the code I used for it even more. It is strange what a little knowledge would end up doing. Maybe I'm weird like that.
The best part is, most of this stuff applies for a good practice outside of RPG Maker, and can even be done much more efficiently in fully affine spaces like Game Maker and OpenGL. Even the weirdly-subdivided grid spaces in RPG Maker can be a little awkward sometimes.
Will I make another RPG Maker game? I dunno. RPG Maker has a great level editor for working with people who aren't very code-heavy, but so often I end up just breaking the entire system over my knee. Maybe if a good team got together and had a reasonable project outline.
- MW
The added scenes shown here were from a development copy of Diddgery's ADVENTURE GAME 3: THE QUEST OF THE JOURNEY, a sequel that might or might not ever be finished of the other two in the ADVENTURE GAME TRIOLOGY, downloadable here.