Jump to content
A 2021 backup has been restored. Forums are closed and work in progress. Join our Discord server for more updates! ×
SoaH City Message Board

Sprite Overlap [solved] - Update: DimX?


Steven M

Recommended Posts

You've seen games before where Hero McNiceguy walks around the level, tagged along by party members Sidekick McScrappy and Princess Bipolar. Where he walks, they walk. If he decides to do a U-turn, they'll gladly walk through him to progress. We're talking games like Mother 3/Crusader of Centy/Zelda where, even if you can't walk through NPC characters, you can still appear 'in front' of them (you overlap them) and also appear 'behind' them (they overlap you). And this is where I come in.

satest2.png

Our red sprite is the 'hero' in this case. If he's in front of the other two characters because he's lower down on the screen, he should be first in 'order'. If he's higher on the screen and the characters are following, he should be last in 'order' (so the other characters overlap him). Simple, right?

I can easily write a script in MMF2 to the point of "if (A)'s Y coordinate > (B)'s Y coordinate, move (A) in front of (B)". But I don't want to have to write that for every character overlapping every other character, especially when NPCs, enemies, items, etc are factored into account.

How do I write it so that if any object has a higher Y coordinate than any other object, they're placed higher up on the order chain?

Link to comment
Share on other sites

Do groups work properly in MMF2? If so, I imagine you could put every object into two groups, 'Overlapper' and 'OverLapped' (IE: Hero is in both Overlapper and Overlapped). Then, use general values like so...

If group.OverLapper.Y < group.OverLapped.Y

***then set object.OverLapper in front of object.OverLapped

That _should_ work.

Link to comment
Share on other sites

Do groups work properly in MMF2? If so, I imagine you could put every object into two groups, 'Overlapper' and 'OverLapped' (IE: Hero is in both Overlapper and Overlapped). Then, use general values like so...

If group.OverLapper.Y < group.OverLapped.Y

***then set object.OverLapper in front of object.OverLapped

That _should_ work.

IF Y position of (Group.Good) &gt; Y position of (Group.Neutral)
THEN Move (Group.Good) in front of (Group.Neutral)
IF Y position of (Group.Good) &lt; Y position of (Group.Neutral)
THEN Move (Group.Neutral) in front of (Group.Good)

Tagging everyone but Hero as Neutral and Hero as Good, he can overlap/underlap(?) properly in front of one object, but it doesn't seem to work with the others - I think the way its working is, he has to be behind ALL the Neutral-tagged objects (e.g the whole group) for the underlap to work, but if he's just walked in front of one Neutral object, the script puts him 'in front' of all the rest. Obviously I don't want that, I want it to work so he can under/overlap every other Neutral object individually.

Tagging Hero as Neutral and Good, it just doesn't work at all. Tagging everyone as Neutral and Good doesn't work, either. I'm going to keep pissing about the script and see if anything works, because I think I'm just not getting it properly.

Edit: and this is just Conrad (the hero) walking around on his own! I haven't even gotten far enough to getting his party following him properly yet!

Double-edit:

I think the way its working is, he has to be behind ALL the Neutral-tagged objects (e.g the whole group) for the underlap to work, but if he's just walked in front of one Neutral object, the script puts him 'in front' of all the rest.

It's definitely this. Confirmed with counters.

Link to comment
Share on other sites

Well, you can't really just stick everything into a group and run a single check to determine the order; you'd have to run a loop through each object within the group just to layer them correctly, but let's talk about an easier solution. ;>

The Layer Object in MMF2 will be your best friend in making this magic happen. Basically, you're saying you want the lower objects to be in front, and the higher objects to be behind. The objects on top are drawn last, so to describe your desire in other words, you want the objects to be drawn in descending Y order.

The Layer Object has a convenient action set called Sort, and within these set of actions, there's one called Decreasing Y Sort. This will cause objects with larger Y positions ( or lower down ) to be drawn last, or on top of other objects. Simply tag this action to an Always event and you're done!

lamevisualpic.png

My only issue with this extension is that you can't seem to isolate the layering to only a certain group of objects, regardless of the condition you use. Because of this, you may consider storing the Y position of objects you want to sort into an alterable value, and sort the objects using that value. This way, if you want certain objects always on top, you can force a huge number that should always be higher than the Y positions of other objects, and vica versa, you could keep things below by setting a very low number.

lamevisual2.png

  • Like 2
Link to comment
Share on other sites

Hahah, you responded even before I could get my needless yet still visually helpful image edited in.

Glad I could help; I used to go crazy over making your same issue work until I came across this extension ( just in time for when I was designing that 3D special stage engine in which I was able to sort by ascending Z position ).

Edit: Attached a second image to my above post showing an example of being able to gain more control of the sort through alterable values in case you ( or others ) have issues in the future.

Link to comment
Share on other sites

Glad I could help; I used to go crazy over making your same issue work until I came across this extension ( just in time for when I was designing that 3D special stage engine in which I was able to sort by descending Z position ).

I remember that special stage, it was aces. And descending Z position? If I remember right you didn't use Mode 7 for the engine, though it probably wouldn't have been that useful anyhow. I can't imagine how you'd get that to work (lots of advanced maths and juggling alt values, I guess).

No, but the layering works like a charm now - I can get all four characters (including the guard) working properly now, whereas before I'd be tearing my head out. Thanks again!

Link to comment
Share on other sites

I remember that special stage, it was aces. And descending Z position? If I remember right you didn't use Mode 7 for the engine, though it probably wouldn't have been that useful anyhow. I can't imagine how you'd get that to work (lots of advanced maths and juggling alt values, I guess).

A bit off topic but,

It really wasn't so bad. I gave each object 3 values, one for X, Y, and Z. Damizean helped me with a simple equation for translating the 3D coordinates into 2D coordinates so that they could be viewable on your flat screen using some division and multiplication. With these 2D coordinates, I then connected and created polygons from sets of four points that the overlay drew as a shape. Then it was just a matter of making a fastloop to go through every object that represented these set of 4 points ( or a rectangle ;> ) and having the overlay draw each one.

(I meant ascending Z position btw; the farther objects go away from the camera, the larger their Z, and so you'd want objects with a lower Z position to be drawn first hence ascending.)

Link to comment
Share on other sites

Alrighty then, new conundrum. I'm studying Retriever II's Caterpillar tutorial (which allows a group of the same object to follow a 'main' object), and part of the script asks for DimX("Array") as a value. For example:

IF start loop "init_array" DimX("Array") times
IF Alterable Value A of "Main Object" &gt; DimX("Array")

Array being the Array object with X, Y and Z dimensions. I get that Dim stands for dimension, and Dim(X,Y) returns the difference between the two integers if it has a positive result. I also understand that - in VBasic at least - "Dim array_name (upper_bound)" is a fixed-size array declaration. So what does DimX in MMF2 stand for, exactly - Dim(X,Y), DimX where 'X' is the name of an array, DimX where X is the X value given to Array, or what? It feels pretty embarrassing being confused at this point, but it's something I have to understand properly.

Link to comment
Share on other sites

DimX/DimY/DimZ("Array") retrieves the array's axis dimension (size). That means, if it's a 8x6x3 (3D) array, DimX would be 8, DimY would be 6 and DimZ would be 3.

start loop "init_array" DimX("Array") times essentially runs the loop for an amount of times equal to the array's X size.

Properties:

X Dimension. This numeric value defines the number of elements contained in the first dimension of the array. If you want to create a single dimension array, set the Y and Z dimensions to 1, and only change the X dimension.

Y Dimension. This numeric value contains the number of elements contained in the second dimension of the array. If you want to create a two dimension array, set the Z dimension to 1, and change the value of the X and Y dimensions.

Z Dimension. This numeric value contains the number of elements contained in the third dimension of the array.

*other properties*

Expressions:

X Dimension. Returns the size (number of elements) of the X dimension.

Y Dimension. Returns the size of the Y dimension.

Z Dimension. Returns the size of the Z dimension.

Link to comment
Share on other sites

DimX/DimY/DimZ("Array") retrieves the array's axis dimension (size). That means, if it's a 8x6x3 (3D) array, DimX would be 8, DimY would be 6 and DimZ would be 3.

start loop "init_array" DimX("Array") times essentially runs the loop for an amount of times equal to the array's X size.

Alright. The array's set dimensions are x=500, y=3 and z=1, ergo the array's 2-dimensional. My assumption was that this was a fixed-size array. Ha! But the script goes as follows:

START OF FRAME 
Special Conditions - Start loop "init_array" DimX("Array") times
ON LOOP "init_array"
Array - Write Value X("Main Object") to (LoopIndex("init_array"), 0)
Array - Write Value Y("Main Object") to (LoopIndex("init_array"), 1)
Array - Write Value Dir("Main Object") to (LoopIndex("init_array"), 2)

So if I understand this right (and I probably don't), the Array object writes three different variables to the loop as it goes on, each variable having a seperate 'depth' from the other (so 0/1/2 would be the Z/depth axis, so to speak... even though the manual states setting a dimension to 1 renders it null?). So does that mean the X value of the "Main Object", which is being written to the loop, determines the number of times the loop runs?

[NEGATE] "Main Object" IS STOPPED
Trail Segment - Set X position to ValueAtXY
( "Array", Alterable Value B( "Trail Segment" ), 0)
Trail Segment - Set Y position to ValueAtXY
( "Array", Alterable Value B( "Trail Segment" ), 1)
Trail Segment - Set Direction to ValueAtXY
( "Array", Alterable Value B( "Trail Segment" ), 2)

And if I'm assuming that 0/1/2 does refer to the Z axis, that leaves "Array" as the X and "Trail" as the Y in the "ValueAtXY" equation, yes? Or no? I'm horribly, horribly confused!

The actual tutorial, if you're interested, can be found here - though it's halfway to what I'd really like, which is the aforementioned Centy/Mother party system.

Link to comment
Share on other sites

I'll check out that tutorial. Its system looks quite weird to me. For my RPFG project I used a tutorial from Clickteam's forums, which makes one object follow another while avoiding obstacles. For the third character, I simply made a separate code section so he follows the guy who is following the leader.

Here's the link, but you need to log in to read stuff in that subforum and download the mfa: http://www.clickteam.com/epicenter/ubbthreads.php?ubb=showflat&Number=66421

Link to comment
Share on other sites

Never mind, I think I've got it sussed. Keyword, think. Mostly it's do with delaying the action of the trail segment as it takes the same path as the Main Object, thanks to the number-crunching script I've got half my head around. Thus:

ON LOOP "init_trails"
+ ALTERABLE VALUE A OF ("Trail Segment") = LOOPINDEX("init_trails")
----
TRAIL SEGMENT
Set Alterable Value B to [i]DimX( "Array" )-(Alterable Value C( "Main Object" )
+Alterable Value A( "Trail Segment" )*Alterable Value C( "Main Object" ))[/i]

Some further code copying/altering was required for the second trail segment, but the crucial difference seems to be this simple:

ON LOOP "init_trails"
+ ALTERABLE VALUE A OF ("Trail Segment") = LOOPINDEX("init_trails")
+ ALTERABLE VALUE A OF ("Trail Segment 2") = LOOPINDEX("init_trails")
----
TRAIL SEGMENT 2
Set Alterable Value B to [b]([/b][i]DimX( "Array" )-(Alterable Value C( "Main Object" )
+Alterable Value A( "Trail Segment 2" )*Alterable Value C( "Main Object" ))[/i][b]*2)[/b]

Given some time I'll be able to better comb through the script, and then probably simplify it.

Edit: thanks for the link, gsoft!

Link to comment
Share on other sites

I figured by the time I was done with this, you'd have the problem figured out on your own or from another tutorial anyway, but:

http://larkss.thisisourcorner.net/tuts/Follower.zip

Requires MMF2; hopefully not a problem!

I did my best to make the example as simple, straight-forward, and explained as possible. Maybe if you have any lingering confusion about certain aspects of the follower movement, this tutorial can clear things up. =]

Edit: Slight fix-up, namely as I forgot to explain why I was forced to separate one event into two; reuploaded. And reuploaded once again because of several wrong value examples in the comments.

Link to comment
Share on other sites

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...