Newbie here. I want to Instantiate a GameObject to a specific position on the Parent. I want to place it at the top of the parent. Can I position it immediately when I instantiate it or do I need to use the transform.position? In either case I don't know how to do it. I also need to figure out how to rotate the child on the parent if you are feeling generous with your time. Also, each child/copy or new instantiated object will scale with each new iteration. I'm trying to build a reverse fractal tree (the branches get bigger over time).
Just a warning - you might cringe at other parts of the code that probably could be written better.
using UnityEngine;
using System.Collections;
public class ExampleClass : MonoBehaviour
{
public Transform Cube;
public GameObject masterTree;
public int instanceCounter = 1;
public int numCubes = 30;
public float scalar = 1.4145f;
public float initialScale = 10f;
public float angle = 30f;
private Transform copy;
void Start()
{
}
private void Update()
{
if (instanceCounter <= numCubes)
{
if (instanceCounter == 1)
{
copy = Instantiate(Cube, new Vector3(0, 0, 0), Quaternion.identity);
copy.transform.localScale = new Vector3(1f, initialScale, 1f);
copy.name = "Copy" + instanceCounter;
copy.transform.parent = masterTree.transform;
instanceCounter++;
}
var copyParent = GameObject.Find("Copy" + (instanceCounter - 1));
Vector3 copyParentSize = copyParent.GetComponent<Renderer>().bounds.size;
Debug.Log("copyParentSizeY = " + copyParentSize.y);
copy = Instantiate(Cube, new Vector3(0, 0, 0), Quaternion.identity);
copy.transform.localScale = new Vector3(1f, initialScale, 1f);
initialScale = initialScale * scalar;
copy.name = "Copy" + instanceCounter;
//copy.transform.rotation *= Quaternion.Euler(angle, angle, 0);
copy.transform.parent = copyParent.transform;
instanceCounter++;
}
}
}
If I understands your needs right...
There is a Instantiate method with Parent parameter, so you can create new GO as a child of your parent
public static Object Instantiate(Object original, Transform parent);
If you want to have some kind of pivot, you can create empty GameObject in your target parent, shift it to right position and instantiate your GO as a child of that empty GO.
Also you can wrap your Cube in another empty GameObject (ex: position 0,0,0), so you can shift Cube up (0,5,0), but origin of whole GameObject remains same (0,0,0).
I understand Vector3 better now. It looks like I can add together different GameObject positions together in the same Vector3:
newPosition = new Vector3(0, copyParentSize.y + copyParentPosition.y + spacer, 0);
Now I move objects around based on the location of other objects.
Thank you for your help!
Related
Following this question How to align sprites of smaller sizes to a moving gameobject sprite?, I'm trying to redraw my sprites to avoid rendering transparent pixels and try to maximize performance, and as I try starting this process with the sword sprites, I need to change the way the Sword game object follows the Player, which before was handled simply by using transform.position = hero.transform.position; because since both objects use sprites that are perfect squares they would have the same pivot point despite their size difference.
At first, it seemed to me the problem lied in how the pivots are different, thus I would need to update the transform position of the Sword every time its attack animation changes sprites. For that, I made a function which updates variables that influence the position as that gets updated:
here, heroTransform is a variable which gets sent the Player's transform property on the script's Start function as heroTransform = hero.transform;, where hero is defined right above it as hero = GameObject.Find("Hero");.
I would have expected this to make the Sword which is equipped with this script, called WieldablePosition to follow the player position, but it seems stuck in the same position as it starts:
I'm not sure, but I don't think I changed anything that would stop the Sword from moving. In what cases could a GameObject remain in a single place even as the transform.position is modified? For reference, please view the script:
using UnityEngine;
public class WieldablePosition : MonoBehaviour {
GameObject hero;
HeroMovement heroMovementScript;
private Transform heroTransform;
protected Animator anim;
private bool isAirAttackSingle;
private bool isFacingLeft;
private float x = 0;
private float y = 0;
void Start() {
hero = GameObject.Find("Hero");
heroTransform = hero.transform;
heroMovementScript = hero.GetComponent<HeroMovement>();
anim = GetComponent<Animator>();
isAirAttackSingle = heroMovementScript.isAirAttackSingle;
isFacingLeft = heroMovementScript.isFacingLeft;
}
void Update() {
UpdatePosition();
isAirAttackSingle = heroMovementScript.isAirAttackSingle;
isFacingLeft = heroMovementScript.isFacingLeft;
anim.SetBool("isAirAttackSingle", isAirAttackSingle);
if (isFacingLeft) {
transform.localScale = new Vector3(-1, 1, 1);
} else {
transform.localScale = Vector3.one;
}
}
public void SetPosition(AnimationEvent eventParams) {
string[] eventPositions = eventParams.stringParameter.Split(',');
x = float.Parse(eventPositions[0]);
y = float.Parse(eventPositions[1]);
}
private void UpdatePosition() {
transform.position = new Vector2(heroTransform.position.x + x, heroTransform.position.y + y);
}
}
I would like to calculate a new position based on the pitch of a mesh in order to make an object following the top of my object which is rotated:
And result in:
I cannot make the square object as represented above as a child (in the Unity object hierarchy) of the line object because the rotated object can see its scale changed at anytime.
Does a mathematics solution can be used in this case?
Hotspots
If you'd like to place something at a particular location on a generic object which can be scaled or transformed anywhere, then a "hotspot" can be particularly useful.
What's a hotspot?
Edit the target gameobject (the line in this case) and add an empty gameobject to it. Give it some appropriate name - "cross arms hotspot" for example, and then move it to the location where you'd like your other gameobject to target. Essentially, a hotspot is just an empty gameobject - a placement marker of sorts.
How do I use it?
All you need is a reference to the hotspot gameobject. You could do this by adding a little script to the pole gameobject which tracks it for you:
public class PowerPole : MonoBehaviour {
public GameObject CrossArmsHotspot; // Set this in the inspector
}
Then you can get that hotspot reference from any power pole instance like this:
var targetHotspot = aPowerPoleGameObject.GetComponent<PowerPole>().CrossArmsHotspot;
Then it's just a case of getting your target object to place itself where that hotspot is, using whichever technique you prefer. If you want it to just "stick" there, then:
void Start(){
targetHotspot = aPowerPoleGameObject.GetComponent<PowerPole>().CrossArmsHotspot;
}
void Update(){
transform.position = targetHotspot.transform.position;
}
would be a (simplfied) example.
A more advanced example using lerp to move towards the hotspot:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CrossArmsMover : MonoBehaviour
{
public GameObject PowerPole;
private GameObject targetHotspot;
public GameObject CrossArms;
public float TimeToTake = 5f;
private float timeSoFar;
private Vector3 startPosition;
private Quaternion startRotation;
// Start is called before the first frame update
void Start()
{
startPosition = CrossArms.transform.position;
startRotation = CrossArms.transform.rotation;
targetHotspot = PowerPole.GetComponent<PowerPole>().CrossArmsHotspot;
}
// Update is called once per frame
void Update()
{
timeSoFar+=Time.deltaTime;
var progress = timeSoFar/TimeToTake;
// Clamp it so it doesn't go above 1.
if(progress > 1f){
progress = 1f;
}
// Target position / rotation is..
var targetPosition = targetHotspot.transform.position;
var targetRotation = targetHotspot.transform.rotation;
// Lerp towards that target transform:
CrossArms.transform.position = Vector3.Lerp(startPosition, targetPosition, progress);
CrossArms.transform.rotation = Quaternion.Lerp(startRotation, targetRotation, progress);
}
}
You would need to put a script on the following gameobject in wich you would put :
GameObject pitcher = //reference to the gameobject with the pitch;
const int DISTANCE_ON_LINE = //distance between the 2 objects
void Update() {
transform.position = pitcher.transform.position + pitcher.transform.forward * DISTANCE_ON_LINE;
}
I'm trying to make a pong game where the player has to move both paddles. They are currently set as dynamic 2D Rigidbodies(collision detection continuous) and have a box collider (is NOT trigger) attached.
The problem is the paddles won't collide with the surrounding box colliders I set on the camera, using the following script :
using UnityEngine;
using System.Collections;
namespace UnityLibrary
{
public class EdgeCollider : MonoBehaviour
{
public float colDepth = 4f;
public float zPosition = 0f;
private Vector2 screenSize;
private Transform topCollider;
private Transform bottomCollider;
private Transform leftCollider;
private Transform rightCollider;
private Vector3 cameraPos;
// Use this for initialization
void Start () {
//Generate our empty objects
topCollider = new GameObject().transform;
bottomCollider = new GameObject().transform;
rightCollider = new GameObject().transform;
leftCollider = new GameObject().transform;
//Name our objects
topCollider.name = "TopCollider";
bottomCollider.name = "BottomCollider";
rightCollider.name = "RightCollider";
leftCollider.name = "LeftCollider";
//Add the colliders
topCollider.gameObject.AddComponent<BoxCollider2D>();
bottomCollider.gameObject.AddComponent<BoxCollider2D>();
rightCollider.gameObject.AddComponent<BoxCollider2D>();
leftCollider.gameObject.AddComponent<BoxCollider2D>();
//Make them the child of whatever object this script is on, preferably on the Camera so the objects move with the camera without extra scripting
topCollider.parent = transform;
bottomCollider.parent = transform;
rightCollider.parent = transform;
leftCollider.parent = transform;
//Generate world space point information for position and scale calculations
cameraPos = Camera.main.transform.position;
screenSize.x = Vector2.Distance (Camera.main.ScreenToWorldPoint(new Vector2(0,0)),Camera.main.ScreenToWorldPoint(new Vector2(Screen.width, 0))) * 0.5f;
screenSize.y = Vector2.Distance (Camera.main.ScreenToWorldPoint(new Vector2(0,0)),Camera.main.ScreenToWorldPoint(new Vector2(0, Screen.height))) * 0.5f;
//Change our scale and positions to match the edges of the screen...
rightCollider.localScale = new Vector3(colDepth, screenSize.y * 2, colDepth);
rightCollider.position = new Vector3(cameraPos.x + screenSize.x + (rightCollider.localScale.x * 0.5f), cameraPos.y, zPosition);
leftCollider.localScale = new Vector3(colDepth, screenSize.y * 2, colDepth);
leftCollider.position = new Vector3(cameraPos.x - screenSize.x - (leftCollider.localScale.x * 0.5f), cameraPos.y, zPosition);
topCollider.localScale = new Vector3(screenSize.x * 2, colDepth, colDepth);
topCollider.position = new Vector3(cameraPos.x, cameraPos.y + screenSize.y + (topCollider.localScale.y * 0.5f), zPosition);
bottomCollider.localScale = new Vector3(screenSize.x * 2, colDepth, colDepth);
bottomCollider.position = new Vector3(cameraPos.x, cameraPos.y - screenSize.y - (bottomCollider.localScale.y * 0.5f), zPosition);
}
}
}
The ball collides with the paddles and bounces off as it should as well as collides with the surrounding box colliders and bounces off perfectly. However, the paddles move right through the surrounding box colliders (EdgeColliders). Please note that I use Touchscript package from the unity asset store to control movement. It does not move the Rigidbody it uses transform. Another thing to note is that when I make the paddles very light (0.0001 mass) and add gravity to them, they do collide with the edge colliders and don't go through the screen.
If you want the paddle to collide with the surrounding box, you should move the Rigidbody with AddForce(), not move the transform.
Or you can limit the movement of the paddles like this :
if (transform.position.x < LeftScreenEdge)
{
transform.position = new Vector3(LeftScreenEdge, transform.position.y);
}
Delete Rigidbody2D attached to paddles.
Get the mouse pos int world coordinates:
Vector2 mP = Camera.main.ScreenToWorldPoint(Input.mousePosition);
And to prevent it from going out of boundaries just clamp It's position:
Vector3 screenBounds;
void Start()
{
screenBounds = Camera.main.ScreenToWorldPoint(new Vector3(Screen.width, Screen.height, Camera.main.transform.position.z));
}
void SetPaddlePos()
{
Vector2 clampedPos;
clampedPos.x = Mathf.Clamp(mP.x, screenBounds.x, -screenBounds.x);
clampedPos.y = Mathf.Clamp(mP.y, screenBounds.y, -screenBounds.y);
paddle.transform.position = clampedPos;
}
So i'm trying to change weapons for my 2d top down space shooter. by weapon I just mean my bullet prefab so it shoots a different bullet which I can then add damage to etc.
here is the code I have. when I press number 2 it shoots my prefab clone in the hierarchy but its greyed out and nothing shows up in the game view. Below is my playerShoot code.
public class playerShoot : MonoBehaviour {
public Vector3 bulletOffset = new Vector3 (0, 0.5f, 0);
float cooldownTimer = 0;
public float fireDelay = 0.25f;
public GameObject bulletPrefab;
int bulletLayer;
public int currentWeapon;
public Transform[] weapons;
void Start () {
}
void Update () {
if (Input.GetKeyDown(KeyCode.Alpha1)){
ChangeWeapon(0);
}
if (Input.GetKeyDown(KeyCode.Alpha2)){
ChangeWeapon(1);
}
cooldownTimer -= Time.deltaTime;
if (Input.GetButton("Fire1") && cooldownTimer <= 0){
cooldownTimer = fireDelay;
Vector3 offset = transform.rotation * bulletOffset;
GameObject bulletGO = (GameObject)Instantiate(bulletPrefab, transform.position + offset, transform.rotation);
bulletGO.layer =gameObject.layer;
}
}
public void ChangeWeapon(int num){
currentWeapon = num;
for (int i = 0; i < weapons.Length; i++){
if (i ==num)
weapons[i].gameObject.SetActive(true);
else
weapons[i].gameObject.SetActive(false);
}
}
}
Keeping the rest of the code same, just change the following line
GameObject bulletGO = (GameObject)Instantiate(bulletPrefab, transform.position + offset, transform.rotation);
to
GameObject bulletGO = (GameObject)Instantiate(weapons[currentWeapon].gameObject, transform.position + offset, transform.rotation);
What the change does is use the transforms for the weapons in your weapon array, rather than using the bulletPrefab.
The problem occured because you were Instantiating a single prefab, which was the same as the Transform you used for the first element in your weapons array. So, when you call ChangeWeapon(1), the prefab would get deactivated. This reulted in inactive GameObjects being instantiated.
What I would suggest you do is to have two separate prefabs and spawn those accordingly.
i want a gameObject to add instanciatetd objects prom a prefab as his chiled.
so i wrote this code:
public class TgtGenerator : MonoBehaviour {
public SpriteRenderer spriteTgt;
public Sprite[] targets;public SpriteRenderer spriteTgt;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
generateRandTgt ();
}
void generateRandTgt(){
SpriteRenderer tgt = GameObject.Instantiate (spriteTgt, getRandPosition (), Quaternion.identity)as SpriteRenderer;
tgt.sprite = randSprite ();
}
Sprite randSprite(){
var length = targets.Length-1;
Debug.Log (Random.Range(0,length));
return targets[Random.Range(0,length)];
}
Vector3 getRandPosition(){
float xScale = gameObject.transform.localScale.x / 2;
float yScale = gameObject.transform.localScale.y / 2;
float x = Random.Range(-xScale,xScale);
float y = Random.Range(-yScale,yScale);
float z = 0;
return new Vector3 (x, y, z);
}
the instantiated object is getting his size from the prefab like i wanted to.
but the problem is it instanciated at the root node of the hirarchy so they are not placed inside of the gameobject coordinate like i wanted to.
when i am adding this line of code just after the instaciate line :
tgt.transform.parent = gameObject.transform;
it generated as a child like i wanted to but it gets huge and upside down.
how should i manage this?
Try Using This To Force Child To Have It's Own Scale After Being a Child:
var localScale = child.transform.localScale; // store original localScale value
child.transform.parent = parent;
child.transform.localScale = localScale; // force set