• Hey! Guest! The 40th (!!!) GMC Jam will take place between February 25th, 12:00 UTC to March 1st 12:00 UTC. Why not join in this very special anniversary jam! Click here to find out more!

3D 3D instance_place() equivalent?

fishfern

Member
Hi Everyone!

I was wondering if anyone had some insight into how I could go about creating a script that returns the id of an object at a point in 3D space. I guess this means I'm essentially looking for a 3D equivalent of instance_place(), if such a thing is possible. I attempted to make a script that would do this (included below), however it doesn't appear to work at all. I'm guessing my code below is probably too basic, but I thought I'd try and cheese it (with no luck).


GML:
///d3d_instance_place_test(x,y,z,target);

var check_x = argument[0];
var check_y = argument[1];
var check_z = argument[2];
var tar = argument[3];

if position_meeting(check_x,check_y,tar)
{
    var tar_check = instance_position(check_x,check_y,tar);
    if ((tar_check.z <= check_z) && ((tar_check.z + height) >= check_z))
    {
        return tar_check
    }
    else
    {
        return noone;
    }
}
else
{
    return noone;
}
Any help is greatly appreciated!

I hope you all have a great evening!
 

TheouAegis

Member
I'm assuming "height" is how virtually "tall" sprites are.

Code:
var w = bbox_right-bbox_left,
    v = bbox_bottom-bbox_top,
    h = height;
with argument[3] {
    if abs(x-argument[0]) < (bbox_right-bbox_left + w)/2
    && abs(y-argument[1]) < (bbox_bottom-bbox_top + v)/2
    && abs(z-argument[2]) < (height + h)/2 {
        return id;
    }
}
 

fishfern

Member
You've built the 3D equivalent of instance_position(), not instance_place(). Do you know the difference?

Also, I suppose you mean to add the target's height instead of your own?
Oh, I hadn't noticed I missed the height check, thanks for that!

You have no idea how long I have been looking for a tutorial/explanation like this! I must have been seriously using the wrong search terms, thank you so much!

I'm assuming "height" is how virtually "tall" sprites are.

Code:
var w = bbox_right-bbox_left,
    v = bbox_bottom-bbox_top,
    h = height;
with argument[3] {
    if abs(x-argument[0]) < (bbox_right-bbox_left + w)/2
    && abs(y-argument[1]) < (bbox_bottom-bbox_top + v)/2
    && abs(z-argument[2]) < (height + h)/2 {
        return id;
    }
}
Thanks for this!I haven't used bboxes much, so this was a crash course! I changed the maths a tad, as my objects are anchored in the top right at 0,0, so when I left the maths as it was, only the top-right quarter of the object would register a collision.

I did find a couple of issues/bugs that I'd love some advice with. I took some quick screencaps to illustrate what I mean:
RayCast_Collision_Test1_1.png

I found that only four of the sixsides of the cubes were registering collisions. I did manage to fix this one, as I realised that the two sides not registering were on the greatest x, and greatest y sides. I just added a '+1' to the w and v check, because the radius of my ray cast is 1. That seems to fix things, but if you have any insight into a better solution, I'm certainly happy to learn!

My other bug related to (in two separate instances) the collision/click being registered by a different instance to the one I am actually clicking on. I'll include two screen shots to show what I mean:

RayCast_Collision_Test1_2.png
RayCast_Collision_Test1_3.png

I honestly have no idea how to even approach fixing this one. Strangely enough, in the first example (the vertical stack), once the top box is removed (clicking destroys the instances of the boxes), the bottom box registers collisions fine.

Thank you so much for your help, and any help or advice you can give!
 

TheouAegis

Member
Yeah, I forgot to add 1 to w and v. That was my bad. It's because bbox_right and bbox_bottom are measured from the top-left corners of the pixels, so that puts the width and height off by 1. Good catch. But the same would apply to "bbox_right-bbox_left" and "bbox_bottom-bbox_top" in the rest of the code, you'd need to add 1 to both of those to be entirely accurate.

For the wrong boxes, I'd guess it was how z and height relate, but since it's also an issue with the horizontal boxes, I really don't know. Is the projection the same in both screenshots?

Is the red sphere supposed to be the cursor?

One idea I had, if you haven't come up with it yourself, is
Code:
var w = bbox_right-bbox_left + 1,
    v = bbox_bottom-bbox_top + 1,
    h = height;
with argument[3] {
    if abs(x + sprite_width/2 - argument[0] - w/2) < (bbox_right-bbox_left + 1 + w)/2
    && abs(y + sprite_height/2 - argument[1] - v/2) < (bbox_bottom-bbox_top + 1 + v)/2
    && abs(z + height/2 -argument[2] - h/2) < (height + h)/2 {
        return id;
    }
}
Since the origin is in the corner, instead of comparing corner to corner, compare midpoints.
 

fishfern

Member
Yeah, I forgot to add 1 to w and v. That was my bad. It's because bbox_right and bbox_bottom are measured from the top-left corners of the pixels, so that puts the width and height off by 1. Good catch. But the same would apply to "bbox_right-bbox_left" and "bbox_bottom-bbox_top" in the rest of the code, you'd need to add 1 to both of those to be entirely accurate.

For the wrong boxes, I'd guess it was how z and height relate, but since it's also an issue with the horizontal boxes, I really don't know. Is the projection the same in both screenshots?

Is the red sphere supposed to be the cursor?

One idea I had, if you haven't come up with it yourself, is
Code:
var w = bbox_right-bbox_left + 1,
    v = bbox_bottom-bbox_top + 1,
    h = height;
with argument[3] {
    if abs(x + sprite_width/2 - argument[0] - w/2) < (bbox_right-bbox_left + 1 + w)/2
    && abs(y + sprite_height/2 - argument[1] - v/2) < (bbox_bottom-bbox_top + 1 + v)/2
    && abs(z + height/2 -argument[2] - h/2) < (height + h)/2 {
        return id;
    }
}
Since the origin is in the corner, instead of comparing corner to corner, compare midpoints.
Hahaha it wasn't so much a good catch as pure luck. I feel like I've learnt a lot from that though, so thanks a bunch!

Oh, I like comparing midpoints, for some reason it's easier to visualise mentally.

Oddly enough, that appears to have fixed the horizontal doubling! I'm not entirely sure what was going on there, it seemed to only be that specific set of boxes, too.

I did have a look at the relation between z and height, and found that I was able to fix the vertical issue by making 'h' a much smaller value (I chose 4 off the cuff, and it appears to work perfectly). I could just not be seeing it at all but why would that make such a difference? Similarly, is there a specific reason why 'h' was given the value of the calling object's height? Apologies for asking all these questions, I just can't believe I'm starting to make some headway into a system that has had me stumped for (literally) years.

Thanks so much for your assistance, I really appreciate it!
 

YellowAfterlife

ᴏɴʟɪɴᴇ ᴍᴜʟᴛɪᴘʟᴀʏᴇʀ
Forum Staff
Moderator
The way I have approached this issue in past was grabbing instances overlapping on XY plane via instance_place_list and then going over them to pick the ones that overlap on Z axis (using a custom check)
 

TheouAegis

Member
Yeah, that works too. LOL The more stones you throw at a bird, the more likely you are to kill it.

As for the h, if you're asking why I didn't just use other.h directly in the equation, no reason. lol if you're asking why I even referenced it, it's for the same reason weight and height are referenced. For any two geometric shapes, each dimension overlaps when half the sum of their dimensions is more than the distance between their centers.
 

fishfern

Member
The way I have approached this issue in past was grabbing instances overlapping on XY plane via instance_place_list and then going over them to pick the ones that overlap on Z axis (using a custom check)
Oh right! I did see something that seemed be along this line, but I couldn't make sense why it used the list. Out of curiosity, is setting up/destroying data structures resource intensive?


Yeah, that works too. LOL The more stones you throw at a bird, the more likely you are to kill it.

As for the h, if you're asking why I didn't just use other.h directly in the equation, no reason. lol if you're asking why I even referenced it, it's for the same reason weight and height are referenced. For any two geometric shapes, each dimension overlaps when half the sum of their dimensions is more than the distance between their centers.
Oh right, that makes sense! in my current application it the test applies to a raycast, so the height isn't so much of a deciding factor, but it's super handy to know how ti might relate to other objects/collisions in game.

Thank you so much for your invaluable help!
 

YellowAfterlife

ᴏɴʟɪɴᴇ ᴍᴜʟᴛɪᴘʟᴀʏᴇʀ
Forum Staff
Moderator
Oh right! I did see something that seemed be along this line, but I couldn't make sense why it used the list. Out of curiosity, is setting up/destroying data structures resource intensive?
You can reuse (clear-fill-check) the same global list across function calls. These use lists specifically since they are easier to reuse.
 
Top