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.
Related
I am creating a digital boardgame, which consits of muliple boards, between which the gamepieces are moved by the players.
The script of the game board needs a 2D array of positions to know where to move a gamepiece when it recives one.
Currently to mark the positions on the game boards, I added placeholder gameobjects to the prefab and named them "spawnpoint\d".In the Awake() method I use Transform.Find() to search for those gameobjects. Then, after I save their positions I call Destroy() on them, so they do not show up in the game.
I see two problems:
This is done for all Instantiated game board, altough the positions are the same on all of them.
I read that using Transform.Find() is heavily discourged by the experts in the community.
I wish to store the spawnpoint positions in a static array, so all instances refer to the same data. Furthermore I wish to easily modify these positions in the editor with visual help.
I tried serializing static members, but those do not show up in the editor to be able to modify.
[SerializeField]
public static int TestNumber;
TLDR:
How to make static members visually changeable from the Unity editor?
tl;dr you can't, static fields are not serialized.
You can do e.g.
[SerializeField] private Transform[] spawnPoints;
public static Transform[] SpawnPoints;
private void Awake ()
{
SpawnPoints = spawnPoints;
}
In general I would suggest rather using something like this:
// Simply attach this class to each GameObject that shall be a spawn point
// MAKE SURE IT IS ACTIVE AND ENABLED BY DEFAULT
public class SpawnPoint : MonoBehaviour
{
// Each SpawnPoint (un)registers itself here
private static readonly HasSet<SpawnPoint> _instances = new HashSet<SpawnPoint>();
// For the public return a new HashSet to make sure nobody can modify the
// original _instances from the outside
public static HashSet<SpawnPoint>() Instances => new HashSet<SpawnPoint>(_instancea);
private void Awake()
{
// Register yourself to the existing instances
_instances.Add(this);
// Optional: make sure this object is not destroyed when a new scene is loaded
DontDestroyOnLoad (gameObject);
// simply hide the entire gameObject
gameObject.SetActive(false);
}
private void Destroy ()
{
// Unregister yourself from the instances
_instances.Remove(this);
}
}
This way
each spawn point Auto-Registers itself to the Instances so you don't even need to serialize this via the Inspector -> you also can't forget any
the spawn points don't get Destroyed when a new scene is loaded (if you use the DontDestroyOnLoad - otherwise they are destroyed and auto-removed from the instances)
you disable the objects (though actually if they have nothing attached except this script it wouldn't matter anyway)
you can easily access all the spawn points without using expensive stuff like Find or FindObjectsOfType but rather simply via the property
var availableSpawnPoints = SpawnPoint.Instances;
I tried to get Terrains from Resources.FindObjectsOfTypeAll(typeof(Terrain)), and then activate it depend on the situations.
But it return Objects.
I had tried to cast it to GameObject by (GameObect)obj and obj as GameObject.
The first one raised an Invalid cast error, and the second returned a null.
The examples I was able to find online talked about Resources.Load mostly, which requires Instantiation.
But I don't think FindObjectsOfTypeAll requires instantiation, because the GameObjects are "already there"! Right!?
So could somebody please be so kind and teach me how can I cast Objects into GameObject so I could activated it!?
Much appreciated!
Terrain is a component, so its associated GameObject is accessed via the gameObject property.
Something like:
var go = ((Terrain)obj).gameObject;
Hi think you could use something like finding the terrain with the name of the object or the name of the tag, maybe this could help:
public class ExampleClass : MonoBehaviour
{
public GameObject terrain;
public GameObject[] terrains;
void Example()
{
// This returns the GameObject named Hand.
terrain = GameObject.Find("Hand");
// returns a list of the game objects with tags = 'terrain'
terrains = GameObject.FindGameObjectsWithTag("terrain");
//returns a single object with the tag terrain
terrain = GameObject.FindWithTag("terrain");
}
}
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.
I am struggeling to come up with a smart way to deal with cutscenes in my 2D game. I think I have decided to Create/Control the cutscenes using the Animator, and moving the actual GameObjects around.
What I am struggeling with is:
This approach means each GameObject needs it's own Animator. So how do I then trigger the correct Cutscene? I am going to use game stages to control the game and its progress, so for example:
if(gameStage == 34 && entering scene castle)
{
playCorrectCutscene();
}
How and where do I keep references to all my cutscenes? Say I have 22 NPCs in a scene, and 15 of those have their own Animator since they have a cutscene, how do I play the Animation from NPC_11?
I guess what I am looking for is some sort of "Cutscene Manager". The best possible solution would be to have a List of every cutscene (animation) with an ID. Then I could just use the ID to play the correct animation. But since each Animation is stored in the actual GameObject I have no idea if that is possible.
Hope Im making sense.
Once you create complete prefab with 1 Animator per prefab, then you can use bellow method to create instances on the fly:
Let say you have CutsceneManager script like this:
class CutsceneManager : MonoBehaviour {
public GameObject InstantiateResource(string folder, string name)
{
GameObject resource = Instantiate<GameObject>(Resources.Load<GameObject>(folder + "/" + name));
if (resource == null)
{
Debug.LogErrorFormat("Cannot find resource {0} in {1}", name, folder);
return null;
}
resource.name = name;
return resource;
}
}
The easiest way to use it is to attach it to Empty object. Then you can create public variable for manager in other scripts, where you would need to show cutscene, like this:
class SomeOtherScript : MonoBehaviour {
public CutsceneManager CutsceneManager;
}
This will let you drag&drop CutsceneManager empty into each script where you need it. This way you have 1 instance of cutscenemanager for all classes.
Now, in place where you would need to play custscene, you instantiate:
class SomeOtherScript : MonoBehaviour {
public CutsceneManager CutsceneManager;
public void PlayMyCutscene() {
GameObject cutscene = CutsceneManager.InstantiateResource("Cutscenes", "SomeOtherCutscene");
cutscene.setActive(true); // Or whetever other method to fire it off
}
}
On folder structure you would need to have: Assets\Resources\Cutscenes
Cutscenes would be called: SomeOtherCutscene.prefab
Notice there is no need to include .prefab when you are instantiating one - Unity framework will "know" and add it for you.
In my Unity3D project I got a complex GameObject of a truck that his hierarchy looks like this.
+ Truck
+FrontPivotPoint
+LeftWheel
Tire
Rim
Hindge
+RightWheel
Tire
Rim
Hindge
+CenterPivotPoint
+Body
Arm
Screw
Pin
Basically what's happening is I got a lot of complex parenting and I want to go trough every child and add to him a RigidBody.
I think it should be something nested but I don't have something in mind.
Any help would be appreciated!
Unity3d allows you to easily automate every routine. You may consider to add custom menu item.
public class MakeRigidBodies : EditorWindow
{
[MenuItem ("Make rigid bodies %&r")]
private static void Execute()
{
var selectedObject = UnityEditor.Selection.activeObject;
if( selectedObject && selectedObject is GameObject )
{
// for all children of selectedObject
{
// add rigid body
}
}
}
}
From what I can see, the structure of your game objects is like a tree data structure. Truck as its parent / root node, and the others as its child. So, you must traverse all the objects / nodes in your structure with tree traversing algorithm, the best that I know is Depth-First-Search (DFS) algorithm.
DFS work like nested loop, the main algorithm are:
Start from the root node
Find its node children
Visit the child
Back to step 2 until all children is visited
This algorithm can be implemented in Unity3d since GameObject stores its child information in transform properties (see http://answers.unity3d.com/questions/416730/get-the-child-gameobject-of-a-parent-and-not-the-t.html). And last, we can add RigidBody to the GameObject with the AddComponent() method (see http://answers.unity3d.com/questions/19466/how-do-i-add-a-rigidbody-in-script.html).
Here is my script to answer your question:
using UnityEngine;
using System.Collections;
public class AddRigidBody : MonoBehaviour {
private void addRigidBody(GameObject gameObject)
{
Rigidbody rigidBody = gameObject.AddComponent<Rigidbody>();
foreach(Transform t in gameObject.transform)
{
addRigidBody(t.gameObject);
}
}
void Start () {
addRigidBody (this.gameObject);
}
}
This script attached to the parent / root GameObject. The AddRigidBody() method is called when this script start (as in Start() method), and this method will traverse all child and add a RigidBody through it.
If I'm not mistaken, and bear with me since it's been a while since I've worked with Unity3D, this could fix it:
* Drag your model onto the stage
* Your entire model should now be selected; parent and its underlying children
* Select the option to add a rigidbody and it should add it to all selected objects.
* Make a prefab of the model and you should be done.
Once again, don't trust me on this. It's been a while and since I don't have access to Unity3D right now, I am unable to check this method myself.
If it's the code approach you want, try this (C#, methods may vary for Boo or Java):
Getting a child: http://forum.unity3d.com/threads/get-child-c.83512/ (see second reply)
Adding a rigidbody: http://answers.unity3d.com/questions/19466/how-do-i-add-a-rigidbody-in-script.html
I hope this helps.