Spawning Prefab spaws clone of Prefab - c#

I'm making a level editor and I need help spawning prefabs.
Below is the prefab that i'm using. Now, the code that I'm using makes it so when I click one of those orbs, a new Prefab is spawned in that diretion, and then disable the orb. And it kinda works:
Code for spawning:
void OnMouseDown()
{
Instantiate(prefab, transform.position + transform.forward, transform.rotation);
gameObject.SetActive(false);
}
Note: I did try to use PrefabUtility.InstantiatePrefab, but that didn't spawn anything:
void OnMouseDown()
{
GameObject currentTile = PrefabUtility.InstantiatePrefab(prefab) as GameObject;
currentTile.transform.position = gameObject.transform.position + gameObject.transform.forward;
gameObject.SetActive(false);
}
How do I pull this off?

I think that when you are setting the orb inactive, you are doing it in the prefab and not in the instance. (The instance is the (clone) that appears in the scene). So that might be causing that when a new clone is created, the clone has the orb inactive already.
For that you should deactivate the orb through the instance instead of the orb of the prefab with something like:
Gameobject GO = Instantiate(prefab, transform.position + transform.forward, transform.rotation);
GO.orb.SetActive(false);
Making the corresponding reference to the orb public and added in the editor so that you can then hace access to it and you can deactivate it.
Hope that makes sense.

Related

How to avoid getting out of position when colliding with another GameObject?

In my Unity game I have some moving objects. There are some collectables ( triggers ) and whenever a moving object enters its trigger the collectable should
Replace itself with a moving object
Destroy itself
Unfortunately the current moving object collides with the new spawned moving object so it will be out of position ( very little ). I would like to avoid that, so one piece connects smoothly to the other one.
For reproduction purposes:
Moving
Create a cube GameObject
Add a Rigidbody component but disable the usage of gravity
Attach the following script to it
.
public class MoveForwardBehaviour : MonoBehaviour
{
private void FixedUpdate()
{
GetComponent<Rigidbody>().velocity = Vector3.forward; // just for testing purposes
}
}
Make this GameObject a prefab
Collectable
Create a cube GameObject
Add a Rigidbody component but disable the usage of gravity
Enable the collider trigger and modify the following values
Attach the following script to it
.
public class Collectable : MonoBehaviour
{
[SerializeField] private GameObject movingPrefab;
private void OnTriggerEnter(Collider other)
{
GetComponent<Collider>().enabled = false;
Instantiate(movingPrefab, transform.position, transform.rotation);
Destroy(gameObject);
}
}
Assign the moving prefab to the script
Make this GameObject a prefab
Now setup a sample scene like so
and start the game. After creating a new moving prefab you can see that the initial moving prefab is not in position anymore
I think this is because of the collision with the new instantiated prefab. Do you have any suggestions how to avoid this?

How to move a Game prefab in unity

Below is my code but I don't know why when the _lazerPrefab spawns it doesn't move, even though _lazerSpeed != 0. I dont't know where the problem is.
if (Input.GetKeyDown(KeyCode.Space))
{
Instantiate(_lazerPrefab, transform.position, Quaternion.identity);
_lazerPrefab.transform.Translate(Vector3.up * _lazerSpeed * Time.deltaTime);
}
You cannot move the prefab itself, as prefabs are like "blueprints" that are used to construct real object instances, hence the name. You can indeed move those instances. Instantiate() will return the reference to the newly created copy/instance!
if (Input.GetKeyDown(KeyCode.Space))
{
GameObject new_lazer = Instantiate(_lazerPrefab, transform.position, Quaternion.identity);
new_lazer.transform.Translate(Vector3.up * _lazerSpeed * Time.deltaTime);
}
But this code will always spawn a new instance when you press Space. And once you spawned a 2nd, you will no longer move the first as the Translate call for the first instance is not done anymore.
So you need to adapt your logic. Either put a "move/accelerate forward" script on the lazers, or keep the references returned from Instantiate() in a list and maintain them and their lifetime. Another way could be adding a RigidBody and giving it a velocity so it keeps moving on it's own. Impact can be handled with a collider and the OnCollisionEnter or OnTriggerEnter (if the collider is marked as trigger) functions, where you can trigger sounds, damage etc.
You are only moving the _lazerprefab when Input.GetKeyDown(KeyCode.Space) is true.
If you want to move the gameObject more than once after you press space you would need to add the move code into the gameObjects Update() Method itself.
You would need to attach this script to the _lazerprefab GameObject.
Example Script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MoveObstacles : MonoBehaviour {
[SerializeField]
private float _lazerSpeed = 10f;
private void FixedUpdate() {
gameObject.transform.Translate(Vector3.up * _lazerSpeed * Time.deltaTime);
}
}
We are now able to just call the Instantiate() Function and the instantiated GameObject will move automatically each frame.
Example Move Call:
if (Input.GetKeyDown(KeyCode.Space)) {
Instantiate(_lazerPrefab, transform.position, Quaternion.identity);
}

Prefab loaded by Resources.Load can not be rendered on scene

I have created a Prefab and I load it in the Awake function with the following code:
GameObject bulletPrefab = Resources.Load<GameObject>("Enemy/Bullet");
bulletPrefab.transform.position = new Vector3(0,0,0);
The problem is that the bulletPrefab is not gonna show in the game scene. Its activeSelf property is true but its activeInHierarchy property is false. Does anyone know why it is like this and how to make the bulletprefab show in the scene?
Do not modify a prefab. You tried to modify it when you did bulletPrefab.transform.position = ...
The bulletPrefab is a loaded GameObject which is only stored in the memory. To see it, you have to instantiate it with the Instantiate function. You seem to have done this in your other question but for some reason decided to remove that critical part in this question.
Looking at your last question, it seems like your issue is shooting the prefab. You don't shoot the prefab by setting the bullet's position to another position in one frame. You can use a coroutine and do that over multiple frames or you can use Rigidbody for this. I suggest using Rigidbody because that's the kind of stuff it is made for.
Makes sure that Rigidbody is attached to the prefab you want to load. Load the prefab, instantiate it then get the Rigidbody attached to it. Move the bullet to the front of the player + camera then use Rigidbody.velocity or Rigidbody.AddForce to shoot the bullet to the CameraTransform.forward direction so that the bullet will travel to the direction the camera is facing.
See below for example of loading and shooting a bullet prefab when space key is pressed.
GameObject bulletPrefab;
Transform cameraTransform;
public float bulletSpeed = 300;
private void Start()
{
//Load Prefab
bulletPrefab = Resources.Load<GameObject>("Enemy/Bullet");
//Get camera transform
cameraTransform = Camera.main.transform;
}
void Update()
{
//Shoot bullet when space key is pressed
if (Input.GetKeyDown(KeyCode.Space))
{
shootBullet();
}
}
void shootBullet()
{
//Instantiate prefab
GameObject tempObj = Instantiate(bulletPrefab) as GameObject;
//Set position of the bullet in front of the player
tempObj.transform.position = transform.position + cameraTransform.forward;
//Get the Rigidbody that is attached to that instantiated bullet
Rigidbody projectile = GetComponent<Rigidbody>();
//Shoot the Bullet
projectile.velocity = cameraTransform.forward * bulletSpeed;
}

How to have a powerup have a slight chance of spawning when killing an enemy?

so we have a class assignment and pretty much we are doing the Survival Shooter project from the Unity tutorials. I've managed to make health packs and little boxes that give you speed when you pick them up, but now I want the power-ups to have a slight chance of dropping when enemies die. Can someone help me out? I'm not really asking for entire code, I have some down below:
public float percentDrop = 50f;
public GameObject HealthPack;
void Awake()
{
HealthPack = GetComponent<GameObject>();
}
public void TakeDamage (int amount, Vector3 hitPoint) { if(isDead) return;
enemyAudio.Play ();
currentHealth -= amount;
hitParticles.transform.position = hitPoint;
hitParticles.Play();
if(currentHealth <= 0)
{
Death ();
}
}
void Death ()
{
isDead = true;
capsuleCollider.isTrigger = true;
anim.SetTrigger ("Dead");
enemyAudio.clip = deathClip;
enemyAudio.Play ();
var randChance = Random.Range(0f, 100f);
if (randChance < percentDrop)
{
//GameObject.Healthpack.setActice(true);
}
}
I'm not too sure how to make the Game Object spawn when they die, can someone help me out?
Create a "Health Pack" prefab from the editor. If you need more information about prefabs, the information is out there on the web. To create a prefab, simply drag and drop a GameObject from the scene to your project. Its name in the scene will become blue. You can delete it from the scene and it will still be in the project.
Drag the prefab from the project to the HealthPack slot in the inspector of your ennemy. The ennemy will now have a reference to the prefab.
When you want to create a new health pack, you can use the Object.Instantiate static method as specified by rutter. Here is the official doc. When you instantiate your new Health Pack, I guess you want it to appear where the ennemy is, wich means you'll want to use one of the method's overloads which takes a Vector3D position as a parameter, which will most likely be transform.position. Since those methods also ask for a Quaternion, just pass in the Quaternion.identity constant.
This is how your code could look:
if (randChance < percentDrop)
{
Object.Instantiate(HealthPack, transform.position, Quaternion.identity);
}
Another problem, as mentioned in my comment, is the Awake function: HealthPack = GetComponent<GameObject>();.
The HealthPack prefab should be assigned to the ennemy from the inspector. That line in the Awake function will assign your ennemy's GameObject component to HealthPack, which is not desirable in the current context.
I hope this helps!

Unity 3D Rigidbody 2D movement using MovePosition

Working on 2D mode, I have a script attached to a Sprite. The Update() part is as follow:
void Update () {
if (Input.GetKeyDown ("left")) {
cursor.rigidbody2D.MovePosition (cursor.rigidbody2D.position - speedX);
} else if (Input.GetKeyDown ("right")) {
cursor.rigidbody2D.MovePosition (cursor.rigidbody2D.position + speedX);
} else if (Input.GetKeyDown ("up")) {
cursor.rigidbody2D.MovePosition (cursor.rigidbody2D.position + speedY);
} else if (Input.GetKeyDown ("down")) {
cursor.rigidbody2D.MovePosition (cursor.rigidbody2D.position - speedY);
}
}
where cursor is a Prefab linked in Inspector. The cursor prefab has only 2 components, Sprite Renderer (to define the image), and the Rigidbody 2D, which setting is as follow:
Mass = 1
Linear Drag = 0
Angular Drag = 0
Gravity Scale = 0
Fixed Angle = true
Is Kinematic = false
Interpolate = None
Sleeping Mode = Start Awake
Collision Detection = Discrete
But when I press the arrow keys, the sprite showing on screen does not move. What did I miss?
Tried to add Debug.Log() inside the if case, it really enters the case. And no error occurred.
Note: speedX = new Vector2(1,0); and speedY = new Vector2(0,1);
You're trying to move an object that doesn't exist from the game's perspective. Assigning cursor a prefab by dragging it from the assets library, is like assigning a blueprint. Telling the prefab to move is like yelling at a car's blueprint to accelerate :)
There are two general solutions.
1) Save a reference
Instantiate the prefab and save the resulting reference to manipulate your new object. You can directly cast it to Rigidbody2D if you're mainly interested in using the rigidbody. The cast will only work if your prefab variable is of the same type, otherwise it will raise an exception. This way will ensure that your prefab always contains a Rigidbody2D or you can't even assign it in the editor.
public Rigidbody2D cursorPrefab; // your prefab assigned by the Unity Editor
Rigidbody2D cursorClone = (Rigidbody2D) Instantiate(cursorPrefab);
cursorClone.MovePosition (cursorClone.position - speedX);
2) Assign the script to the prefab
Depending on your game and what you want to achieve, you can also add a script directly to the prefab. This way every instance of it would just control itself.
void Update () {
if (Input.GetKeyDown ("left")) {
rigidbody2D.MovePosition (rigidbody2D.position - speedX);
} else { //...}
}

Categories