Picking Different Objects and Adjusting Pick Order

2 favourites
From the Asset Store
Hand-painted tiles, objects, animated objects, and background to build a colorful Mayan civilization environment.
  • Hello, I am having an incredible frustrating problem where I cannot check collisions between two objects of the same family correctly.

    My goal is to have a functional 2.5d z-axis within Construct 2, and while I have the basics for collision checking down, updating the z-axis via gravity is proving rather difficult.

    What I am attempting to do is check if a member of the family of sprites with the special variables concerning z-axis, z-height, etc, is standing on top of another member of the same family. If they overlap at an offset that FACTORS IN THE FAMILY-SPECIFIC Z-AXIS VARIABLE then the object ON TOP of the other object knows not to fall through the object under it.

    My main issue is that when using a For Each loop, the instance picked from the family cannot interact with other instances in the family via collision checks because the overlap check will only work on the instance that is ALREADY PICKED - the one selected via the For Each loop.

    I have seen workarounds to checks between two of the same object that require using a second family, but that is undesirable for me as the overlap check refers to a family-specific variable.

    What the hell do I do? Something like this would work if the overlapping object (second/index 1 instance) was pickable IN ADDITION to a set object picked in the For Each loop, but as far as I know that's not the case.

    Sorry for the seemingly overcomplicated issue, if any clarification is needed on what my problem is or what I plan on using the code for please let me know, I am desperate for help.

  • Ah, I know that issue well. Events don’t excel at dealing with two instances of the same type independently.

    Personally I like just having a single type, putting that into a family, and adding the instance variables to a family. That way you can use picking to get two separate instances and still access the variables for both.

    I’ve attempted to two family method but I ran into the same issue. Can’t access the instance variables in one of them.

    A third tool we have is sprite(2).x. That expression will give you the x of the sprite with iid=2 no matter what is picked, and it will work for any property.

    So for your example you probably could do a hybrid of iid and the second family idea. The instance variables would be added to family1, and the second family2 would have the same objects and would be used to utilize the overlapping conditions. Anyways to access the variables from a family2 instance you’d do family1(family2.iid).z.

    In theory something like this would then work. I’m going with the premise that family1.iid and family2.iid have the same value for the same object.

    Every tick
    — family1: add 300*dt to vz
    — family1: add self.vz*dt to z
    family1: z>0
    — family1: set z to 0
    — family1: set vz to 0
    
    For each family1
    Family1 is overlapping family2
    For each family2
    Compare family1.z<family1(family2.iid).z
    Compare: family1.z > family1(family2.iid).z-family1(family2.iid).zheight
    Compare: family1.z< family1(family2.iid).z+family1.zheight
    — family1: set z to family1(family2.iid).z-family1(family2.iid).zheight
    — family1: set vz to family1(family2.iid).vz
  • Try Construct 3

    Develop games in your browser. Powerful, performant & highly capable.

    Try Now Construct 3 users don't see these ads
  • My apologies, using family1(family2.iid).z won't work. We can only utilize iid to access different instances of the same type, not family. Guess there's always something new to learn.

    Here is a test of three different ways to access and set values of two different instances.

    1. family vs family containing the same types.

    2. type vs family with just that type. (by far the simplest imo)

    3. type vs same type.

    dropbox.com/s/82wzrtp796gjbnj/twoInstances_sameTypeOrFamily.capx

    In general you can just pick one at a time and store the instance variables to some other variables, so then when you pick the other object you can have values to compare to.

    Another option is to use a function to get/set values from different objects.

    on function "get"
    -- number var uid=-1
    -- text var name=""
    -- set uid to function.param(0)
    -- set name to function.param(1)
    -- family: pick by UID: uid
    -- -- name="x"
    -- -- -- function: set return to family.x
    -- -- name="area"
    -- -- -- function: set return to family.area
  • Ah, it seems I misunderstood what the value in the parenthesis did. I thought it referred to the nth instance of the picked instances, not the iid of all instances of that object.

    This is huge, thank you so much for your time and help, glad you are always around to push Construct 2 to its extremes.

  • In case anyone else wants to implement a 2.5d game with a z-axis, the system proposed with two families absolutely works.

    Apologies if the perspective or the visuals look a bit wonky, this is just a test room.

    The Z-Axis IS possible :)

  • R0J0hound Are you familiar with ways to order objects along the z-order that takes into account multiple variables and overlapping?

    (for the sake of clarity z-level refers to my custom 3d system's z-plane, z-order refers to the order in which sprites are rendered in construct)

    I've tried to do a For-Each ordered loop which takes into account the y-level of objects to place them correctly in the z-order. This works for objects with a z-level of 0, but once I start stacking objects on top of each other in the 3d z-plane or increase the z from 0 (eg. bottom object has a z of 0 but height of 10, and top has a z of 10 and height of 5, the one with the height of 5 rests on the one with height of 10) this obviously breaks the display because it considers the y level of the object, and as the top object has a lower y value, it gets displayed BEHIND the object it is on top of.

    (this would render the top box behind the bottom box)

    So the solution would be to incorporate the z-level into the calculation, correct? Well no, because if I set it to order based off y+z, if the object is slightly behind the equivalent of the bottom object's origin point when factoring in the z-axis, it will STILL BE DISPLAYED BEHIND despite being on TOP of the object.

    So rather than place objects in the z-order based off a simple calculation of values, would I have to check objects overlapping at an offset determined by the different in z-level, then check of one of the them has a higher z than the other's z+height?

    YES! I WOULD! And it works when using the custom sorting function with rexrainbow's zsort plugin.

    But only sometimes! If a large number of sprites overlap, the ordering breaks.

    Here is the code, I'm aware it's not efficient but I was trying to avoid using if-else since in rexrainbow's example he doesn't use it for some reason.

    I'm at my wits end trying to fix this stupid bug. It has nothing to do with the actual collisions or functionality of 3d which has been perfect for me so far.

    I know this is a weird question to ask and I apologize if I should have opened a separate post. Please, if anyone is capable of helping in the slightest or needs more clarifying information, let me know.

  • Under the system actions:

    Sort Z order

    Sort the Z order of instances of a given object according to an instance variable. This effectively removes all instances from their Z order, sorts them, then inserts the sorted sequence back in to the holes left behind. This means if the instances are spread across a range of layers, they will be sorted in the same Z order locations, maintaining the same order relative to other instances on those layers. Note this action is much faster than using an ordered For each with an action like Send to front/back, so this action should be the preferred way to sort the Z order of large numbers of instances.

    So, when the object changes y, or every tick, instance set variable myz to instance.y

    Sorting would be sort z order by myz

  • Hope my formula gives you an idea:

  • I like how simple alextro's formula is. Unfortunately that will only work with isometric blocks with the same size.

    For different sized blocks you need to figure out which objects are in front of the other. Consider the simplest case of two blocks. This site does a nice job at explaining a way to do that:

    bannalia.blogspot.com/2008/02/filmation-math.html

    Once you have a way to decide which of any two blocks should be in front of the other you can use that to progressively sort the scene. You only need to sort objects visually overlapping each other. For making everything sort more instantly, you can use a topo sort if needed.

    In my latest tests I've found the step of figuring out which of two blocks should be in front of the other is closely related to pushing one object out of the other for Collison detection. Basically find the normal of the collision/overlap of each pair. Even if the objects aren't overlapping in 3d it's possible to find this normal. If you're not familiar with normals, they are just the 3d direction from one contact face to the other object.

    Anyways with that you dot product the normal vector with the direction of the screen. If <0 then one object is in front, otherwise the the other is in front.

    Here's a test of that.

    dropbox.com/s/9veb43lyxd7bja0/iso_sort3simplified.capx

    Anyways, for the perspective you're using it will be simpler than sorting for a isometric view, but the idea is similar. I was attempting to adapt my example to your perspective but not much luck yet. Hopefully it gives some ideas, or you stumble on a simpler solution.

  • Here is the sorting with the perspective you're using.

    dropbox.com/s/m1p2f090xmqa230/alt_iso_sort.capx

  • newt I understand how to sort the z-order, I also understand how to change an object's z-order based on their Y. I'm not doing this in my case because the z-order is affected by a z-axis as well as a y-axis.

    alextro My objects all have different widths and heights and my game isn't isometric, although your formula is quite clean, I really wish it'd work for me :(

    R0J0hound I've tried your sorting algorithm designed for my perspective, and while it works in the capx you sent, it seems to function incorrectly when I try to implement it myself. Since it works for you, there is evidently something I am doing wrong.

    "SOLID_SPRITES_Family" would be equivalent to "Sprite" in your example, and "SOLID_SPRITECOMPARATOR_Family" would be equivalent to "other" in your example.

    The main issue that arose was that some objects just wouldn't sort correctly, and would be placed under ones they should be over. The other issue was that sorting wouldn't occur unless the collision boxes actually overlapped.

    In my game the collision boxes do not cover the full sprite due to how the collision works with incorporating the z-axis. I thought this was potentially the problem, so when testing I made the collision boxes cover the entire sprite like in your example, which didn't fix it.

    I thought potentially it was because the origin point was not at the very bottom of a sprite like in your example. I moved it to the bottom, which did not fix it.

    You may notice that my sorting method is not a 1:1 copy of yours, this is because the z-axis is more positive the higher up an object is in my game. In your example, the z-axis is more negative the higher up an object is. To fix this, I just made the references to the z-level in the algorithm flip (instead of -sprite.z it'd be +sprite.z, I doubt these changes are the cause but I thought they were worth mentioning).

    In the portion where you set dy, using yy, I just do the yy calculation there. I don't think that would affect anything besides performance. I also add z to y instead since z is positive in my case.

    I didn't have an sy value prior to implementing your system, so I added it and set it accordingly for the sprites I was testing with.

    Just so it is easy to understand the difference in variable names, yy is just y+z (in your case it was set to y-z, but I can't do that), z is z (but positive), sy is length, and sz is trueHeight.

    The alternate family has the same sprites as the main, and all its variables are properly synced with the main. SCz is equivalent to z, SCtrueHeight is equivalent to trueHeight, etc.

    Any idea what I've done wrong? Once again, if I've explained poorly and you need clarification please let me know. I really appreciate how helpful you've been.

  • The image isn't loading in my previous post, here is what the code looks like.

  • I changed mine so z up is positive and compared what I did with yours:

    yours: dy = (A.y+A.z)-(B.y+B.z)-(A.sy-B.sy)/2
    mine: dy = (A.y+A.z)-(B.y+B.z)-(A.sy-B.sy)/2
    
    yours: dz = -A.z+B.z-(A.sz-B.sz)/2
    mine: dz = A.z-B.z-(A.sz-B.sz)/2
    
    yours: best = ((abs(dy)-(A.sy+B.sy)/2)>((abs(dz)-(A.sz+B.sz)/2))?dy:dz
    mine: best = ((abs(dy)-(A.sy+B.sy)/2)>(abs(dz)-(A.sz+ B.sz)/2))?dy:dz

    It's just your dz equation that is off. The rest looks correct from what I can tell.

    You can do your own bounding box check if you want to reserve the collision poly for collisions. These two conditions would do that:

    A.bbboxleft is between B.bboxLeft-A.width and B.bbboxRight
    A.bbboxTop is between B.bboxTop-A.Height and B.bbboxBottom
  • Thanks again, seems to be working for the most part but when multiple sprites overlap I encounter issues still.

    Here the table on the left slips under the table below it, and the table behind renders below the table under the table in front of it. The table on the right also slips under stuff it is supposed to be standing on.

    While the change in the code seemed to fix most issues of the player rendering incorrectly, here is the player being rendered behind a table it is above.

    I thought this might be due to the origin points not being at the bottom of the sprite, but they are in this screenshot and the problem still occurs regardless.

    Edit: I should also mention I'm using the BBox collision method instead of the default overlapping.

  • It’s hard to reason about more complicated cases. One thought that comes to mind is objects that are side by side on the x axis may be considered overlapping with that bounding box code. That would throw things off. Maybe shrinking it a bit may help:

    A.bbboxleft is between B.bboxLeft-A.width+1 and B.bbboxRight-1

Jump to:
Active Users
There are 1 visitors browsing this topic (0 users and 1 guests)