I'm designing a 3D Tetris game. I'm new to unity and just started to learn some basics in this site
My plan is not to create a regular tetris board, but to create a 3D surface, with width,height and depth so the user will need to build a surface in order to destroy the objects.
So in my design I know that I need an object generator and to create an object (Tetris cube) in they that I'm calling the object generator in the update method with some timer.
Also the idea is to make a 3d matrix that represent the game board so I could check in the game logic if there is a "surface" in that matrix.
This is a part of the game logic script.. and my problem is that i don't know where to put this script.. I mean in the game logic I need to create a random cube, and to check if there is a surface that can be destroyed.. but where should I put the game logic script?
I always used IDE's like visual studio or eclipse so there you can have a main class with the main method that start your program.. and now in unity i'm confused..
Edit:
Thanks for your replying.. I forgot to mention that I have something like 3 scenes (levels) in the game.. so for each level (scene) should I create an empty game object?
make an empty gameobject and attach your object that you want to spawn(as child) to it and attach your spawn code to that empty object(parent)
Create an empty gameobject like mentioned and put a script on it that saves it from being destroyed on scene-change (some sort of singleton).
Some basic way to do it:
using UnityEngine;
using System.Collections;
public class GameController : MonoBehaviour
{
private static GameController instance
public static GameController Instance
{
get { return instance; }
}
private void Awake()
{
instance = this;
DontDestroyOnLoad(instance);
}
}
The DontDestroyOnLoad will hold the whole gameobject with everything attached to stay loaded on scene-change.
Related
I am trying to reference a game object in a prefabs folder to insatiate how would I do that. also, the object I'm trying to reference is a particle effect if that helps anyone who is answering this.
In your MonoBehaviour scipt, add a [SerializeField] GameObject _prefab field.
e.g. here I've made a script called SlabMaker that makes endless terrain utilising a prefab:
public class SlabMaker : MonoBehaviour
{
[SerializeField]
private GameObject _prefab;
.
.
.
Then in the Editor, select the object with the previously mentioned script attached. In my example I have attached the SlabMaker script to a GameObject with the highly original name of "_Game". Notice the properties for the SlabMaker appearing in the Inspector along with a field for Prefab. Hurrah!:
...then drag whatever prefab you wish to use from the Project window into the Prefab property in the Properties pane:
In this example I will use my fancy jumpjet plane. Why I want to make endless terrain with Harrier Jumpjets is anyones' guess:
Now then all you have to do is to instantiate the prefab in your script. Job done.
When I put this script into the object, a cube, it does not register the platform it hits beneath when I make the gameObject the platform. I'm trying to get the two objects to detect collision between each other but it does not seem to work. Neither objects are trigger checked in the Box Colliders. The cube has a rigid body with gravity checked but the platform does not. This is a 3D game.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Collision : MonoBehaviour
{
public Transform gameObject;
void onCollisionEnter(Collision col)
{
if (col.gameObject);
{
Debug.Log("Yes");
}
}
}
As Sven Viking already said, you have to change the syntax from onCollisionEnter to OnCollision enter. Also, let's take a look at your logic:
You want to check that, if your cube object collides with another object, and if that object is the same as the one you're referencing, you want to see a log of that in your console. Currently, however, you're asking for something else.
First of all, your platform is not stored as a gameObject, it's stored as a Transform. Those two are different things, the Transform stores the position/rotation/scale of an object, while 'GameObject' is the entire object, includng its Transform. Also, you named your variable gameObject, which you should never do - Never name variables with the same name as existing elements.
'col' represents the collision. col.gameObject is the gameObject of that collision. There's no logic demanded there. You're just making a reference. What you want, instead, is compare the gameObject of the collision with your referenced gameObject(the platform) and, if both of them are the same, then you can proceed. Therefore, what you want is:
public class CollisionScript : MonoBehaviour
{
public GameObject platform;
void OnCollisionEnter(Collision col)
{
if (col.gameObject == platform);
{
Debug.Log("Yes");
}
}
}
Let me know if this solves your problem.
EDIT: I see now you also named your class 'Collision', which I'm pretty sure would break things, as Collision is already a class within Unity(you can check that looking at "Collision col", that indicates there is a class named Collision). You should change both the class name on the top of the script and the file name to reflect that change.
I'm in the process of creating the enemy for my tower defense game.
I want one enemy to be tanky (lots of health)
one enemy to be fast
one enemy to cast spells to boost other enemies
Based on my research, I could create an enemy base class, then create a script for each enemy type (Tank, Speed, Enchanter). I would then need to place them on each respective prefab but I'm wondering whether this is good practice? Let's say that I have 100 enemy types, do I need to create 100 scripts and prefabs for it?
On another note, I'm planning to use scriptable objects for the enemy stats but I'm
a bit confused on how to implement it. I would create one enemy prefab, feed it the scriptable object of my enemy (e.g some SO has lots of health, some has lots of speed) but I'm not too sure how can I implement different behaviors for each enemy type.
Thank you!
You can create a scriptable object like this:
[CreateAssetMenu(fileName = "Enemy", menuName = "Enemy")]
public class EnemyData : ScriptableObject
{
public int Health;
}
you can define more variables as you want. You can create multiple EnemyData from Create menu and set different values for each enemy.
Then create an enemy class like this.
public class Enemy : Monobehavior
{
public EnemyData data;
}
You can load this data from different ways. The simplest way could be like this for Enemy1:
public class Enemy : Monobehavior
{
public EnemyData data;
private Awake()
{
data = (EnemyData)Resources.Load("Enemies/Enemy1", typeof(EnemyData));
}
}
You can access to each value like this:
data.Health
For this, you should put your enemy objects in Resource/Enemies folder.
You can define name or id for different enemies, so loading could be easier.
I hope this brings an idea for you.
You could create an Enemy base class and expose the speed and health as public properties so that way you could configure each instance differently.
I would also consider creating a separate script that's sole purpose is 'casting spells to boost other enemies' also a separate script that fires projectiles with customizable damage, etc. By separating the responsibilites, you make your system modular and you can basically put together any combination you want by adding a behavior to a prefab.
During gameplay, is there any way to check whether a game object is an instance of a prefab, and get a reference to that prefab? I tried various methods in PrefabUtility, but they're all saying that my scene's instance of a prefab is not a prefab.
The thing is that PrefabUtility like e.g. PrefabUtility.IsPartOfAnyPrefab is in the UnityEditor namespace. So anyway it won't help you unless you need it only inside the UnityEditor itself.
Also this thread might be relevant if the PrefabUtility isn't working for you in the Editor because you are in the prefab mode:
In Prefab Mode the GameObject are simply regular gameobjects unless you have a nested prefab.
For runtime in a build or as soon as you enter the PlayMode the concept of prefab instance doesn't really exist anymore. They are then only GameObjects with no information about where they came from ;)
You could however store the reference to the prefab in a component like e.g.
#if UNITY_EDITOR
using UnityEditor;
#endif
[ExecuteInEditMode]
public class PrefabInfo : MonoBehaviour
{
public GameObject original;
#if UNITY_EDITOR
private void Awake()
{
// See https://docs.unity3d.com/ScriptReference/PrefabUtility.GetCorrespondingObjectFromOriginalSource.html
original = PrefabUtility.GetCorrespondingObjectFromOriginalSource(gameObject);
}
#endif
}
and on runtime also do
var obj = Instantiate(yourPrefab);
if(obj.TryGetComponent<PrefabInfo>(out prefabInfo)
{
prefabInfo.original = yourPrefab.gameObject;
}
else
{
obj.AddComponent<PrefabInfo>().original = yourPrefab.gameObject;
}
This way you would know if something is a prefab instance on runtime and which is the original prefab.
If you want to kind of hack this in order to automate it you could even create an Inspector for all MonoBehaviour and attach the PrefabInfo component automatically if something is a prefab or a prefab instance ;)
No - the information is removed from the instantiated GameObjects in the runtime for performance reasons.
The only way to do this would be to store it yourself via Editor script, run it before you enter the runtime, map out all prefabs that are interesting to you, and use this newly created information.
In my fps level (Unity), targets spawn at a random position. I want to make sure targets can't spawn behind objects or inside objects.
To make sure they don't spawn behind an object, I've made a raycast going from the player to the target. If it's obstructed I recalculate the spawn point. This works fine, but, since the targets are spheres the raycast won't be obstructed when a target is 50% inside an object, for example the floor. I don't want that, obviously.
To determine whether or not the target is in the bounds of another object, I tried using OnCollisionEnter and OnCollisionExit. While this works when simply moving a target inside another object, it seems to be unreliable when one script's Update cycle is recalculating the spawn position while the target's Update cycle is keeping track of the Collision.
So I looked for a different approach. Here's what I came up with (from the Unity docs):
m_Collider2 = spawnpoints[i].GetComponent<Collider>();
m_Collider = world.GetComponentInChildren<Collider>();
if (m_Collider.bounds.Intersects(m_Collider2.bounds))
{
Debug.Log("Bounds intersecting");
}
The Game Object world is the parent in which I put all the objects of my gaming world.
The problem is that he only takes into account the collider of the first object. I basically want to use one big collider, which is composed by all the level objects.
Is this possible? Or does anyone know a different approach on how I can achieve this?
You should use the GetComponentsInChildren method instead of GetComponentInChildren, so that you can get from it an array of colliders on which you can execute a foreach to check if the bounds are intersecting.
I.E.:
m_Collider2 = spawnpoints [i].GetComponent<Collider>();
m_Collider = world.GetComponentsInChildren<Collider>();
foreach(Collider objCollider in m_Collider) {
if (objCollider.bounds.Intersects(m_Collider2.bounds))
{
Debug.Log("Bounds intersecting");
break;
}
}
But, this way of doing things is very heavy for the CPU, since GetComponent methods are really slow, so their use should be limited inside Awake and Start methods if possible.
Another approach to the problem would be to create a List<Collider> at the start, and add to it the starting children of your World game object. If another one is instantiated, just Add it to your list, if it's destroyed, just Remove it.
Then, just before instantiation, you can check the bounds by looping inside the List with a foreach, the check will be a lot more faster.
==================================
EDIT:
Ok, here's the deal. First of all, add these lines to your World game object script (I guess you called the class World):
using UnityEngine;
using System.Collections.Generic; //Namespace needed to use the List type
public class World : MonoBehaviour {
//The list which will hold references to the children game objects colliders
public List<Collider> childrenColliders;
private void Start() {
//Code used to populate the list at start
childrenColliders = new List<Collider>(GetComponentsInChildren<Collider>());
}
Now, since in the script which spawns a new object has already a world variable which holds a reference to the World class:
foreach(Collider coll in world.childrenColliders) {
if (coll.bounds.Intersects(m_Collider2.bounds))
{
Debug.Log("Bounds intersecting");
break;
}
}
And, of course, as I said before remember to add a newly spawned game object's collider to the list with:
void AddNewGameObject() {
// spawnPoint is the transform.position Vector3 you'll use for the new game object
var newGameObject = Instantiate(yourObjectPrefab, spawnPoint, Quaternion.identity, world.transform);
world.childrenColliders.Add(newGameObject.GetComponent<Collider>());
}
That's pretty much it. ;)