I came across a simple problem earlier: "I want to display a healthbar over an enemy." The solution was equally simple: "I'll use spread values to link the two objects together."
End of article.
Really, though. It turned out that the solution wasn't as simple as I thought. I wanted to use a counter to represent the health of the enemy. Counters can not have alterable values assigned to them. With no means of linking the active to the object, I gave up hope. In a moment of brilliance shortly afterward, I knew what I had to do and how I had to do it.
Fixed Values
Most objects support alterable values. This works when you are linking two active objects, as the active object supports alterable values. As previously mentioned, counters (and strings) do not support alterable values. However, like all objects, they both support fixed values.
>> What is a fixed value? <<
Every object has a fixed value. In any frame, put down a myriad of objects. Actives, backdrops, counters, anything really. Select all of them. Each object will have that blue selection box with a number in the top left. That number is the fixed value, sort of. As you put different kinds of objects down, you'll notice that the fixed value of objects already placed will change. Objects like Backdrop and Quick Backdrop will take the first fixed values. As you can see in this screenshot, the Backdrop and Quick Backdrop objects are 1 and 2, respectively. They were placed down 6th and 10th, respectively.
There seems to be some sort of hierarchy to the fixed values of objects that decides which object gets a higher value than the other, but I won't go into how the ordering is done. Just look at the screenshot above for an approximation of this ordering; Backdrops come first, followed by counters and strings, then regular objects, then extensions, then the list object. The only anomaly you might notice is that the Lua object is mixed in with the actives and not the extensions. (I put the Lua and Ini objects down before another instance of the actives.)
So thats what the fixed values are. Sort of. Let construct a simple frame to do a simple test: Do the fixed values shown in the frame editor correspond to the fixed values at runtime? Logically, yes.
>> Setting up the test: <<
You'll need:
• Active 1, two instances.
• Active 2, two instances.
• Counter
• String
Put the actives down in any order, and be sure to record the order you put them down in, as well as their fixed value. Give both actives the qualifier "Group.0".
Use this code:
+ Mouse is over Group.0
= Counter: Set value to Fixed("Group.0")
= String: Set alterable string to Hex(Fixed("Group.0"))
Run the frame, and mouse over the actives.
Result:
The lowest alterable value for any of the actives should be 196610. The hexadecimal string for that object should also be 0x30002. If these values aren't the same for you, don't worry. The test still has a valid result. As you can see, the fixed value at runtime is different than the one shown in the frame editor. If you've ever tried the following code (or some derivation of it), then you should know why it didn't work:
+ Fixed value of Active = 1
= Do stuff
>> Deconstructing the information <<
Now that we know how to get (and display!) the fixed values for any object, we can do some neat stuff with that data. First thing we can do is figure out how many objects we can have before we run out of fixed values. We have 16 possible values for 5 digits, so a simple equation will work: 16^5 = 1,048,576. Wow, that's a lot. As MM2 limits you to 20,000 objects, it is virutally impossible to max out the number of fixed values. Of course, that's not the only reason why. Let's take a look at the hexadecimal for the first object again. This is the object with the fixed value of 1 in the frame editor.
0x10000
We can break this number down into the following pattern:
0x | t | i
t is the total number of objects made, as a hexadecimal. t always starts at 1. When you have more than 15 objects in the frame, you'll see that the number of digits for the fixed value increases. In a simple loop that created, displayed the fixed value, then destroyed objects, I've seen t reach 5 digits, bringing the total number of digits (t+i) to 9. For all intents and purposes, t is the fixed value of the object in question. It will always match up to the fixed value as seen in the frame editor.
i is the current number of objects, also as a hexadecimal. i always starts at 0. It is a zero-padded value, to 4 digits; If you have one object, it will be 0000. Two objects, 0001. You should never see the number of digits exceed 4, as FFFF would be 65536 objects. Again, MMF2 doesn't go over 20000, so its virtually impossible to exceed 4 digits of i. As far as I can tell, i references when the object was created, in terms of other objects on screen. Like t, you're never going to see two objects with the same i. Unlike t, a greater value of i does not mean it is the most recent object created.
>> Using information from the fixed value <<
We just covered what the fixed value is, but now we have to turn that into a usable form that MMF2 can recognize. There are two primary ways to do this: Using the hexadecimal string; Using the integer. If we want to use the hexadecimal, then we need to store the data in a string: Alterable string, string object, array, whatever. Likewise, if we want to use the integer, then we need to store that as a number: Counter, alterable value, array, whatever.
We'll be storing as an integer, first. It is much simpler and can easily be turned into a hexadecimal if we need it as such later. For this, we're going to need:
• An active object, "Active"
• A counter object, "Counter"
• Another active object, "anchor"
The code:
-- Destroy Active and Counter objects, make anchor invisible
+ Start of Frame
= Active: Destroy
= Counter: Destroy
= Mouse: Make invisible
-- Set anchor to the mouse
+ Always
= anchor: Set X position to XMouse
= anchor: Set Y position to YMouse
-- Create a new active/counter pair when we click on the frame
+ User clicks with left button
= Create: Create "Active" at (0,0) from anchor
= Create: Create "Counter" at (0,0) from anchor
= Active: Set Alterable Value A to Fixed("anchor")
-- Links the counter we just made to the anchor we just made, courtesy of MMF's object scope.
-- The counter would be considered the "child" of the active by doing this, but MMF's object scope
-- (the same one that made linking possible) will make the counter a psuedo-"parent" to the active,
-- as we'll see later.
-- Link an active to the anchor when we want to move it around by holding down shift
+ Mouse pointer is over "Active"
+ Upon pressing Shift
= anchor: Set Alterable Value A to Fixed("Active")
-- When an active is anchored, we put it under the cursor.
+ Fixed value of "Active" == Alterable Value A("anchor")
= Active: Set X position to XMouse-16
= Active: Set Y position to YMouse+16
-- When we release shift, we unlink the active from the anchor.
+ (X) Repeat while Shift is pressed
= anchor: Set Alterable Value A to 0
-- This is how we will destroy active/counter pairs. By right-clicking them.
+ User clicks with right button on "Active"
= Active: Add 1 to Alterable Value B
-- Here's the child code mentioned earlier. We're positioning the counter to be above the active,
-- as well as making the counter display the information we want.
+ Fixed("Counter") == Alterable Value A("Active")
= Counter: Set X position to X("Active")+16
= Counter: Set Y position to Y("Active")-8
= Counter: Set counter to Alterable Value B("Active")
-- This is the psuedo-parenting code also mentioned. We have to test for the fixed value of the
-- counter first. Because the counter is displaying the active's alt value, we test the counter for
-- the alt value instead of the active, asserting that we are looking at a specific active/counter
-- pair, instead of any pair. Ordering is important for the second condition, otherwise only the
-- most recently created pair will be tested, and all counters will be destroyed, instead of the
-- pair.
+ Fixed("Counter") == Alterable Value A("Active")
+ Counter: Counter value > 2
+ Alterable Value A("Active") == Fixed("Counter")
= Active: Destroy
= Counter: Destroy
-- Oh, this is also the code that destroys the active/counter pair.
Basically, we make pairs in the frame by left clicking, and we move them around by holding shift down. We right click on an active three times to destroy it. You can left click the same spot and create a stack of pairs, and then use shift to pull one pair away at a time.
Now, if you want to use the hexadecimal string instead of the integer, just use the same code as above. However, instead of storing the string in an alterable value, you want to store it in one of the alterable strings. I'm not going to copy/paste the same bit of code with minor alteration when I can do something more useful, like tell you how to split the string into usable parts. This is slightly more complicated as once you convert to hexadecimal there is no (easy) way to convert back to integer.
To get data from the hexadecimal string, use these expression when you're setting a string value. The expression for t is listed first, i is second:
If you've forgotten what t and i are, or how they're set, then scroll up to the section named >> Deconstructing the information <<.
>> So why use fixed values over spread values? <<
When you want to create active/counter pairs. Or active/string pairs. Basically, any time you want to use a spread value to link two objects together, but only have one object that can store an alterable value. Other than that, just use spread values.
Thanks for reading my first article. Share any ideas you have about when you can use fixed values, be it the integer, hexadecimal, t, or i, in the comments. If you have any questions or information to add about fixed values, leave a comment. If you just want to say nice article, then don't leave a comment.