if colliders tag is equal to "whatever" transform.position = collider.position

Was having trouble understanding and getting my building system from before to work, so I’ve started trying to write it a different way. No clue if it will end up working or not, but it’ll be a valuable learning experience.

In my raycast I want to check if the collider’s tag is equal to “something” (in this instance “Foundation_SnapPoint”) and if so, move the instantiated object to the position of the collider. Looking at the old scripts, I thought what I have might work, but it isn’t an I’m not sure how to go about it. Any help would be appreciated.

Edit: The Foundation_SnapPoint is a child of the foundation. Just thought to check the transform on the SnapPoint and noticed the position is 1, 0, 0, which makes sense as it is exactly one foundation over from the actual foundation. I could see that being a problem, however, the object isn’t moving it’s position to 1,0,0 worldspace or anything when the raycast hits the SnapPoint, so I’m still at a loss there. Sorry if this is confusing, kind of confusing myself. lol

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class BuildingSystem : MonoBehaviour
{

    public GameObject foundation;
    private GameObject previewGameObject = null;

    public bool isBuilding;

    public LayerMask layer;

    // Start is called before the first frame update
    void Start()
    {
      
    }

    // Update is called once per frame
    void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            NewBuilding(foundation);
        }
        if (isBuilding)
        {
            CastBuildRay();
        }
    }

    private void CastBuildRay()
    {
        Ray ray = new Ray(Camera.main.transform.position, Camera.main.transform.forward);
        RaycastHit hit;

        if (Physics.Raycast(ray, out hit, 25f, layer))
        {
            Debug.Log(hit.collider.name);
            if (previewGameObject == foundation && hit.collider.tag == "Foundation_SnapPoint")
            {
                previewGameObject.transform.position = hit.collider.transform.position;
            }
            else
            {
                //Use 3 lines below for primitives
                float y = hit.point.y + (previewGameObject.transform.localScale.y / 2f);
                Vector3 pos = new Vector3(hit.point.x, y, hit.point.z);
                previewGameObject.transform.position = pos;

                //previewGameObject.transform.position = hit.point; //use this if importing properly anchored models
            }
        }
        else
        {
            var pos = ray.origin + ray.direction * 25f;
            previewGameObject.transform.position = pos;
        }

    }

    public void NewBuilding(GameObject _go)
    {
        var lookPos = Camera.main.transform.position + Camera.main.transform.forward * 25f;
      
        previewGameObject = Instantiate(_go, lookPos, Quaternion.identity);
        isBuilding = true;
    }
}

Some things:

You have this code: `if (previewGameObject == foundation’

But ‘previewGameObject’ is some object you’ve just instantiated a moment ago, so I don’t see how it could ever equal something you already have a reference to. Maybe you can explain that code, because I don’t understand it.

In general:

  • Put breakpoints or debug statements more liberally throughout your code, so you can figure out exactly what line of code isn’t being reached.
  • Instead of hit.collider.tag == "Foundation_SnapPoint"', do this: hit.collider.gameObject.CompareTag(“Foundation_SnapPoint”)'. It does the tag comparison without generating garbage.
1 Like

Hi. Thanks for the response. I’ll explain what I’m trying to do in more detail.

I plan on adding more public GameObjects, wall, ceiling, etc, assigned to either number keys or eventually a hotbar. I then want to be able to instantiate the foundation, walls, etc that I have slotted into those spots in the editor. For now all I’m trying to do is use NewBuilding(foundation) to instantiate whatever I have slotted upon mouse click and set isBuilding to true so it starts the raycast. That is all working as intended for the moment. With the “if(previewGameObject == foundation” chunk I’m trying to check if the currently instantiated object is in the foundation slot, if it is and my ray is hitting a collider with the appropriate tag, I am then trying to move it to the position of that collider with the “previewGameObject.transform.position = hit.collider.transform.position;” I assume I am going about it all wrong though based on your response. lol. Hopefully I explained this well enough.

Edit: You got me thinking and I just changed “If (previewGameObject == foundation…)” to just “if (foundation…)” and it is now ‘snapping’ and ‘unsnapping’ as intended. Thank you very much for your help.

Are you sure that `previewGameObject == foundation’ is ever true? I still don’t see how that is likely to be true. The previewGameObject is created by you on line 68 of the code you included here. Although you’re cloning the foundation object to create it, the clone and the original won’t be the same object, so I’d expect that would always be false, and your tag comparison code would never even be called.

1 Like

Dang. You’re right. I assumed it was working the way I wanted because it was snapping and unsnapping. I got so excited I even made a little gif to show it was working. Lol.

https://gph.is/g/a9polLP

So yeah, as I was saying before I plan on there being more slots, not just the Foundation slot. All I’m really trying to achieve now I guess is making that tag comparison. The snapping part was always working I suppose.

How would I go about that?

Edit: I removed the tag comparison and it still worked… because of course it did. Duh. I just added back the tag comparison but only said “Foundation_Snap” so it wouldn’t be true and it didn’t work. I then corrected it to “Foundation_SnapPoint” and it did work. So I guess it is actually making the comparison and working correctly? Lol. That’s honestly just a guess. It seems to be. As per your suggestion earlier, I think I need to look into debugging and pointbreaks, been having trouble doing some very simple debug statements, and they’d really help. I’ll do that now.

Edit:2 Just though of a quick check to do and said (!foundation…) and it didn’t work. Don’t know if that proves anything.

4541509--421204--BSSlot.png

Edit: Fixed it. This seems like it will make some stuff in the future easier, as well. Such as having multiple types of foundation/walls snap. Changes below.

 if (previewGameObject.tag == "Foundation" && hit.collider.tag == "Foundation_SnapPoint" ||
                previewGameObject.tag == "Wall" && hit.collider.tag == "Wall_SnapPoint")
            {
                previewGameObject.transform.position = hit.collider.transform.position;
            }

Went ahead and created a wall gameobject, slot and snap points on my foundation tagged “Wall_SnapPoints.” Can now instantiate a foundation with 1 or a wall with 2, so I tested it out. My foundations and walls both snap to my “Foundation_SnapPoints” and when I add the check for the wall snap points, they both snap to the wall as well. It seems the tag comparison is working, I’m just not properly checking if the instantiated object is from the appropriate slot or not.

How can I check to see if the instantiated object is from the correct slot? (foundation for foundation, wall for wall and so forth.)

Edit: For Clarifications sake.

if (foundation && hit.collider.tag == “Foundation_SnapPoint”)

Right of && is working (so far as I can tell.) Left of && is not.

Cool gif. I always like when game UIs do that snapping stuff.

A couple of things. First, use the CompareTag function (Unity - Scripting API: Component.CompareTag) instead of using == to test for the tag names. It might not make much difference on a small scale, but it’s more efficient for Unity (generates less garbage).

Second, in your if' statement, each of the conditions needs to evaluate as a boolean type. Your tag comparison is a boolean, but simply saying if (foundation)’ is not usually considered correct. It might work, but it’s not quite clear what your intent is. Most likely you mean `if (foundation != null)', maybe? In any case, sometimes you can get away with this kind of syntax, but you should be more explicit about what that test is checking for.

Third, watch out with complex conditions like you have there, with lots of && and ||. C# considers && to be “stickier”, or have a high precedence. So the code you posted in your last comment probably holds together like you want, but I would personally wrap portions of that statement with parens to avoid confusion over whether your code means (A && B) || (C && D), or whether it means AA && (BB || CC) && DD.

So anyway, that’s mainly code style stuff, but it can easily lead to confusion.

That logic generally seems reasonable to me, though, from a pure functionality perspective. I assume you’ve confirmed that previewGameObject' is taking on the correct tag in both cases? The tag isn't wrong, or getting set to Default or something? Another approach, instead of testing previewGameObject's in each raycast, is to store another class variable like previewGameObjectType’, in which you store an enum value representing whether the current preview object is a Foundation, a wall, etc. You’d test that at the same time you Instantiate the previewGameObject. Probably won’t make an actual difference, but it could lead to cleaner feeling code.

Anyway, short answer is I’m not quite sure what’s wrong with your code. It pretty much seems like it should work. So you should add more diagnostics. Debugging your code is a critical skill to learn, so I highly recommend you take a few minutes to understand how the debugger (such as in Visual Studio) works, and step through your code so you can see the current values for everything, and understand why you’re reaching parts of your code you weren’t expecting to.

1 Like

I should have been more clear with that last edit I did(the one at the top of my last post.) I got it working as intended… well, at least it’s doing what I want it to do. For your second point, my intent was just to see if the instantiated object came from the foundation slot. I changed that to “if (previewGameObject.tag == “Foundation” && hit.collider.tag == “Foundation_SnapPoint”” then made sure it was working with the other building pieces and that none of them are snapping where they shouldn’t be. So rather than checking which slot the instantiated object came from I’m just comparing the tags.

I’d still love to know if there is a way to check what slot the instantiated object is from, if that is even possible.

Honestly, most of what you just posted went way over my head. Still very new to this, only experience I have is following some tutorials years ago for stuff that was way beyond me, and of course I didn’t really learn much. In fact, it has become painfully obvious that I still need to learn a lot of terminology, simple terminology even. I don’t know what to call half of this stuff, it’s all “functions” and “conditions” to me. lol.

That being said, I thank you for all your help and advice. I will start looking into changing my code to use the CompareTag function you mentioned, then read further into your post and see if I can possibly wrap my head around any more of it.

I’ll drop another gif below. In it you can see it is all snapping as it should. You can probably also see that I’ve got some things to work out. Such as not being able to access a snap point that is behind another unless some of it is actually visible to the raycast. I think I’ve learned enough at this point that I could just go back to the Partum Game Tutorials tut script that I followed in the first place and then modified. Think I could get it working how I want now. I’ll stick with trying to write this one though, think I’m going to learn a lot from it. Already starting to see why he used multiple scripts, as I’m not for sure how I’m going to do some things with this one. I’ll stick with trying to write this one to completion though, I’m learning a lot and for the most part can actually explain all of my code (to myself at least, if not to others lol.)

BareRedIndigowingedparrot

Again, thank you for all your help, patience and kindness. Much appreciated.

1 Like

Looks good. You might have already done this, but in addition to setting the position while snapping, you probably also want to match the rotation of the object to the snap-to object. That’ll get your walls lined up.

Also, depending on whether you like the idea of nearer things blocking the snapping (the way your wall snap-to objects are blocking the raycasting of the far foundation), you can use RaycastAll to get more than just the closest raycast. Just something to be aware. Nice work overall, though.

1 Like

As for the rotation, I am planning to change it to where it orientates itself based on the snap points rotation. I think I know how to do that, though haven’t tried it yet. Also going to add a rotation key. Think I understand how to do the first… simply rotate my snap points facing the way I want, so for example the wall snap points would all be facing out from the foundation and then set the rotation just as I set the position.

This RaycastAll you speak of, I’ll definitely have to look into that. I don’t want the snap points blocking each other, especially since this is first person and I won’t be floating around in the air like I have been in these gifs. lol. One thing I’d really like to do is have a key to toggle between available snap points, I had no clue how I was going to do that, and still don’t. It seems like that would probably be possible and easier with the RaycastAll.

To do list: A place building function, a change color function for if I’m snapped or not (doesn’t seem necessary, but would be nice,) a cancel building function and the aforementioned toggle snap point function. Not quite for sure how I’m going to do those first 2. Right now the objects I’m instantiating are actually the preview prefabs, which isn’t clear and I need to alter the code to reflect that. Thinking I might have to take a leaf from that tutorial I mentioned and separate some of this into another script that I can actually place on the preview prefabs. Oh, and one last function I’d love to have but have absolutely no clue how to do it at this point and all my googling has not led me to any good answers, is to some how be able to hide all the snap points (either through deactivating the object or just disabling its mesh renderer, not for sure which would be best atm) and only make them visible when appropriate. Such as only the foundation snap points showing when I’m “holding” a foundation, and wall snap points when I’m holding a wall.

Anyways, I got working what I was trying to get working when I began this thread. It is technically solved. Typing all this out and your responses (which have gone above and beyond what was expected) are really helping me think all this through and work it out in my head. I’m not saying “THREAD CLOSED.” Just that my original problem has been solved. I appreciate and will respond to any further responses. Thanks.