Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Question Setting Rotation of Thrown Object(s)

Discussion in 'Physics' started by m_daniel26, Jul 5, 2023.

  1. m_daniel26

    m_daniel26

    Joined:
    Feb 7, 2023
    Posts:
    57
    Using Unity 2021.3.20f1.

    In my game I'm trying to make an axe that is throwable, and then you have to go and retrieve the axe from where it lands (so not the "boomerang" effect of which there are millions of tutorials on, lol). I've basically got it working - except that when the thrown axe instantiates, the axe appears horizontally across the FOV instead of pointed away from the player. I've tried modifying the rotation of the prefab, and the spawn point, but nothing I do seems to makes any difference.

    Here's the throw portion of the code I have so far:

    Code (CSharp):
    1. GameObject axeInstance = Instantiate(throwableAxe, spawnPoint.position, throwableAxe.transform.rotation);
    2.         axeInstance.transform.rotation = Quaternion.LookRotation(-spawnPoint.forward);
    3.         Rigidbody axeRig = axeInstance.GetComponent<Rigidbody>();
    4.  
    5.         axeRig.AddForce(spawnPoint.forward * speed, ForceMode.Impulse);
    Any advice would be greatly appreciated!
     
  2. halley

    halley

    Joined:
    Aug 26, 2013
    Posts:
    1,834
    The code you showed looks like it assumes the axe's +Z local axis is outward from the blade's edge. If that's not true for your model, you'll have to correct for it.
     
  3. KillDashNine

    KillDashNine

    Joined:
    Apr 19, 2020
    Posts:
    449
    I assume it's a player/characer that's throwing the axe? Then your initial rotation needs to be relative to the character and not to spawnPoint, which I assume is a vector that just marks the position but is at a static rotation. Rotate it in relation to character.transform.forward.
     
  4. m_daniel26

    m_daniel26

    Joined:
    Feb 7, 2023
    Posts:
    57
    Correct - it's a FPS player throwing the axe, sorry for not specifying. I updated the second line to: axeInstance.transform.rotation = Quaternion.LookRotation(player.transform.forward); but it's still getting thrown sideways instead of straight out (also tried mainCamera.transform.forward just for kicks, but same effect). :/
     
  5. m_daniel26

    m_daniel26

    Joined:
    Feb 7, 2023
    Posts:
    57
    How would one specify which axis would be the outward axis?
     
  6. KillDashNine

    KillDashNine

    Joined:
    Apr 19, 2020
    Posts:
    449
    Open your prefab and take a look at your object. When your 3D model is imported, it will be fixed to local coordinates. Optimally, you would want to import your objects in a way that their local coordinates are useful, and in the case you'd need to import your axe in a way that the axe head if up (Y) and the axe edge is forward (Z).

    If it is not imported this way, make note that Quaternion.LookRotation creates a rotation that orients the transform's forward axis, as it makes the transform "look at" something. This would work if your axe has its head up and its edge is pointing forward. Now, you could use many other methods to rotate your object, but this will complicate your rotation code, because you'd want your actual object to be rotated in a ready-to-use way, and it would be best to rotate your gameobject's coordinate system.

    There are many ways. Such as
    1. Correct your object's orientation in Blender and re-export, then reimport in Unity
    2. Create an empty holder gameobject "wrapper" on top of your gameobject, and orient the sub-object
    3. (my preferred way) Use a free Asset called "Adjust Pivot" that is able to both repivot and to reorient your gameobject local coordinates in the scene view according to given transform. Then you can save the override to your prefab.
    I wanna say that Adjust Pivot is a staple tool for me and I use it pretty much with all of my prefabs. It does the job in 10 seconds. It absolutely should be a part of Unity. Method 2 (wrapper objects) complicates your gameobjects and is not feasible in many situations, as I am using some libraries that require your gameobjects to be composed in a particular way, and hence it's not always possible to freely choose the hierarchy.
     
    Last edited: Jul 6, 2023
    m_daniel26 likes this.
  7. m_daniel26

    m_daniel26

    Joined:
    Feb 7, 2023
    Posts:
    57

    I ended up going with option 2, as I already had some animations for the melee attack for the axe that I didn't want to have to fix, which I believe would result from 1 or 3 (though I agree that 3 sounds like a good option going forward, so thanks for that reference!) That got the axe facing the right way finally, only now when it's instantiated it's being thrown toward the player instead of away from it. Fix one thing, another one breaks, lol.
     
  8. KillDashNine

    KillDashNine

    Joined:
    Apr 19, 2020
    Posts:
    449
    If you use the wrapper method, you need to rotate the sub-object such that your object initial orientation is correct. But when you actually throw the axe, then you need to manipulate the parent wrapper object.
     
  9. m_daniel26

    m_daniel26

    Joined:
    Feb 7, 2023
    Posts:
    57
    Yeah that's how I did it - I rotated the sub-object (the axe model), and assigned the empty parent object (well, technically the prefab with the axe within the parent object) as the "throwableAxe" variable via the inspector.

    I have the rigid body attached to the parent object (since that's where the script is looking for it), and the mesh collider and renderer attached to the sub-object (since that's the actual model) - could that be effecting this outcome?
     
  10. KillDashNine

    KillDashNine

    Joined:
    Apr 19, 2020
    Posts:
    449
    Look at your force vector. It will get thrown to that direction. You'll want to use player.forward instead of spawnPoint.forwrd.
     
  11. m_daniel26

    m_daniel26

    Joined:
    Feb 7, 2023
    Posts:
    57
    I tried using both player.transform.forward and camera.transform.forward (I do have the camera already assigned for a different function in the same script), but either way it's still being launched toward the player instead of away. :/
     
  12. KillDashNine

    KillDashNine

    Joined:
    Apr 19, 2020
    Posts:
    449
    I wonder which way your player's coordinates are, then! :D With any transform, forward is the blue axis when you select the transform in the inspector and set the Scene View Tool Handles to use local coordinates.
     
  13. m_daniel26

    m_daniel26

    Joined:
    Feb 7, 2023
    Posts:
    57
    Welp. As seems to be often the case, I took a break, closed everything down for a few hours, came back, and now it's working. lol
     
    KillDashNine likes this.
  14. m_daniel26

    m_daniel26

    Joined:
    Feb 7, 2023
    Posts:
    57
    One last issue I'm having with the overall axe-throwing function (this one isn't technically physics, but I figured it'd be easier to keep it on this thread rather than start over from scratch in a new thread). After the axe has been thrown, I have it set to be collectable again, and for my collectable objects I have a UI graphic prompt (ie: "Press E to take"). For most of my collectables, I use the inspector to assign the Game Object that the graphic is attached to, but that doesn't work in this instance since the thrown axe is a spawned clone. I attempted to use "collectText = GameObject.Find("CollectText");" to assign it via script, and while that doesn't generate any errors outside of gameplay, when the thrown axe is instantiated, it generates a NullReferenceException. Any ideas on how to get around that?
     
  15. KillDashNine

    KillDashNine

    Joined:
    Apr 19, 2020
    Posts:
    449
    Prefabs will be instantiated just in the state they are if you inspect the prefab file. Whatever configurations you've set in the editor to an already instantiated prefab have nothing to do with any fresh instances instantiated in a script.

    I handle UI elements the way that I save all of them as prefabs, then instantiate them in the script using a custom InstantiateUIElement method that correctly initializes the RectTransforms scale and position parameters that typically have wrong values upon instantiation.

    ps. I would never recommend attaching UI elements to any of your gameobjects, but ideally your game and UI should be decoupled. The way I do it is using an event system. Player looking at something invokes an event which will trigger the UI RectTransform getting instantiated and positioned on your gameobject.
     
    m_daniel26 likes this.