How to load prefab properly - c#

I want to instantiate a Prefab by it's name (and path), which comes from my server, from my Assets folder and came across some issues.
I found multiple ways of doing this:
var prefab = Instantiate(Resources.Load("prefabName")) as GameObject;
This is suggested by most threads but as described here you should not use it.
var prefab = Instantiate(UnityEditor.AssetDatabase.LoadAssetAtPath<GameObject>(path));
This is the second way I found but this will only work when working inside the Editor. Building the project to a WebGl for example will immidiatly throw a build error.
So what is the proper way to instantiate a prefab then?

Why not simply add a (serializable) field in your MonoBehaviour:
[SerializeField] private GameObject myPrefab;
or
public GameObject MyPrefab;
Drag your prefab in the inspector, then below in your code:
GameObject clone = Instantiate(myPrefab);
The difference with this approach is that your prefab is preloaded in memory, i.e. when you instantiate you read from memory (as opposed to disk).

Are you importing assets into your already built game? Or are you refering to assets that are already in your project?
Because if you want to import on runtime you could use AssetBundles. Unfortunately I can't really help you with that since I have no real experience on working with them, but I have read somewhere that many mobile devs use them to distribute their asset on game launch.
Maybe the Asset Bundle Manual helps you with that.
If you want to Instantiate prefabs that are already in your project you could use a Dictionary<string,GameObject>. Like that:
public Dictionary<string, GameObject> prefabDict = new Dictionary<string, GameObject>();
public void SpawnPrefabFromDict(string name)
{
Instantiate(prefabDict[name]);
}
The string as key then point to its value - your prefab!
Hope this helps!
Good Luck!

Related

Accessing namespace from another namespace. Is it an assembly issue? A Monobehavior issue? Syntax issue?

I'm trying to put an inventory management system (Devion Games from Unity's asset store) into the Ellen 3d Gamekit project (Also from Unity).
The problem I'm facing is releasing the mouse and camera movement when you open one of Devion's inventory or crafting menus). I can see where Devion pauses playerinput if using their 3rd person camera.
Devion...UIWidget.cs:
if (m_CameraController != null)
{
this.m_CameraTransform.SendMessage("Activate", this.m_CameraPreset, SendMessageOptions.DontRequireReceiver);
}else {
//Show Cursor without ThridPersonCamera
this.m_PreviousLockMode = Cursor.lockState;
Cursor.lockState = CursorLockMode.None;
Cursor.visible = true;
// MY CODE trying to use Gamekit3D's PlayerInput's GainControl()
//m_Player.GetComponent("PlayerInput");
}
But of course the Ellen 3d Gamekit uses a Cinemachine.
I thought it would be as easy as adding a "using GameKit3D" to the above code, then referencing it exactly how the pause menu from GameKit3D does
GameKit3D...StartUI:
PlayerInput.Instance.GainControl();
However, in the all the Devion files, when I try to do "using Gamekit3D" I get "type or namespace not found".
I can put "using DevionGames" in the Gamekit3D scripts, but not the other way around.
As you can probably tell, I'm new to all this. Things I've tried:
Relocating all the Devion scripts out of the folder structure and into assets/scripts. This broke all kinds of references. But I was able to add "using Gamekit3D", but there were so many problems I couldn't get the game to load.
I tried renaming the Devion namespace to the Gamekit3D and that also created too many errors for me to figure out.
I've messed around a little with assembly definitions and references but honestly, it's way over my head and everything I tried immediately broke references to other things.
I tried as many kind of references as I could. When I debugged, I could see the class I wanted to use in the place I wanted to use it, but I could not figure out how to getcomponent or FindGameObjectWithTag
Here's a picture of debuging where loading the Devion menu releases mouse control and you can see the PlayerInput which has public voids "ReleaseControl()" & "GainControl()" that I want to use:
debug showing what I want to access where I want to access it
One more thing I've explored and may be playing in here is that most of the scripts related to Devion's menues are not Monobehaviour and the Gamekit3D scripts, PlayerInput most notably, is a Monobehaviour and I've played around with switching those up, or accessing the Gamekit3D gameobject as Monobehaviour.
EDIT to add structure:
The reason I think it might be related to an assembly is how I can access one namespace from the other, but not vice versa:
My project structure is as follows:
Gamekit3D (all the scripts in this folder structure can add "using devion")
-- prefabs, scripts and such
Devion (all the scripts in this folder structure canNOT add "using Gamekit3D")
-- prefabs, scripts and such
Scripts (all the scripts in this folder structure can add both "using devion" & "using Gamekit3D")
here is a look at the solution view:
a look at the solution exploreer
I am quite stuck with this and any help is appreciated!

What do people mean when they talk about serialization in Unity?

I hear people talking about serializing variables among things in their unity projects and quite don't understand it. I see them using
[SerializeField]
and don't know why or what it does.
I looked up the definition of data serialization: Serialization is the process of converting the state information of an object into a form that can be stored or transmitted.
During serialization, objects write their current state to temporary or persistent storage. Later, the object can be recreated by reading or deserializing the state of the object from the store.
Objects are created as the program runs, and then reclaimed when unreachable, with a short lifespan. But what if we want to store the contents of the object permanently?
Convert it into a sequence of bytes and save it on a storage medium. Then serialization is required. [SerializeField] is to force Unity to serialize a private field. This is an internal Unity serialization function. Sometimes we need to Serialize a private or protected attribute. In this case, the [SerializeField] attribute can be used.
The above is some information I found, I hope it is correct and can bring you some help
Say, you have a field _speed and you want to set it using inspector. It means we want it to be serialized - stored somewhere in a human-readable and flexible format(e.g. xml), not directly in code. So when you edit fields in inspector, you edit the serialized data. During compilation, it's being deserialized and assigned to a field. This is how serialization/desearialization works. It is used to store non-static or just big amounts of data. In case of Unity it is used to show you everything in inspector. Transform has position and scale variables serialized and you can edit them.
In Unity there are two common ways to make fields assignable in inspector: using public fields or using [SerializedField] attribute for private ones.
Making fields public just to edit them with inspector is bad practice. If you can edit field in inspector, it means every other component can too, which is insecure. There is no good architecture that allows such things. If you want other components to edit the field, make it a property or make a set method. If you just need to assign fields by hand, don't use public fields. Avoid them.
When you use the [SerializeField] attribute, you create a private field that is accessible to this component only and you can assign it in inspector at the same time. If you need other components to read it, you can make a public property without set (public float Speed => _speed;).
This all is not an obligatory usage. Just good practice.
Any values set in the Unity inspector for any public fields or private/protected fields that use the attribute [SerializeField] are saved with the current scene file.
If you open up a Unity.scene file you will find a hierarchy of data that matches the scene hierarchy along with lists of what script or component classes are attached to that game object and what the field values of those classes/components should be.
When loading a level in Unity, the scene file is deserialized meaning that a program walks the data structure creating game objects. It then creates component and script class instances attached to those components and initializes them with the serialized data in the scene file. After that you end up with a level more or less the same as it was when saved in the unity editor.
In addition to your own Monobehaviour scripts having this ability, all the default unity components work this way. Transform uses serialized Vector3s for position, rotation and scale. MeshFilter components serialize a reference to a mesh asset and the MeshRenderer component references Materials that are used by the GPU to draw the mesh etc etc.
In short, serialisation is a process by which computers transform data so that it can be written to a file (or sent across a network via a protocol stream) and then later transformed back into the original set of objects it was to begin with (or as close as matters).

How to save a float between scenes in unity

Hi there I am very new to code and I'm really struggling. I'm just trying to create a simple bet system for a blackjack game, in which you place your bet and the value is saved then it gets carried into my next scene which would be the game scene. So basically I created a button in a scene called BetScene when the button is pressed it adds 25 to the betamount and removes 25 from the playeramount. Once the player is happy with the money they placed they press the second button PlaceBet. When that button gets pressed the game scene loads so what I want to do is save the amount that was placed and display it in the game scene. Hope this makes sense I really need help I'm really trying to learn thanks
Okay, so first: This scenario does not sound like you should use multiple scenes, so I would say "reconsider your architecture and scene flow in this case." But I am also here, to answer your question, so let's do that instead.
A great way of sharing data between scenes is using a ScriptableObject as a data container. You simply create the class of the data you want to use in multiple scenes and then create an instance of your ScriptableObject as an asset in your Assets-folder.
This asset can then be assigned to all components that need to use it for data transfer. It is basically like a texture that is painted on in one scene and read from in another scene.
You can even improve on this by creating a kind of "data binding" using these ScriptableObject assets as variables. There is a great talk about that topic from 2017 on Unitys YouTube channel: Unite Austin 2017 - Game Architecture with Scriptable Objects
Solution 1: Using PlayerPrefs.
PlayerPrefs.SetFloat("HIGHSCORE", 123.45f);
float highscore = PlayerPrefs.GetFloat("HIGHSCORE");
Solution 2: Using Static Instance
public class MyClass: MonoBehavior {
public static MyClass Instance;
public float highscore;
void Awake() {
Instance = this;
DontDestroyOnLoad(this);
}
}
...
public class YourClass: MonoBehavior {
void YourFunction() {
print(MyClass.Instance.highscore);
}
}

TrailRenderer.colorGradient "Print current specs in order to replicate in code"

After reading the API info here:
https://docs.unity3d.com/ScriptReference/TrailRenderer-colorGradient.html
I am wondering if I can "tune in" my trail renderer in the normal unity interface, print those complicated code parameters, then use that code in my script to change color on triggers, etc.
To clarify, how do I get the information here presented in code:
[]
I guess I am approaching this from a CSS background. Is there a Unity colorgradient version of this website:
https://www.colorzilla.com/gradient-editor/
Can I make the script print the characteristics of the trail renderer (for the purpose of replicating it elsewhere in my code)?
1
Much appreciate the help!
I'm still not 100% sure if I understood the question but I'll give it a shot.
As I understand you want to have a component on every trigger object where you can define different gradient settings for each.
And I assume by Unity interface you mean the Inspector.
So something like e.g.
public class GradientSetter : MonoBehaviour
{
public GradientColorKey[] colorKeys;
public GradientAlphaKey[] alphaKeys;
}
Put this on the trigger object(s) and adjust the settings via the Inspector. At beginning they should be empty arrays so to add elements just enter the wanted element count in the size property of both arrays.
And wherever you have the Collision implemented on your TrailRenderer object
void OnTriggerEnter(Collider other)
{
var gradientSetter = other.GetComponent<GradientSetter>();
if(!gradientSetter) return;
gradient.SetKeys(gradientSetter.colorKeys, gradientSetter.alphaKeys);
...
}
I'm assuming GradientColorKey and GradientAlphaKey are Serializable. If you implement this but they don't show up in the Inspector let me know, then you'll have to make a wrapper class for them. (I can't test it right now)
Note: Typed on smartphone so no warranty but I hope the idea gets clear

Unity Stitching meshes together

I've been thinking on this for a few days and have tried a few different things and have googled quite a bit. Iv specifically looked at this thread alot
http://forum.unity3d.com/threads/stitch-multiple-body-parts-into-one-character.16485/
But im confused, and not sure if this 100% what i wanted.
Im just trying to add a new mesh to an already existing gameobject with its own mesh. That runs off the same bone structure or animator, the object being added has the required bones of the position its being pasted at.
https://gyazo.com/19778b3c73ef9a749c8cc338f7e49d79
Thats the object im trying to add onto my player. I tried taking the mesh directly off of it and then linking it to the same bone structure as the player being animated
When the object is created and imported with fuse/mixamo it adds the object as separate mesh objects on a parent player
https://gyazo.com/55ce7442dc186756da4ff149ac3543e5
So if i was to disable the armor mesh id be left with this
https://gyazo.com/09ffd7c7721f46e6980f895a1a873749
But i tried importing my character without the armor on it. Then i opened the character with the player and armor in blender and deleted the player and left the bone structure and the armor and then saved that as a separate fbx and imported that into unity and am pasting the new armor fbx on the original player in an attempt for it too animate the same was it originally was from the mixmo object. But it doesnt, cant even get it to import in Tpose. And when i configure it myself it wont save the configuration and just keeps going back to where it was.
I suppose i should.... only have the bones required on the armor. Then do some type of game logic to figure out what bones are the same name on the armor object as is being added to the player and replacing the player bones with the bone of the armor? But i feel like if i wanted to do it this way, then i need the player split into pieces so that it knows what parts to replace of the player. Or is there a way i can keep the player together and just make the armor follow the bones of the player, i guess would be the easiest thing to do
Im pretty sure the link i posted is pretty much waht i want. I guess i just dont understand it fully and wanted someone to help me better understand it
Ok so, this post is not going to be explaining how the code works but how to get the code TOOOOO work. Masterprompt explains the code well enough here. If you want to understand how the code works follow that link.
Anyways, onto what to do to go about merging 2 objects together to make one object that runs off the animation of the base object.
Example uses could be
Creating a person limb from limb.
Add armor too a base player
The meat and bones of how i get this too work without having a graphic artist to create my assets for me is using fuse and mixamo. I highly suggest these programs. You can still easily get this too work without those programs, but i will be explaining how to do it as if you are using it.
Ok so, download Adobe fuse and create your base player. (preferably naked)
Now save that player as whatever you would like (I used Main_Player_Naked)
Upload this player to mixamo for auto rigging, after downloading the model from mixamo import him into unity. (At this point im assuming you know how to set the model up as a humanoid in unity)
Now that your player is created and imported into unity go ahead and animate him or do whatever you want with him. Whatever you do to him will work fine with the new armor/hair/beard whatever you are adding to your player.
Ok, now time to create the armor we are going to add. Go ahead and reopen your naked player in fuse and recreate him with the new asset you want him to have (Dont change any body shape sizes, just add the new object). (Don't worry we're not switching the whole model out, this is just so we don't have to rig the new asset by ourselves) Now that you have the new asset looking nice, go ahead and follow the first steps of creating the naked played. So save your newly created character and import to mixamo for auto-rigging. Now download and import the new player into unity. Delete all the objects off the player except the new asset (Which is on a separate mesh that the naked player that's under the object)
Now we are going to use the code from Masterprompts post
I've rewritten it, so here's my new code
using UnityEngine;
using System.Collections;
public class CreatePlayer : MonoBehaviour
{
public GameObject objPlayer;
public GameObject objLimb;
public GameObject objAdded;
// Use this for initialization
void Start()
{
}
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.H))
AddLimb(objLimb, objPlayer);
if (Input.GetKeyDown(KeyCode.J))
Destroy(objAdded);
}
//
void AddLimb(GameObject BonedObj, GameObject RootObj)
{
var BonedObjects = BonedObj.gameObject.GetComponentsInChildren<SkinnedMeshRenderer>();
foreach (SkinnedMeshRenderer SkinnedRenderer in BonedObjects)
{
ProcessBonedObject(SkinnedRenderer, RootObj);
}
}
private void ProcessBonedObject(SkinnedMeshRenderer ThisRenderer, GameObject RootObj)
{
/* Create the SubObject */
var NewObj = new GameObject(ThisRenderer.gameObject.name);
NewObj.transform.parent = RootObj.transform;
/* Add the renderer */
NewObj.AddComponent<SkinnedMeshRenderer>();
var NewRenderer = NewObj.GetComponent<SkinnedMeshRenderer>();
/* Assemble Bone Structure */
var MyBones = new Transform[ThisRenderer.bones.Length];
for (var i = 0; i < ThisRenderer.bones.Length; i++)
MyBones[i] = FindChildByName(ThisRenderer.bones[i].name, RootObj.transform);
/* Assemble Renderer */
NewRenderer.bones = MyBones;
NewRenderer.sharedMesh = ThisRenderer.sharedMesh;
NewRenderer.materials = ThisRenderer.materials;
objAdded = NewObj;
}
private Transform FindChildByName(string ThisName,Transform ThisGObj)
{
Transform ReturnObj;
if( ThisGObj.name==ThisName )
return ThisGObj.transform;
foreach (Transform child in ThisGObj)
{
ReturnObj = FindChildByName( ThisName, child );
if( ReturnObj )
return ReturnObj;
}
return null;
}
}
This was very quickly thrown together. I suggest making it nicer.
But just add the naked player too objPlayer and the asset to add to objLimb.
Run your game and pushing 'H' creates the asset and 'J' deletes it.

Categories