How do I convert Mesh to MeshFilter in unity - unity3d

Hi I am making a Generation Game In unity, and I have custom meshes and I wanted a function to convert Mesh to MeshFilters in the fastest way cause this function will get a input of a Array of Meshes and the output will be a Array of MeshFilters.
Thanks :)

This should be pretty streight forward.
In general you don't simply "create" MeshFilters. You rather attach them to a GameObject. There are bascially three ways to do so:
use AddComponent in order to attach it to an existing object
use Instantiate in order to create a clone instance of an existing prefab
use the constructor of GameObject and pass the according type(s) in as parameters
And well then just assign your Mesh to MeshFilter.sharedMesh or MeshFilter.mesh in this case where you assign the entire mesh it shouldn't really make a difference.
So you could e.g. simply do
// Needed for option B - see below
//[SerializeField] private MeshFilter preparedPrefab;
public MeshFilter[] CreateObjects(Mesh[] meshes)
{
var amount = meshes.Length;
var meshFilters = new MeshFilter[amount];
for(var i = 0; i < amount; i++)
{
// here you have multiple options
// A - create a new empty GameObjects with the MeshFilter component
meshFilters[i] = new GameObject("someName" /*, typeof(MeshRenderer), etc*/).AddComponent<MeshFilter>();
// B - Rather already prepare a prefab/template which contains all the components you need
// in particular you might also want a MeshRenderer in roder to see your objects
// and e.g. MeshCollider in order to apply physics and raycasting to your objects
//meshFilter[i] = Instantiate(prapredPrefab);
meshFilter[i].sharedMesh = meshes[i];
}
return meshFilters;
}
Note that a Mesh itself has no information about any position, rotation, scale and child-parent relationships in your scene. For this you would need more information.

Related

Unity3D How can I select multiple objects in 3D with a drag and select / lasso select?

I am struggling to find a good tutorial or informations that would allow me to select multiple objects in 3D in a user friendly manner.
So far, the best tutorial I found is this one : https://sharpcoderblog.com/blog/unity-3d-rts-style-unit-selection. The tutorial works by using the transform.position of the selectable objects and checking if it within the user's selection.
What I wish is to have the user be able to select a unit even if it is only partially within the user's selection such as most RTS games do ( both in 2D and 3D ).
One possibility would be to create a temporary mesh using the camera's clipping distances and the user's selection and then check for collisions but I was not able to find any tutorials using this method nor do I know if it is the best approach to the subject.
If I understand correctly you want to
somehow start a selection
collect every object that was "hit" during the collection
somehow end the collection
Couldn't you simply use raycasting? I will assume simple mouse input for now but you could basically port this to whatever input you have.
// Just a little helper class for an event in the Inspector you can add listeners to
[SerializeField]
public class SelectionEvent : UnityEvent<HashSet<GameObject>> { }
public class SelectionController : MonoBehaviour
{
// Adjust via the Inspector and select layers that shall be selectable
[SerializeField] private LayerMask includeLayers;
// Add your custom callbacks here either via code or the Inspector
public SelectionEvent OnSelectionChanged;
// Collects the current selection
private HashSet<GameObject> selection = new HashSet<GameObject>();
// Stores the current Coroutine controlling he selection process
private Coroutine selectionRoutine;
// If possible already reference via the Inspector
[SerializeField] private Camera _mainCamera;
// Otherwise get it once on runtime
private void Awake ()
{
if(!_mainCamera) _mainCamera = Camera.main;
}
// Depending on how exactly you want to start and stop the selection
private void Update()
{
if(Input.GetMouseButtonDown(0))
{
StartSelection();
}
if(Input.GetMouseButtonUp(0))
{
EndSelection();
}
}
public void StartSelection()
{
// if there is already a selection running you don't wanr to start another one
if(selectionRoutine != null) return;
selectionRoutine = StartCoroutine (SelectionRoutine ());
}
public void EndSelection()
{
// If there is no selection running then you can't end one
if(selectionRoutine == null) return;
StopCoroutine (selectionRoutine);
selectionRoutine = null;
// Inform all listeners about the new selection
OnSelectionChanged.Invoke(new HashSet<GameObject>(selection);
}
private IEnumerator SelectionRoutine()
{
// Start with an empty selection
selection.Clear();
// This is ok in a Coroutine as long as you yield somewhere within it
while(true)
{
// Get the ray shooting forward from the camera at the mouse position
// for other inputs simply replace this according to your needs
var ray = _mainCamera.ScreenPointToRay(Input.mousePosition);
// Check if you hit any object
if(Physics.Raycast(ray, out var hit, layerMask = includeLayers ))
{
// If so Add it once to your selection
if(!selection.Contains(hit.gameObject)) selection.Add(hit.gameObject);
}
// IMPORTANT: Tells Unity to "pause" here, render this frame
// and continue from here in the next frame
// (without this your app would freeze in an endless loop!)
yield return null;
}
}
}
Ofcourse you could do it directly in Update in this example but I wanted to provide it in a way where you can easily exchange the input method according to your needs ;)
From UX side you additionally might want to call a second event like OnSelectionPreviewUpdate or something like this every time you add a new object to the selection in order to be able to e.g. visualize the selection outcome.
I might have understood this wrong and it sounds like you rather wanted to get everything inside of a drawn shape.
This is slightly more complex but here would be my idea for that:
Have a dummy selection Rigidbody object that by default is disabled and does nothing
don't even have a renderer on it but a mesh filter and mesh collider
while you "draw" create a mesh based on the input
then use Rigidbody.SweepTestAll in order to check if you hit anything with it
Typed on smartphone but I hope the idea gets clear
I think I would try to create a PolygonCollider2D because it is quite simple comparing to creating a mesh. You can set its path (outline) by giving it 2D points like location of your pointer/mouse. Use the SetPath method for it. You can then use one of its methods to check if another point in space overlaps with that collider shape.
While the PolygonCollider2D interacts with 2D components you can still use its Collider2D.OverlapPoint method to check positions/bounds of your 3D objects after translating it to 2D space.
You can also use its CreateMesh method to create a mesh for drawing your selection area on the screen.
You can read more about the PolygonCollider2D here.
Hope it makes sens and hope it helps.

unity get child data

I am trying to create a procedural created dungeon in Unity.
I have it creating the dungeon, and have a script attached to each prefab that goes to make up the walls, floor etc. Each one of these is attached to a single parent, to make it easy to delete and rebuild the entire dungeon. The script contains details:
public class WallPrefab
{
public bool use;
private int roomId;
public WallTypes type; //enum = torch, switch, item etc
public WallDirections direction; //direction wall is facing
public GameObject myPrefab; //nested
}
The prefab also contains an empty game object used as a mount point for torches, switches etc.
myPrefab
prefab //prefab for the actual 3d object
wallmount //empty game object to store location and rotation details
....
My questions:
1. How do I get the wall type?
int childs = transform.childCount;
for (var i = childs - 1; i >= 0; i--)
{
c = transform.GetChild(i).gameObject;
Debug.Log("child:" + c.name);
//WallTypes g = c.GetComponentInChildren<WallPrefab>().type;
WallTypes g = c.transform.GetComponentInChildren<WallSettings>().type;
(Edited to insert working solution to this part of my problem!)
This code does not work, because Unity complains that:
ArgumentException: GetComponent requires that the requested component
'WallPrefab' derives from MonoBehaviour or Component or is an
interface.
How do I get the transform of the mount point?
I know how to get the location and rotation, once I get the mount point, but how do I actually get the mount point?
Question 1 seems pretty self explainatory.
Question 2 looks a bit more interessting.
If i understood you correctly, you have a script, that "creates" torches on specified mount points. Assuming those mount points are empty game objects and you dont want to add torches directly into the prefab (would be nice if we got a little bit more detail here on how exactly your dungeon+mount point is generated), i would add a script to the prefab, add a GameObject instance variable and use the inspector to drag the mount point onto the script. then i would use "gameobjectVariable.transform.position" to get the position.
something like:
public class prefabClassWithMountPoints{
GameObject mountpoint; //drag mount point from inspector
GameObject torchGameObject; //drag torch prefab here
public void createTorch(){
GameObject torchObject = Instantiate(torchGameObject, mountpoint.transform.position, Quaternion.identity);
//...
}
//rest of code
}
this is assuming the mount points are not randomly generated WITHIN the prefab.

Spawn sprites on action

I'm trying to make a Pinata GameObject, that when clicked bursts and gives a variable number of Gift GameObjects with various images and behaviors in them.
I'm also not sure what the unity vocabulary for this is so as to look this up in unity docs.
Can anyone please lend me a hand here? Thanks!
There are several ways to handle this.
The simple way is to use Object.Instantiate, Object Instantiation is the vocab you're after.
This will create a copy of a predefined Unity object, this can be a gameobject or any other object derived from UnityEngine.Object, check the docs for more info https://docs.unity3d.com/ScriptReference/Object.Instantiate.html.
In your case, your Pinata would have an array, or list, of prefabs. These prefabs are created by you with a certain behaviour and sprite for each one. When the Pinata bursts, you instantiate random prefabs at random positions surrounding the Pinata, up to you how to position these objects.
Something along these lines should do the trick:
class Pinata : Monobehaviour
{
public GameObject[] pickupPrefabs;
public int numberOfItemsToSpawn; //This can be random
//any other variables that influence spawning
//Other methods
public void Burst()
{
for(int i = 0; i < numberOfItemsToSpawn; i++)
{
//Length - 1 because the range is inclusive, may return
//the length of the array otherwise, and throw exceptions
int randomItem = Random.Range(0, pickupPrefabs.Length - 1);
GameObject pickup = (GameObject)Instantiate(pickupPrefabs[randomItem]);
pickup.transform.position = transform.position;
//the position can be randomised, you can also do other cool effects like apply an explosive force or something
}
}
}
Bare in mind, if you want the game to be consistent, then each behaviour prefab would have there own predefined sprite, this would not be randomised. The only thing randomised would be the spawning and positioning.
If you did want to randomise the sprites for the behaviours then you'd have to add this to the Pinata class:
public class Pinata : Monobehaviour
{
//An array of all possible sprites
public Sprite[] objectSprites;
public void Burst()
{
//the stuff I mentioned earlier
int randomSprite = Random.Range(0, objectSprites.Length - 1);
SpriteRenderer renderer = pickup.GetComponent<SpriteRenderer>();
//Set the sprite of the renderer to a random one
renderer.sprite = objectSprites[randomSprite];
float flip = Random.value;
//not essential, but can make it more random
if(flip > 0.5)
{
renderer.flipX = true;
}
}
}
You can use Unity random for all your random needs, https://docs.unity3d.com/ScriptReference/Random.html
Hopefully this'll lead you in the right direction.

How to find all Cube game Object in the scene?

I'm looking for a way to find all CubeGameObject in the scene. I'm trying to do this :
Cube[] ballsUp = FindObjectsOfType (typeof(Cube)) as Cube[];
But cube isn't a game object type apparently.
I think i need to use something related to PrimitiveType but can figure out what and how to use it...
Thanks
Your Cube is of primitive type. And Primitive type objects are not possible to find using FindObjectsOfType.
There are many ways to solve the above problem. The easiest is by using tags.
When you instantiate your cube object you can use tag "Cube".
GameObject cube = GameObject.CreatePrimitive(PrimitiveType.Cube);
cube.tag = "Cube";
Then you can get all the cube objects in scene with cube tags using
GameObject[] arrayofcubes = GameObject.FindGameObjectsWithTag("Cube");
This will give all the array of GameObject cubes in the scene.
FindObjectsOfType can be used to find gameobjects with attached classed and not primitive types.
Another way to proceed is finding all objects with MeshFilters and Searching for the Desired primitive name in the mesh filter arrays
string[] meshNames = new string[5] {"Cube", "Sphere", "Capsule", "Cylinder", "Plane"};
MeshFilter[] allMeshFilters = FindObjectsOfType(typeof(MeshFilter)) as MeshFilter[];
foreach(MeshFilter thisMeshFilter in allMeshFilters)
{
foreach(string primName in meshNames)
{
if (primName == thisMeshFilter.sharedMesh.name)
{
Debug.Log("Found a primitive of type: " + primName);
}
}
}
Geeting all the Object by their primitive type (C#)
You could try using a script. Let's say your GameObjects have a script MyScript, then you could FindObjectsofType GameObject and GetComponent Myscript.
Hope this helps. Although, I know it's not the answer you want, it's definitely an idea worth trying as a last resort :)
You could try this. If you are using the cube primitive of unity the mesh should be called "Cube" and while running "Cube Instance".
var gameOjects = GameObject.FindObjectsOfType<GameObject>();
foreach (var gameOject in gameOjects)
{
var meshFilter = gameOject.GetComponent<MeshFilter>();
if (meshFilter != null && meshFilter.mesh.name == "Cube Instance")
Debug.Log(gameOject.name);
}
tough this isn't very elegant or robust.
A more appropriate way would be to tag all cubes and get them by "FindGameObjectsWithTag"
Then recommended way from Unity of doing this is to create a tag and then use GameObject.FindGameObjectsWithTag to find all of them. GameObject.FindGameObjectsWithTag returns array of objects in this tag.
For example, create a tag called "cubeTags" then go to each cube and change the tag to cubeTags. When you want to find all the cubes, you can just do:
GameObject[] cubes = GameObject.FindGameObjectsWithTag ("cubeTags");
Cube[] ballsUp = new Cube[cubes.Length];
for(int i=0; i<cubes.Length; i++){
ballsUp = cubes[i].GetComponent<Cube>();
}

Move a particular sprite to a target position after clicking the button in unity 4.6

I have just started unity. I have 4 Images(sprites) aligned in a grid.
As soon as i touch the particular chocolate, its texture changes[I wrote a code for that]. There is a button on screen.After pressing the button, I want to move only those chocolates whose texture has been changed.
I know the following move code but i don't know how to use it here.
void Update () {
float step=speed*Time.deltaTime;
transform.position=Vector3.MoveTowards(transform.position,target.position,step);
}
I just don't know to move that particular sprite whose texture is changed. Thanks
Do you want to be moving the sprites over the course of a duration or instantly?
If it's over the course of a duration I suggest you use Lerp. You can Lerp between two Vector.3's in a time scale. Much cleaner and once learned a very useful function.
Code examples below:
http://docs.unity3d.com/ScriptReference/Vector3.Lerp.html
http://www.blueraja.com/blog/404/how-to-use-unity-3ds-linear-interpolation-vector3-lerp-correctly
However if you want to move it instantly. This can be done very easily using the built in localPosition properties which you can set in or outside the object.
Set your changed sprites Bool moved property (create this) to true on click (if you're using Unity 4.6 UI canvas then look at the IClick interfaces available for registering mouse activity in canvas elements) and then when you press the button, loop through a list in a handler file which contains all your button texture objects and move those that the moved property is set to true for.
foreach(GameObject chocolate in chocolateList)
{
if (chocolate.moved == true)
{
gameObject.transform.localPosition.x = Insert your new x position.
gameObject.transform.localPosition.y = Insert your new y position.
}
}
However please do clarify your intentions so I can help further.
EDIT 1:
I highly suggest you make your sprites an object in the canvas for absolute work clarity. This makes a lot of sense as your canvas can handle these type of things much better. Use Image and assign your image the sprite object (your chocolate piece), define it's width and height and add a script to it called "ChocolatePiece", in this script create two public variables, bool moved and int ID, nothing else is required from this script. Save this new object as your new prefab.
Once you've done this in a handler script attached to an empty gameobject in your canvas make a list of gameobjects:
List<GameObject> chocolatePieces = new List<GameObject>();
You'll want to at the top of your handler script define GameObject chocolatePiece and attach in your inspector the prefab we defined earlier. Then in Start(), loop the size of how many chocolate pieces you want, for your example lets use 4. Instantiate 4 of the prefabs you defined earlier as gameobjects and for each define their properties just like this:
Example variables:
int x = -200;
int y = 200;
int amountToMoveInX = 200;
int amountToMoveInY = 100;
Example instantiation code:
GameObject newPiece = (GameObject)Instantiate(chocolatePiece);
chocolatePieces.Add(newPiece);
newPiece.GetComponent<ChocolatePiece>().ID = i;
newPiece.transform.SetParent(gameObject.transform, false);
newPiece.name = ("ChocolatePiece" + i);
newPiece.GetComponent<RectTransform>().localPosition = new Vector3(x, y, 0);
From this point add to your positions (x by amountToMoveInX and y by amountToMoveInY) for the next loop count;
(For the transform.position, each count of your loop add an amount on to a default x and default y value (the position of your first piece most likely))
Now because you have all your gameobjects in a list with their properties properly set you can then access these gameobjects through your handler script.