Unity: GameObject always at center regardless of position changes - unity3d

I am working on a 2D game and have created a game object using C# script as below. I also set my camera to orthogonal and have adjusted my sprite based on the width of the screen. Regardless of the position I set, the object is always at the center of the screen. How can I solve this?
using UnityEngine;
using System.Collections;
public class TestingPositions : MonoBehaviour {
GameObject hero;
Sprite heroSprite;
Vector3 heroPosition;
// Use this for initialization
void Start () {
hero = new GameObject ();
Instantiate (hero, heroPosition, Quaternion.identity);
Camera camera = GameObject.FindGameObjectWithTag ("MainCamera").GetComponent<Camera> ();
heroPosition = camera.ScreenToWorldPoint(new Vector3(Screen.width/4, Screen.height/4, camera.nearClipPlane));
heroSprite = Resources.Load <Sprite> ("Sprites/heroImage");
SpriteRenderer renderer = hero.AddComponent<SpriteRenderer>(); renderer.sprite = heroSprite;
}
}

when you use Instantiate you have to use it on
an existing model.
Instantiate means "duplicate this model" or "copy this model", or "make a new one, using this model as an example".
What you are doing, is creating a brand new empty "hero" game object - and then "instantiating" it. That is meaningless and does nothing.
What you must do whenever you want to use "Instantiate" is this:
public GameObject modelPerson;
Note that the name must be "modelSomething".
first put that in your code. LOOK at the Inspector. MAKE your actual model hero (or whatever it is)
Sit it somewhere off camera where it is not seen.
Now, drag that thing to the "modelPerson" slot in the Inspector.
If you are not familiar with the basics of using Inspector-dragging in Unity, review basic Unity tutorials https://unity3d.com/learn/tutorials/topics/scripting
Next in your code, perhaps in Start, try this
GameObject newHero = Instantiate( modelPerson );
newHero.transform.position = .. whatever you want
newHero.transform.rotation = .. whatever you want
newHero.name = "Dynamically created";
newHero.transform.parent = .. whatever you want
once you understand these basics, there is very much more to learn about Instantiate. You can ask that in separate questions. Good luck.

Your need to save the reference to your gameObject that is created with Instantiate, because Instantiate makes a copy not modifies the original.
To modify a gameobjects position after instantiation, you need to use gameobject.transform.position = newPosition; To modify it before instantiation, you would need to do the "heroPosition" line before using heroPosition in Instantiate.
So like this:
using UnityEngine;
using System.Collections;
public class TestingPositions : MonoBehaviour
{
GameObject hero;
SpriteRenderer heroSprite;
// Use this for initialization
void Start()
{
Camera camera = GameObject.FindGameObjectWithTag("MainCamera").GetComponent<Camera>();
//Save the reference to the instantiated object into a variable
//Since you are creating an object from scratch, you don't even need Instantiate, which means copy - not create.
hero = new GameObject();
//Set its position
hero.transform.position = camera.ScreenToWorldPoint(new Vector3(Screen.width / 4, Screen.height / 4, camera.nearClipPlane));
//Set its rotation
hero.transform.rotation = Quaternion.identity;
//Add sprite renderer, save the reference
heroSprite = hero.AddComponent<SpriteRenderer>();
//Assign the sprite
heroSprite.sprite = Resources.Load<Sprite>("Sprites/heroImage");
}
}

Related

Is there a way to make an instantiated text follow a game object?

I'm currently experiencing a coder's block right now as I'm trying to instantiate text on a game object, specifically a Zombie prefab. I've gotten down the enemy's position for the text to be spawned but can't seem to make it follow the zombie's movement as it walks towards the player.
This is my 'Word Spawner' script.
public GameObject wordpb; // my word prefab
public Transform canvas; // connected to a canvas ui that has world camera set
public EnemyOne enemy;
public DisplayWord Spawn()
{
Vector2 targetPos = new Vector2(enemy.transform.position.x, enemy.transform.position.y);
GameObject wordobj = Instantiate(wordpb, targetPos, Quaternion.identity, canvas);
DisplayWord displayWord = wordobj.GetComponent<DisplayWord>();
return displayWord;
}
and this is where the DisplayWord class is derived from.
public Text text;
public void SetWord(string word)
{
text.text = word;
}
public void ThrowLetter()
{
text.text = text.text.Remove(0, 1);
text.color = Color.red;
}
public void ThrowWord()
{
Destroy(gameObject);
}
My best guess is that I should be implementing a void Update method in which I use transform.Translate? Or should I put a placeholder that acts as a child class to my Zombie prefab and attach the DisplayWord script there? Please help a poor soul out.
How does the text relate to the Zombie game object? Knowing what the text is for in relation to the zombie might inform the best way to make it follow the game object.
If the text is something like a worldspace nametag, instead of translating in Update you could make the text a child of the game object it needs to follow. It might not be the most elegant solution but if you give each text its own worldspace canvas you could assign the text as a child of the zombie, or, if you know you'll always have text following a zombie, you could just add a worldspace canvas and text to the zombie prefab...
To instantiate as a child you'd need to rework your word prefab to be its own worldspace canvas with your text as its child.
You can assign a parent when you instantiate:
wordobj = Instantiate(wordpb, enemy);
Or set the parent after instantiation:
wordobj.transform.SetParent(enemy.gameObject.transform, true);
The second parameter in SetParent is 'worldPositionStays', and controls whether the child object keeps its world position (true) or whether it's transform is evaluated relative to its new parent's transform. You could make it work either way: if you leave it 'true' you don't need to change the rest of your code, but I think if you make it false you don't need to get the enemy GameObject's position... The same is true for Instantiate when a parent is assigned but no transform position/rotation. So I think you could skip the step of finding the enemy's position and rewrite your Spawn code to:
public GameObject wordpb; // my word prefab
public EnemyOne enemy;
public DisplayWord Spawn()
{
GameObject wordobj = Instantiate(wordpb, enemy, false);
DisplayWord displayWord = wordobj.GetComponent<DisplayWord>();
return displayWord;
}
You'd need to assign the newly instantiated canvas's worldspace camera to make this work...

Is there a way to specify where a game object spawns in the hierarchy in unity?

I have set up a random spawner that creates new game objects but they are being created outside of my canvas and therefore can't be seen when play the game. Is there any way to fix this? The objects 'neg thoughts' are UI Buttons and are being created outside of the canvas even though I need them to appear on screen so they can be used.
I did see a similar question but the suggestions didn't work for my problem.
this is very frustrating for me and any help would be awesome!
You can simply pass the parent into Instantiate
parent Parent that will be assigned to the new object
var newObj = Instantiate(prefab, parentTransform);
or with additional transforms
var newObj = Instantiate (prefab, position, rotation, parentTransform);
Or as others already said you can still do it afterwards at any time either by simply assigning a new transform.parent
newObj.transform.parent = parentTransform;
or using transform.SetParent
newObj.transform.SetParent(parentTransform, worldPositionStays);
The advantage of the later is that you have an optional parameter worldPositionStays
worldPositionStays If true, the parent-relative position, scale and rotation are modified such that the object keeps the same world space position, rotation and scale as before.
assigning a new
transform.parent = parentTransform;`
will always act the same way as
transform.SetParent(parentTransform);
since the default value for worldPositionStays (so if you don't explicitly pass it) is true.
So for the specific case of UI in a Canvas you could use
public TheSpawnComponent : MonoBehaviour
{
// Via the Inspector drag&drop any object here that is inside the canvas
// or the canvas itself
[SerializeField] private GameObject parentInCanvas;
[SerializeField] private Button buttonPrefab;
public void DoInstantiate()
{
var newButton = Instantiate (buttonPrefab, parentInCanvas);
//Todo Position and callback
}
}
Or if the spawner script is attached to an object inside the canvas anyway you could also spawn as child of this one directly using
var newButton = Instantiate(buttonPrefab, transform);
You can specify the transforms parent after you have created the game object.
spawnedObject.transform.parent = canvas.transform;
You have to use below code
public GameObject Prefab; // Object to Create
public Transform ParentOfObj;// Must Be inside the canvas or canvas it self
void Start()
{
GameObject g = Instantiate(Prefab) as GameObject;
g.transform.SetParent(ParentOfObj);
g.transform.localScale = Vector3.one;
}

GameObject (Prefab object ) created by script does not appear in Game View but appears in Scene View in Unity3d

I created a pin object by script attached it to a sphere object .
using UnityEngine;
public class InstantiateMarkerPin : MonoBehaviour
{
public float Xpos;
public float Ypos;
public float Zpos;
public GameObject gameObjectPinInstantiate;
// Start is called before the first frame update
private void Start()
{
Xpos = 0.09f;
Ypos = 0.50f;
Zpos = 1.1f;
//The original object, where to instantiate, and the orientation of the new object
GameObject marker = (GameObject)Resources.Load("gameObjectPin");
Vector3 location = new Vector3(Xpos, Ypos, Zpos);
Quaternion rotation = Quaternion.Euler(0, 0, 0);
//The object the script is attached to
GameObject world = this.gameObject;
//Instantiate the prefab
gameObjectPinInstantiate = Instantiate(marker, location, rotation, world.transform);
Debug.Log("InstantiateMarkerPin class : Marker Location 2 :X, Y, Z : " + gameObjectPinInstantiate.transform.position);
}
// Update is called once per frame
private void Update()
{
}
}
This script is attached to the sphere Object .My sphere Object have shader material of earth image (globe).
This Instantiated Prefabs (gameObjectPin) on sphere surface appears on scene but not on game screen ,When I select the camera object in the camera preview also this object does not appear .
Scene view
Scene View when camera is selected
I am new to Unity what should I check or correct to appear my created object on the sphere
basically I am trying to add pins to corresponding country and label it .Similar to the globe on this http://kitsdmcc.com/news
Gameobject is created when Play is clicked on the sphere object
When the Pin Object is selected on play mode
Oh now I see it! What you did was only setting its GIZMO via this menu
which is only displayed in the SceneView.
This has nothing to do with the rendering in the GameView but is just a way for easier seeing and finding certain types of objects in the SceneView since usually they would be invisible if not selected.
From the Glossary:
A graphic overlay associated with a GameObject
in a Scene
, and displayed in the Scene View
. Built-in scene
tools such as the move tool are Gizmos
, and you can create custom Gizmos using textures or scripting. Some Gizmos are only drawn when the GameObject is selected, while other Gizmos are drawn by the Editor regardless of which GameObjects
are selected.
As noted in the comments there is no Component at all on your GameObject so nothing is rendered in the Gameview.
Of course now you could enable Gizmos also for the GameView via the Gizmos toggle
but I guess what you rather are trying to achieve is rather rendering that icon in the final App.
You probably would like to use e.g. the SpriteRenderer component here. And simply drag in your Icon to the Sprite property.
You might have to change the Pin Texture's TextureType to Sprite (2D and UI).
In general I would also recommend to Create a Prefab instead of using the Resources folder here.
There are also some changes I would do to your code in general:
public class InstantiateMarkerPin : MonoBehaviour
{
[Header("Settings")]
// directly use a Vector3 for setting the values
// | default value for this field
// | (only valid until changed via Inspector!)
// v
public Vector3 TargetPosition = new Vector3(0.09f, 0.5f, 1.1f);
// Instead of using Resources simply reference the
// created Prefab here
public GameObject gameObjectPinPrefab;
[Header("Outputs")]
public GameObject gameObjectPinInstantiate;
private void Start()
{
// Careful this currently ovewrites any value set via the
// Inspector. Later you will probably want to remove this.
TargetPosition = new Vector3(0.09f, 0.5f, 1.1f);
//As said I would rather use a prefab here and simply reference it above in the field
//gameObjectPinPrefab = (GameObject)Resources.Load("gameObjectPin");
//Instantiate the prefab
gameObjectPinInstantiate = Instantiate(gameObjectPinPrefab, TargetPosition, Quaternion.identity, transform);
Debug.Log("InstantiateMarkerPin class : Marker Location 2 :X, Y, Z : " + gameObjectPinInstantiate.transform.position);
}
// Always remove empty Unity methods
// They are called as messages if they exist
// and only cause unnecessary overhead
}

How can I add a scriptable tile at runtime to a Unity Tilemap?

I'm trying to add one of my scriptable tiles to my Unity Tilemap during runtime. I can paint the tile in the editor and everything looks fine but I would like to add it during runtime.
I tried instantiating the ScriptableObject asset itself, but it does not have the correct sprites it needs that the generated tile asset has in the editor. Also, I don't believe I should be instantiating the ScriptableObject asset for each tile since one asset is meant to be shared for all of the same tiles on the map.
The Tilemap API provides a way to add a tile, but no instructions or example of how to create the tile.
This is kinda off the top of my head, but I was messing around with something similar yesterday, instantiating a tile on click.
Vector3Int tilePos = map.WorldToCell(mousePos);
YourTileClass tileInstance = ScriptableObject.CreateInstance<YourTileClass>();
Texture2D tex = Resources.Load<Texture2D>("tileTexture") as Texture2D;
Sprite sprite = new Sprite();
sprite = Sprite.Create(tex, new Rect(0, 0, 400, 400), new Vector2(0.5f, 0.5f));
Tile tile = Resources.Load<Tile>("tileInstance") as Tile;
tileInstance .sprite = sprite;
yourTileMap.SetTile(tilePos , tile);
I am not 100% if that is the best way to do it, but it worked for me. Let me know if that does not work and I will double check the actual file.
Sorry, I can't comment, but not knowing what you've tried so far, have you tried assigning the ruletile in the inspector and then just assigning it with SetTile at runtime whenever you need to? From the sounds of it this should achieve what you're trying to do
public Tilemap tilemap;
public MyRuleTile myRuleTile;
tilemap.SetTile(coordinate, myRuleTile);
Assuming your ScriptableObject is inheriting from TileBase object you can do the following:
public Tilemap tilemap;
public TileBase tileToDraw; //Object to draw at runtime
//Get tilemap position from the worldposition
Vector3Int tilemapReferencePosition = tilemap.WorldToCell(reference.transform.position);//this can be the position of another gameObject e.g your Player or MousePosition
roadTileMap.SetTile(tilemapReferencePosition, tileToDraw);
I recently used something similar for a Fire Emblem style RPG where I wanted to draw all the potential directions a spell can be cast before casting it and I ended up with the following function
public void DrawPreAttack(GameObject reference, Spell spell) {
Vector3Int gridReferencePos = preAttackTileMap.WorldToCell(reference.transform.position);
foreach (Vector2 direction in spell.validDirections) {
for (int i = 0; i <= spell.maxDistance; i++) {
preAttackTileMap.SetTile(new Vector3Int(gridReferencePos.x + (i * (int)direction.x) , gridReferencePos.y + (i * (int)direction.y) , 0), preAttackTile);
}
}
}
I have provided two small scripts for you that show you exactly how to do this:
1) The ScriptableObject
After placing this script in the Assets/??? folder, you can create new ScriptableObjects (or rather "ScriptableTiles") by right-clicking in the folder -> ScriptableObjects/ScriptableTile. After you have created such an asset, you have to "fill" it with what you want to have in it. In this case: a Tile. Just drag any Tile from your folder into the "m_Tile" slot that the ScriptableTile provides for you.
using UnityEngine;
using UnityEngine.Tilemaps;
[CreateAssetMenu(fileName = "NewScriptableTile", menuName = "ScriptableObjects/ScriptableTile")]
public class ScriptableTile : ScriptableObject
{
public Tile m_Tile;// Fill this with a Tile
public bool m_IsCollider;// This does nothing, it's just a showcase for what else could be stored in here
}
2) A simple "Placer"
Attach the "Placer" MonoBehaviour to a GameObject and give it a reference to a TileMap and your ScriptableTile. On Start() it will place the Tile in the middle of the chosen TileMap.
using UnityEngine;
using UnityEngine.Tilemaps;
public class ScriptableTilePlacer : MonoBehaviour
{
public Tilemap m_ExampleTileMap;
public ScriptableTile m_ExampleTile;
private void Start()
{
m_ExampleTileMap.SetTile(Vector3Int.zero, m_ExampleTile.m_Tile);
}
}
I've played around with creating TileMaps at runtime myself - you can get even more out of ScriptableTiles by adding more variables. For example, if you have a separate Collider TileMap, you could use a bool to mark certain Tiles as "IsCollider" or "IsNotCollider". Another idea would be to not store Tiles inside the ScriptableTile, but Sprites. This allows you to completely bypass the TilePalette - which is pretty much useless when it comes to runtime creation. Just write a short public Tile GetTileFromSprite() method inside the ScriptableTile. With a few lines of code you can create Tiles from Sprites and return them.

Set transform from another GameObject's script

I'm trying to make a script to set an object when is being instantiated. The problem is, I don't clearly know how to do it. I have this function..
function spawnPlayer()
{
var CameraScript = GameObject.Find(PlayerPrefab.name).GetComponent("Camera Control");
Network.Instantiate(PlayerPrefab, spawnObject.position, Quaternion.identity, 0);
}
Where PlayerPrefab is going to be the Prefab that's going to be instantiated. When this happens, I need to set the instantiated gameObject on another GameObject which is camera and has a script called "Camera Control" and inside there's a transform Target which I'm trying to set. How to do this?
The code you posted can't be right. You are using the PlayerPrefab's name to to find the Camera Control script attached to the camera? By that logic then the moment you instantiate PlayerPrefab, on the second line, you will have a second camera.
I think what you want to do is this: Instantiate the player prefab and make the camera point to the player.
So I am assuming the CameraControl script is created. You need the following before we start to code.
Attach CameraControl script to the camera in the scene.
Make sure the Player script is attached to the Player Prefab.
Have a third script that will instantiate the PlayerPrefab. I will call it Instantiator. Attach it to an empty GameObject in the scene, think of it as the world GameObject. We will call it World.
Make sure the Instantiator script is attached to the World GameObject and that it is pointing to the PlayerPrefab.
Code: Instantiator
The Instantiator script will spawn and create things we will use in the scene.
#pragma strict
var PlayerPrefab : GameObject;
function Start ()
{
// You can add position and rotation to the function call if you like.
var p = Instantiate(PlayerPrefab) as GameObject;
// Find the camera script and point to Player's transform.
Camera.main.GetComponent("CameraControl").SendMessage("setTarget", p.transform);
}
Notice I used the fact that the MainCamera in the scene is marked by Unity for you so it is easy to find.
Code: CameraControl
The CameraControl will have the logic to follow the Player as you see fit. Notice that target will point to what the camera will focus on. Of course following the Player around you will have to write.
var target : Transform;
function setTarget(t : Transform)
{
target = t;
}
I just taught myself a bit of JavaScript. I had never used it before.
I found my solution.
What I was meaning on my question was to set my camera's script the transform of the instantiated object.
I did not have to make many empty objects with scripts value of each object; it took me hours to find it because I did not know how unity handles the scripts objects calls.
This is how I made it:
var PlayerPrefab : GameObject;
var spawnObject : Transform;
private var MainCamera : GameObject;
function spawnPlayer()
{
var player = Instantiate(PlayerPrefab, spawnObject.position, Quaternion.identity);
MainCamera = GameObject.Find("MainCamera");
player.name = "Ball";
if(MainCamera)
{
MainCamera.GetComponent.<CameraControl>().target = player.transform;
Debug.Log("Succeed.");
}
}
Like this, my camera will have the transform properties of the new instantiated object automatically.