Instantiating GameObject as a child and freezing relative position/rotation

I’m making a little game where a beaver chews down trees and gathers logs to use for building a dam. The trees get destroyed once they’re chewed down. Then, when the player wants to use them for building, they left-click to instantiate the trunk (the log) in front of the beaver, right-click to rotate it how they want (one of three orientations), and then left-click again to place it at some location. The problem I’m having is instantiating the trunk so that it stays in front of the beaver, initially (until the player right-clicks) oriented left-to-right, as it moves and jumps. The trunk also isn’t meant to detect collisions during this time, though I don’t think I’m having a problem with that.

I’ve gotten it to where the trunk instantiates in the correct position and at the correct initial rotation, but it wouldn’t follow the beaver upward when the beaver jumped. However, I’ve spent several hours trying to fix the problem, messing one thing up while fixing another, and I don’t remember how I got as far as I did then. My current problem seems to be that the trunk is stuck instantiating at a set world position and rotation instead of ones local to the beaver. I’m sure this is an easy issue to fix, but every time I go into the code, I can’t fix it.

Current code below. I’m trying to write the ReadyLog() function:

using UnityEngine;
using System.Collections;

public class Inventory : MonoBehaviour {
	
	// Current number of logs possessed
	int logNum = 0;
	
	public GUISkin logSkin;
	public Rect displayArea;
	public Rect logDisplay;
	
	// Indicates if a log has been instantiated (with the ReadyLog() function)
	bool logReadied = false;
	// Reference to the log in use
	GameObject log;
	// Reference to the tree prefab
	public GameObject tree;
	// For the orientation of the instantiated, but not-yet-placed, log
	Direction dir = Direction.LeftRight;
	
	void OnGUI(){
		GUI.skin = logSkin;
		GUI.BeginGroup(displayArea);
		GUI.Label(logDisplay, logNum.ToString());
		GUI.EndGroup();
	}
	
	// For the orientation of the instantiated, but not-yet-placed, log
	enum Direction{
		LeftRight,
		UpDown,
		ForwardBackward
	};
	
	// Called from another script, increments the number of logs possessed
	void AddLog(){
		logNum++;
	}
	
	// Instantiates the tree model's trunk and locks it in place relative to the beaver object
	void ReadyLog(){
		log = Instantiate(tree, /*PROBLEM CODE GOES HERE*/) as GameObject;
		log.transform.parent = transform;
		/*PROBLEM CODE MAY ALSO GO HERE*/
		log.rigidbody.detectCollisions = false;
		log.transform.FindChild("Leaf").renderer.enabled = false;
		
		logReadied = true; 		//Indicates readiness for log's placement in world
	}
	
	// Locks the log in place after it's been instantiated and rotated (if desired)
	void PlaceLog(){
		log.transform.parent = null;
		log.rigidbody.constraints = RigidbodyConstraints.FreezeAll;
		logNum--;
	}
	
	// Rotates the log to one of three orientations, in sequence
	void TurnLog(){
		if(dir==Direction.LeftRight){
			log.transform.RotateAround(Vector3.forward,90f);
			dir = Direction.UpDown;
		}
		if(dir==Direction.UpDown){
			log.transform.RotateAround(Vector3.right,90f);
			dir = Direction.ForwardBackward;
		}
		if(dir==Direction.ForwardBackward){
			log.transform.RotateAround(Vector3.up,90f);
			dir = Direction.LeftRight;
		}
	}
	
	// Detects when the player wants to instantiate, and then place, a log
	void Update(){
		if(!logReadied  logNum > 0  Input.GetMouseButtonDown(0)){
			ReadyLog();
		}
		if(logReadied  Input.GetMouseButtonDown(0)){
			PlaceLog();
		}
		if(logReadied  Input.GetMouseButtonDown(1)){
			TurnLog();
		}
	}
}

I’m also aware that my GUI doesn’t currently work, but that’s something I’ll look into after this issue is resolved. I have Will Goldstone’s great book that I used to construct a tutorial game, so I have some prior experience with things.

Thanks in advance for any assistance.

well about the log not following the player why not parent a empty gameobject in front of the player and once the object is instantiated you can make that game object follow the position such as saying: log.position = emptytransform.position "this is pseudo code by the way lol.
now about the collision of the log witht he objects use the get component class to get the cloddier and turn it off, or have it off first before even instantiating and then once you pllace the log where you want it make it so it turns it back on.

another thing too i didn’t mentioning about parenting it since you said that you wanted to be able to place the log at whicever rotation you wanted it. sometimes you don’t really need to parent you can just make it equals a position of another object and that way you can controll the rotations of your log when you want to place it around.

At any point you can set the log’s global transform, and changes in parenting won’t affect that (until the parent object moves). So you can set it before or after you parent the log to the beaver, for example.

If you wait until after you parent the log, though, you can instead set the localPosition and localRotation relative to the beaver, which will be constant. This is probably the easiest way to get what you want.

e.g.

    log.transform.localPosition = new Vector3(0, 0, 1); // 1 metre in front of the beaver
    log.transform.localRotation = Quaternion.AngleAxis(90, Vector3.forward);

The orientation code is just an example - it depends on how your log model is oriented. What I wrote will work if the log is aligned to its Y axis, so you want to rotate it 90 degrees about the beaver’s forward direction to make it go from left to right.

@foxter888

I’d thought about placing an empty object in front of the beaver as a child in order to use its location for instantiation of the logs, as you suggest, but I wanted to see if I could do it the way I’ve been attempting, just for practice. This is a very short-term project, to be completed by March 5th. I actually have a much bigger project in the planning stages, and I don’t want to cheat myself out of learning something that will probably be immensely useful later on.

As for collisions, I currently have the command “log.rigidbody.detectcollisions = false” in the above code, which – correct me if I’m wrong – should have the same effect as locating and disabling the collider component. Regarding disabling the collider prior to instantiation, the game begins with a forest of trees, possibly hand-placed instead of placed via script. To disable the collider prior to instantiating in the building phase, wouldn’t I need to disable the collider in the prefab, which would disable it in every tree in the forest before it’s cut down? This would be inconvenient, as I need the colliders enabled at the start of the game so the trees will impact the ground when they’re cut down.

Also, something I just thought of: Since I’m rotating the log (trunk) prior to placement, its center point would need to be located at different positions in front of the beaver depending on which orientation it’s in. Left-to-right, it would be ground-level. Up-down, I would need to shift its center so half of it isn’t below-ground (just for practical reasons when it comes to placing it in that orientation). Forward-backward might be similar, but it would be ground level and the center would be farther away from the beaver.

@George Foot

My ReadyLog() function is now as follows:

// Instantiates the tree model's trunk and locks it in place relative to the beaver object
	void ReadyLog(){
		log = Instantiate(tree) as GameObject;
		log.transform.parent = transform;
		log.transform.localPosition = new Vector3(0,0,1);
		log.transform.localRotation = Quaternion.AngleAxis(90,Vector3.up);
		log.rigidbody.constraints = RigidbodyConstraints.FreezeAll;
		log.rigidbody.detectCollisions = false;
		log.transform.FindChild("Leaf").renderer.enabled = false;
		
		logReadied = true; 		//Indicates readiness for log's placement in world
	}

(The beaver is much longer than one meter, so I’ll need to adjust the position value.) This places the log in the correct initial orientation, but the log doesn’t translate or rotate with the beaver after that – it just stays still and grounded. If I comment out the logReadied bool, leaving it false, I get something better, but still not what I need (and I really don’t understand why leaving it false would do this): The log instantiates in the correct initial rotation and will follow the beaver’s rotation and movement properly… except that it won’t rise into the air with the beaver during a jump.

i’m glad you are able to make it through, and what you said about doing the position of the log differently than what i suggested you are right.
there is not really a right or wrong in unity as long it works like it needs be what i love about unity is that there are always several ways of doing a certain thing inside unity. even do eventually we have our points where we get stuck but it’s great when we get the rewarding joy of solving a puzzle that probably took days and long hours of staring at the screen lol.

i would call myself and agressive coder lol, when i get stuck on something i curse our my pc lol, once i fix it feels like i saw a good team winning a homerun, or touchdown or goal lol

Well, as I said in my last post, I didn’t actually get it to work. I have several years of experience in coding, but whether it’s the fact that I’m rusty or the fact that I’m not accustomed to code that can run each frame, I just can’t figure out why changing my logReadied bool makes such a large difference, nor have I been able to see why I can’t get the log to follow the beaver into the air during a jump. This is really perplexing, and despite trying to fix it for most of yesterday, I’ve still made little or no progress.

If anyone has more ideas about why my code isn’t working or what it needs, I’d be grateful for further suggestions.

I’d guess that the rigid body is preventing the child object from moving with the parent. Maybe you can just disable its rigid body until you want it to behave as an indepedent object. Otherwise, you could make the RB kinematic and reset its local position and rotation on every frame.

Thanks, George! I’d completely forgotten about the “isKinematic” bool. Setting that to true really helped. Problem solved! I also managed to implement rotation of the log today, which I finally got right after having difficulty with the left-handed coordinate system Unity uses. Sculpted and textured the terrain, and added a skybox and a lake/river, too.

One further question, this time related to terrain texturing: Is there something I could do to make the opacity setting more feasible to mess around with? It always behaves more similarly to an on/off switch than something with at least 100 different settings.