Cant instantiate multi-sprite - unity3d

I can't seem to load a sprite runtime.
I have a main grid object, on the grid I have a TerrainDrawer component.
The code for the script :
void Start()
{
Sprite[] myFruit = Resources.LoadAll<Sprite>("Sprites/multisprite");
foreach(var sprite in myFruit)
{
print("sprite : " + sprite.name);
}
/*var spritePath = "Sprites/225835_hyptosis_tile-art-batch-1";
//GameObject go = new GameObject();*/
SpriteRenderer renderer = gameObject.AddComponent<SpriteRenderer>();
renderer.sprite = myFruit[0];
//renderer.sprite = Resources.Load(spritePath , typeof(Sprite)) as Sprite;
}
The sprite that I'm wanting to use:
When I start up my game, I get this error :
IndexOutOfRangeException: Index was outside the bounds of the array.
TerrainDrawer.Start () (at Assets/Scripts/TerrainDrawer.cs:21)
I have a strong feeling that my problem is with the path to the sprite, but now matter what I try, I can't get it loaded up.
Any advice?

To load from Resources in code there must exist a folder named Resources with that sprite in it. You are basically loading in an empty array and that is why you get an out of range error.
Take a look at this page from the docs.
Hope this helps!

Related

Can't instantiate "scene object" [Unity Mirror Multiplayer]

I am trying to instantiate an object that already exists in the scene so that I can enlarge it and "zoom" in on it, but when I play the game and hover over an object, instead of showing the zoomed card, this error shows up:
Card1(Clone)(Clone) has already spawned. Don't call Instantiate for NetworkIdentities that were in the scene since the beginning (aka scene objects). Otherwise the client won't know which object to use for a SpawnSceneObject message.
NOTE: I am following a tutorial for a 2D Unity Card game with mirror (2019.2.15f1), and I am using a different version of Unity (2020.1.0f1).
First, I am instantiating objects into my game with this script, which never throws any errors.
[Command]
public void CmdDealCards()
{
for (int i = 0; i < 4; i++)
{
GameObject card = Instantiate(playerDeck[Random.Range(0, playerDeck.Count)], new Vector2(0, 0), Quaternion.identity);
NetworkServer.Spawn(card, connectionToClient);
RpcShowCard(card, "Dealt");
}
}
The problem comes when I try to instantiate these objects again later, here:
public void OnHoverEnter()
{
zoomCard = Instantiate(gameObject, new Vector2(Input.mousePosition.x, 540), Quaternion.identity);
zoomCard.transform.SetParent(Canvas.transform, true);
zoomCard.layer = LayerMask.NameToLayer("Zoom");
RectTransform rect = zoomCard.GetComponent<RectTransform>();
rect.sizeDelta = new Vector2(240, 354);
}
I know this is a really late answer, but I came across it while running into the same issue, and maybe in the future, someone will do the same as me, so:
What you've done is attached the wrong prefab to your CardZoom script in the Inspector.
Image of Inspector with Zoom Card attached
What I did, and presumably you also, was to attach Card1 here, which is where it was failing to duplicate the NetworkIdentity

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.

Unity: GameObject always at center regardless of position changes

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");
}
}

Scripting GUI buttons to trigger an event of changing materials

Apologies if there's a similar question, however, I have probably seen it and it has not fixed my problem.
I am trying to write a JS script for unity in order to achieve an event to be triggered once clicked.
I have searched online on UnityAnswers website and others, the closest I can get is based on these questions
http://answers.unity3d.com/questions/368303/changing-shaders-of-a-gameobject-via-script-1.html
and this one
http://answers.unity3d.com/questions/319875/change-objects-material-using-gui-buttons-via-scri.html
and also looked at this one
http://docs.unity3d.com/ScriptReference/Material-shader.html
So, my code is this so far
var button2_tex : Texture;
var button3_tex : Texture;
var button4_tex : Texture;
var seat_mat1 : Material;
var seat_mat2 : Material;
var veneer1 : Texture;
var veneer2 : Texture;
var rend : Renderer;
var _mouseDown = false;
function Start() {
seat_mat1 = Resources.Load( "seat_mat1" );
seat_mat2 = Resources.Load( "seat_mat2" );
}
function Update(){
if(Input.GetMouseButtonDown(0)){
_mouseDown = true;
}
}
function OnGUI() {
GUI.Box (Rect (10,10,100,200), "Menu");
if (_mouseDown){
if (GUI.Button (Rect (20,40,40,20), button1_tex)){
if(seat_mat1){
rend.material = seat_mat2;
Debug.Log("This button was clicked!");
}
else{
rend.material = seat_mat1;
}
}
}
Please note some variables I haven't used yet, as am still testing bunch of other codes to get it working..
the code snippet I am trying to fix starts with "function OnGUI()" but I maybe wrong and could use some fresh insight.
this is a screenshot of the resulting script. The button on the left side is supposedly to change the colour of the material from seat_mat1 to seat_mat2 by the event of mouse clicking on the button.
I have attached the previous script to the 3D object in unity and had made a folder names "Resources" for the materials to be visible and referenced through the script.
My problem is that upon clicking the GUI button, nothing happens, and it maybe something very simple and I am just missing it .. apologies for being inexperienced in JS much or unity.
Thanks in advance.
EDIT:
So after playing a bit more with the code. I added a Debug.Log() after this line
GetComponent.<Renderer>().material = seat_mat2;
Debug.Log("This button was clicked!");
and seems to be this error that I am getting every time the button is pressed
"MissingComponentException: There is no 'Renderer' attached to the "scene_export3" game object, but a script is trying to access it.
You probably need to add a Renderer to the game object "scene_export3". Or your script needs to check if the component is attached before using it.
materialChanger.OnGUI () (at Assets/materialChanger.js:44)"
So with simple understanding, it seems that the renderer is not attached somehow?
Your code is working fine But still i think once you have loaded The materials in start function you do not need to load them every time. And one thing more is to make sure you have applied the script to the gameobject you want to change the material of. If you just want to change the color not want to change complete material use color property of material and your OnGUI function should look like this.
function OnGUI() {
GUI.Box (Rect (10,10,100,200), "Menu");
if (_mouseDown){
if (GUI.Button (Rect (20,40,40,20), button1_tex)){
if(GetComponent.<Renderer>().material == seat_mat1)
GetComponent.<Renderer>().material.color = seat_mat2.color;
else
GetComponent.<Renderer>().material.color = seat_mat1.color;
}
}
}
But if you do not use color poperty it will work fine just make sure you have applied script to game boject you want to change material i your case may be to your seat1.
Thanks Nain for your guidance, with your help I was able to come up with a partial solution, where I know I can fix from there.
The solution is as follows.
The code:
function OnGUI() {
GUI.Box (Rect (10,10,100,200), "Menu");
if (_mouseDown){
if (GUI.Button (Rect (20,40,40,20), button1_tex)){
var rendArray : Renderer[];
rendArray = GetComponentsInChildren.<Renderer>(true);
for(var rend : Renderer in rendArray){
if(rend.sharedMaterial == seat_mat1){
rend.sharedMaterial = seat_mat2;
Debug.Log("This button was clicked!");
}
else{
rend.sharedMaterial = seat_mat1;
}
}
}
}
}
After saving the script in MonoDevelop, open Unity where you create an empty game object and add all the objects with specific material e.g. seat_mat1 under it as children.
Then click on the empty object, rename it if you like, and add a "Mesh Renderer" component from "Add Component > Mesh > Mesh Renderer".
After that drag the script to the empty object and in the inspector you can find an option which you can choose a renderer called "rend". Choose the empty object as the Mesh Renderer.
Upon testing the outcome, I have managed to change materials of some objects together to seat_mat2, but unrelated materials changed themselves to seat_mat1 and once the button is clicked again, they alternate between seat_mat1 and seat_mat2
and even though it is not perfectly done, I am answering this question as anything else is fixable (I hope).
Thank you again Nain for your help :)

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.