I am working on a project where I have a script that combines all the meshes of a gameobjects childs into one mesh while in edit mode. Now the problem is that even though I have managed to then save the mesh into my assets folder it is only saved as a default asset(blank white icon) and not as a mesh that I can then use for other things. Now I would like to know how to get it saved as a mesh asset. I think I could either somehow convert the default asset file to a mesh asset if that is possible, or I could directly save an objects mesh into the asset folder but I dont know if that's possible.
I would be very grateful if you could share code that I could use to do this(it doesnt have to be fance, it should just work).
Here is the code that I have currently:
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
[ExecuteInEditMode]
[RequireComponent(typeof(MeshFilter))]
[RequireComponent(typeof(MeshRenderer))]
// Copy meshes from children into the parent's Mesh.
// CombineInstance stores the list of meshes. These are combined
// and assigned to the attached Mesh.
public class CombineMeshes : EditorWindow
{
[Header("References")]
public GameObject generateFromObject;
[MenuItem("Window/My/MeshGenerator")]
static void Init()
{
CombineMeshes window = (CombineMeshes)GetWindow(typeof(CombineMeshes));
}
private void OnGUI()
{
generateFromObject = (GameObject)EditorGUILayout.ObjectField(generateFromObject, typeof(GameObject), true);
if (GUILayout.Button("Generate"))
{
Generate();
}
}
void Generate()
{
MeshFilter[] meshFilters = generateFromObject.GetComponentsInChildren<MeshFilter>();
CombineInstance[] combine = new CombineInstance[meshFilters.Length];
int i = 0;
while (i < meshFilters.Length)
{
combine[i].mesh = meshFilters[i].sharedMesh;
combine[i].transform = meshFilters[i].transform.localToWorldMatrix;
i++;
}
generateFromObject.transform.GetComponent<MeshFilter>().mesh = new Mesh();
generateFromObject.transform.GetComponent<MeshFilter>().mesh.CombineMeshes(combine);
generateFromObject.transform.gameObject.SetActive(true);
Mesh mesh = generateFromObject.transform.GetComponent<MeshFilter>().mesh;
AssetDatabase.CreateAsset(mesh, "Assets/myAsset");
AssetDatabase.ImportAsset(AssetDatabase.GetAssetPath(mesh));
AssetDatabase.SaveAssets();
}
}
Related
I wanted to make a simple mod support script but it got tedious very fast. The goal is that people can make prefabs and the put them into the game to give that mod idea. To specify my problem I want to make a script that (on the exported Windows version) checks if there is a mods folder in the resources folder if that exists it will check for prefabs in the mods folder if there are it will make a ui button pop up in the scene with the name of the prefab then when you click it, it spawns the prefab at 0,0,0.
For anyone wanting a picture with how that would have looked here is the game it would have been a sort of spawn menu with mods showing up as the buttons like the pictures of the game.
So I made the script below but it just never worked, like it did find the mod folder but it does not want to spawn the prefab with a button, but other times it did not find the mods folder in the resources folder. I don't know what to do any more.
using UnityEngine;
using UnityEngine.UI;
using System.IO;
public class ModLoader : MonoBehaviour
{
public GameObject buttonPrefab;
public VerticalLayoutGroup verticalLayout;
private string modFolder = "Mods";
private string modPath;
private void Start()
{
modPath = Path.Combine(Application.dataPath, "Resources", modFolder);
if(Directory.Exists(modPath)){
// Get all prefabs in the mod folder
Object[] prefabs = Resources.LoadAll(modFolder, typeof(GameObject));
for (int i = 0; i < prefabs.Length; i++)
{
GameObject prefab = (GameObject)prefabs[i];
// Create a button for each prefab
GameObject button = Instantiate(buttonPrefab, verticalLayout.transform);
button.GetComponentInChildren<Text>().text = prefab.name;
int index = i;
button.GetComponent<Button>().onClick.AddListener(() => SpawnPrefab(index));
}
}else{
Debug.Log("Mod folder not found");
}
}
private void SpawnPrefab(int index)
{
// Instantiate the prefab at position (0,0,0)
Object[] prefabs = Resources.LoadAll(modFolder, typeof(GameObject));
GameObject prefab = (GameObject)prefabs[index];
Instantiate(prefab, new Vector3(0, 0, 0), Quaternion.identity);
}
}
In this code I tried to get the asset path for a material (component, not sure if that's important to specify), but when I try to display the output in the debug log it just returns nothing. Also, the playerprefs stuff I set isn't working either, please help. EDIT!!! I found out that when trying targeting a component of a gameobject, the code just targets the object; therefore the code isn't looking for a material asset, it's looking for the object the material is on.
`
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
public class CustomData : MonoBehaviour
{
const string MatKey = "material";
Renderer rend;
string matpath;
void Start()
{
//Playerprefs
string material = PlayerPrefs.GetString(MatKey);
matpath = material;
//Sets material to desired material
rend = GetComponent<Renderer>();
rend.material = (Material)AssetDatabase.LoadAssetAtPath(matpath, typeof(Material));
}
void Update()
{
//Gets renderer and asset path of material
rend = GetComponent<Renderer>();
matpath = AssetDatabase.GetAssetPath(rend.material);
Debug.Log(matpath);
PlayerPrefs.SetString(MatKey, matpath);
PlayerPrefs.Save();
}
}
`
I've tried like a billion documents and stack overflow replies from other people to 0 success.
Scenario: User has different tile palettes for each season (Summer, Fall, etc.) and switching between the two using popular Unity techniques would be tedious if the number of tiles in the tileset is greater than 5 or 10. How would said user switch between their tile palettes programmatically, instead of using a wasteful solution like prefab tiles?
This problem seems significant enough that Unity docs would cover it. However I found myself digging through years-old forum posts to come up with my solution. Here's what I came up with, and it's not too complicated.
Create your tilesets. Import your tilesets as multi-sprite spritesheets, and split them using the Unity sprite editor. Do not bother naming each sprite. Each tileset should be organized the same exact way (bushes/trees/objects should be in the same spot on every season's tilesheet). When you are finished, create a folder "Resources" in your "Assets" folder. Inside of resources, create a folder "Spritesheets", and place your spricesheets in it.
Run this renaming script:
using UnityEngine;
using UnityEditor;
using System.Collections;
public class SpriteRenamer : MonoBehaviour
{
public Texture2D[] texture2Ds;
public string newName;
private string path;
private TextureImporter textureImporter;
void Start ()
{
foreach(Texture2D texture2D in texture2Ds){
path = AssetDatabase.GetAssetPath (texture2D);
textureImporter = AssetImporter.GetAtPath (path) as TextureImporter;
SpriteMetaData[] sliceMetaData = textureImporter.spritesheet;
int index = 0;
foreach (SpriteMetaData individualSliceData in sliceMetaData)
{
sliceMetaData[index].name = string.Format (newName + "_{0}", index);
print (sliceMetaData[index].name);
index++;
}
textureImporter.spritesheet = sliceMetaData;
EditorUtility.SetDirty (textureImporter);
textureImporter.SaveAndReimport ();
AssetDatabase.ImportAsset (path, ImportAssetOptions.ForceUpdate);
}
}
}
Attach it to an empty GameObject in an empty Scene (just for simplicity). Drag and drop your spritesheets into the Texture2D array. Set the newName field to whatever you want, it will be the prefix for the name of each sprite in each spritesheet. Finally, run the scene and each spritesheet's sprites will be renamed to make each corresponding sprite have the same name.
We now have each of our seasons' tilesheets modified so each tile is identically named. The next step is to create a Grid object with a child TilePalette. Draw all of your scenery, collision, etc. You can use as many TilePalettes as needed, as long as they are children of the Grid object. Now, create a script called ReskinnableTileBase:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Tilemaps;
public class ReskinnableTileBase : TileBase
{
public Sprite sprite;
public override void GetTileData(Vector3Int position, ITilemap tilemap, ref TileData tileData)
{
tileData.sprite = sprite;
}
}
Attach this Reskinner script to your Grid object:
using System;
using System.Linq;
using UnityEngine;
using UnityEngine.Tilemaps;
public class Reskinner : MonoBehaviour
{
Sprite[] subSprites;
Tilemap[] tilemaps;
void Start(){
tilemaps = GetComponentsInChildren<Tilemap>();
SetSkin("#INSERT DEFAULT TILE PALETTE NAME HERE#");
}
public void SetSkin(string name){
reloadSprites(name);
foreach(Tilemap tilemap in tilemaps){
for(int x = (int)tilemap.localBounds.min.x; x < tilemap.localBounds.max.x; x++){
for(int y = (int)tilemap.localBounds.min.y; y < tilemap.localBounds.max.y; y++){
TileBase tb = tilemap.GetTile(new Vector3Int(x, y, 0));
Debug.Log(tb);
ReskinnableTileBase rtb = (ReskinnableTileBase)ScriptableObject.CreateInstance(typeof(ReskinnableTileBase));
if(tb == null || rtb == null || tb.name.Length < 1){
continue;
}
Sprite replace = getSubSpriteByName(tb.name);
rtb.sprite = replace;
rtb.name = tb.name;
tilemap.SwapTile(tb, (TileBase)rtb);
}
}
}
}
void reloadSprites(string name){
subSprites = Resources.LoadAll<Sprite>("Spritesheets/" + name);
}
Sprite getSubSpriteByName(string name){
foreach(Sprite s in subSprites){
if(s.name == name){
return s;
}
}
return null;
}
}
And there you go! Now, any time you need to change the skin/season/tilesheet, just use a reference to the Grid's Reskinner script, and call the SetSkin method, like so:
Reskinner reskinner = gridObject.GetComponent<Reskinner>();
reskinner.SetSkin("summer");
I have created a cube in the scene and I want to attach the texture to the cube by scripting.
The problem is there is no error of my code but The cube doesn't change after I press run in my program...
Here is my code
using UnityEngine;
using System.Collections;
public class testing : MonoBehaviour {
void start(){
Texture2D tex = (Texture2D)Resources.Load("BlueColorTex.png", typeof(Texture2D));
renderer.material.mainTexture = tex;
}
}
void start()
{
Texture2D tex = (Texture2D)Resources.Load("BlueColorTex", typeof(Texture2D));
renderer.material.mainTexture = tex;
}
Resources.Load does not use extensions. This is a common mistake.
Returns the asset at path if it can be found otherwise returns null.
Only objects of type T will be returned. The path is relative to any
Resources folder inside the Assets folder of your project,
extensions must be omitted.
from: http://docs.unity3d.com/ScriptReference/Resources.Load.html
I'm looking to create a piece of terrain in unity using only a script (c# preferably) to do this rather than the menu options on the editor. So far I only have this code below, but I don't know what to do next to get it to appear on the scene, can anyone help?
Thank you
using UnityEngine;
using System.Collections;
public class terraintest : MonoBehaviour {
// Use this for initialization
void Start () {
GameObject terrain = new GameObject();
TerrainData _terraindata = new TerrainData();
terrain = Terrain.CreateTerrainGameObject(_terraindata);
}
// Update is called once per frame
void Update () {
}
}
Simply adding :
Vector3 position = ... //the ingame position you want your terrain at
GameObject ingameTerrainGameObject = Instantiate(terrain, position, Quaternion.identity);
should make the terrain appear ingame. The Instantiate method returns a reference to the gameobject spawned ingame, so if you later want to access it, you can use that reference.