Moving a Prefab in Unity - visual-studio

The purpose of the code is to
make a prefab of "Normal" and "Virus"
make them move in random directions
when they collide, change "Normal" into "Virus" Prefabs
However, I've got stucked on step 2.
I successfuly made "Normal" and "Virus" Prefabs get spawned at random places.
Btw, I have no idea what I should do to supply transform function to Prefabs.
Also, what codes should I use to replace "Normal" Prefabs into "Virus" Prefabs if they collide each other?
These are the codes and pics I used
using UnityEngine;
public class VirusSpawner : MonoBehaviour
{
[SerializeField]
private int objectSpawnCount = 5;
[SerializeField]
private GameObject[] prefabArray;
private void Awake()
{
for (int i = 0; i < objectSpawnCount; ++i)
{
int index = Random.Range(0, prefabArray.Length);
float x = Random.Range(-3, 3);
float y = Random.Range(-4, 4);
Vector3 position = new Vector3(x, y, 0);
Instantiate(prefabArray[index], position, Quaternion.identity);
}
}
}

As I understood what you need is a script for your objects, responsible for moving them and controlling all this "Normal" and "Virus" states.
2.1. Create a C# Script (i.e. "Virus") that moves the object as soon as it exists.
2.2. Right after instantiating your prefabs add this script to it:
GameObject newGO = Instantiate(prefabArray[index], position, Quaternion.identity);
newGO.AddComponent<Virus>();
On the new "Virus" script, add the collision detection and variable that holds the state of Normal or Virus

As #Caio Rocha said you can instantiate new Virus Object and add component to it but there can be one more way which can be faster :
Create a Empty Game Object.
Add both (Virus and Normal) prefabs as children of that prefab and drag and drop to project window to create new Prefab.
Attach this script to Parent:
public class ParentObject : MonoBehaviour
{
public GameObject VirusObject;
public GameObject NormalObject;
private bool isVirus;
private void Awake()
{
isVirus = (Random.Range(0, 2) == 1); //Randomly Make an object
//virus or normal on instantiation
if (isVirus)
{
TurnToVirus();
}
else
{
TurntoNormal();
}
}
private void OnCollisionEnter(Collision other)
{
ParentObject coll =
other.collider.gameObject.GetComponent<ParentObject>();
if (coll && coll.isVirus) //if other object is virus
{
TurnToVirus();
}
}
private void TurnToVirus()
{
VirusObject.SetActive(true);
NormalObject.SetActive(false);
}
private void TurntoNormal()
{
VirusObject.SetActive(false);
NormalObject.SetActive(true);
}
}
Now Inside prefab array move this Parent prefab instead of your own prefabs and it will randomly create normal and virus objects and when they interact normal turn to viruses. Make sure this script and collider is now on parent. This is much optimized over adding component individually just for single check.

Related

Unity Instantiate objects appear in hierarchy but not visible

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MakePipe : MonoBehaviour
{
public GameObject pipe;
float timer = 0;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
timer += Time.deltaTime;
if (timer > 1)
{
Instantiate(pipe);
timer = 0;
}
}
}
I am trying to instantiate pipes using prefab, and with the code, a new set of pipes should spawn and move left from the original position where the first set of pipes spawned, but they are not visible.
They are generated as clones in the hierarchy, but when I double-click them to check the position, it points towards the first pipe position.
My guess is that new clones are generated and overlapped in the first pipe as they move together.
Please help
Thanks for your reply.
Sorry I didn't add a separate cs code 'move', I should have added gif..
The following code is to move the pipe left with certain speed. There is no problem there.
However from the 'MakePipe' code that I originally posted, I used instantiate to keep reproducing the pipe. Maybe I should add some lines to 'Start()' part to set original spawn location?
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Move : MonoBehaviour
{
public float speed;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
transform.position += Vector3.left * speed * Time.deltaTime;
// Debug.Log(transform.position);
}
}
I had to delete photos because error message tells me I should have more than 10 reps to edit :(
I don't have enough rep to comment, I'll attempt to give you a answer and update it for what you need.
The Object.Instantiate method has some parameters that you can use to get your pipes into place.
public static Object Instantiate(Object original, Vector3 position, Quaternion rotation, Transform parent);
And without the overloads it will use the original prefab's parameters. So they will spawn in the same location. You have to calculate the next position and pass it in the Instantiate method (Vector3 position).
I misunderstood what you are trying to do at first. #Geeky Quentin
gave the right answer in the first comment.
[SerializeField] private GameObject pipe;
float timer = 0;
float offset = 1.5f;
void Start()
{
}
void Update()
{
timer += Time.deltaTime;
transform.position += new Vector3(-Time.deltaTime/offset, 0, 0);
if (timer > 1)
{
GameObject lastPipe = Instantiate(pipe);
lastPipe.transform.SetParent(transform);
timer = 0;
}
}
I still don't have enough rep to comment. Regarding your last changes. I tested your code out.
Are you parenting the instantiated pipe to the PipeMaker in another script? If not this is the effect it spawns but it does not move:
To make it work you need to parent the instantiated pipe and change it's position MakePipe.cs:
public GameObject pipe;
float timer = 0;
private GameObject _newPipe;
void Update()
{
timer += Time.deltaTime;
if (timer > 1)
{
//instatiate with parent on transform
_newPipe = Instantiate(pipe, transform);
//Set positiion to orginal prefab position
_newPipe.transform.position = pipe.transform.position;
timer = 0;
}
}
This is the effect:
My PipeSpawner has the Move and MakePipe scripts attached to it. And the prefab is in a hidden PipePrefab object that's unrelated to the rest of the system.
You could also set the position of the original spawn location in your Start() method as you said, it's up to you.

Getting errors when i try to get game to restart when i hit an obstacle or fall of ground

Please excuse me I'm a complete novice at all this but I'm trying to make a game following "Brackeys How To Make A Video Game" I'm on video 8 if that helps. I can't seem to find what i have done wrong i have added my scripts for "player movement", "player collision" and "game manager". Please if there is anything else you need to help me please ask i really don't want to give up just yet was really enjoying doing this.
Thank you all
using UnityEngine;
public class PlayerMovement : MonoBehaviour {
// This is a reference to the Rigidbody component called "rb"
public Rigidbody rb;
public float forwardForce = 2000f; // Variable that determines the forward force
public float sidewaysForce = 500f; // Variable that determines the sideways force
// We marked this as "Fixed"Update because we
// are using it to mess with physics.
void FixedUpdate ()
{
// Add a forward force
rb.AddForce(0, 0, forwardForce * Time.deltaTime);
if (Input.GetKey("d")) // If the player is pressing the "d" key
{
// Add a force to the right
rb.AddForce(sidewaysForce * Time.deltaTime, 0, 0, ForceMode.VelocityChange);
}
if (Input.GetKey("a")) // If the player is pressing the "a" key
{
// Add a force to the left
rb.AddForce(-sidewaysForce * Time.deltaTime, 0, 0, ForceMode.VelocityChange);
}
if (rb.position.y < -1f)
{
FindObjectOfType<GameManager>().EndGame();
}
}
}
using UnityEngine;
public class PlayerCollision : MonoBehaviour {
public PlayerMovement movement; // A reference to our PlayerMovement script
// This function runs when we hit another object.
// We get information about the collision and call it "collisionInfo".
void OnCollisionEnter (Collision collisionInfo)
{
// We check if the object we collided with has a tag called "Obstacle".
if (collisionInfo.collider.tag == "Obstacle")
{
movement.enabled = false; // Disable the players movement.
FindObjectOfType<GameManager>().EndGame();
}
}
}
using UnityEngine;
using UnityEngine.SceneManagement;
public class GameManager : MonoBehaviour {
bool gameHasEnded = false;
public float restartDelay = 1f;
public GameObject completeLevelUI;
public void CompleteLevel ()
{
completeLevelUI.SetActive(true);
}
public void EndGame ()
{
if (gameHasEnded == false)
{
gameHasEnded = true;
Debug.Log("GAME OVER");
Invoke("Restart", restartDelay);
}
}
void Restart ()
{
SceneManager.LoadScene(SceneManager.GetActiveScene().name);
}
}
when i fall off ground:
NullReferenceException: Object reference not set to an instance of an object
PlayerMovement.FixedUpdate () (at Assets/Scripts/PlayerMovement.cs:32)
when i hit an obstacle:
NullReferenceException: Object reference not set to an instance of an object
PlayerCollision.OnCollisionEnter (UnityEngine.Collision collisionInfo) (at Assets/Scripts/PlayerCollision.cs:15)
It seems to me that FindObjectOfType<GameManager>() is returning null, which is causing a null reference exception when you attempt to call the EndGame function. This most likely means that there is no object in your scene with the GameManager component on it. The solution to this problem is simple:
Create an empty object in your scene and add the GameManager component to it. This will fix the error in this instance, but it could happen in the future if you're not careful. It is also a good idea to check if you found an object or not before calling functions on it:
GameManager gm = FindObjectOfType<GameManager>();
if (gm != null)
{
gm.EndGame();
}

Why in my unity project the chasing part is not working?

Could someone please maybe download and see my project? It is very simple, but not working as in the tutorial.
In my project, I set IsTrigger to true in either the ThirdPersonController or the AIThirdPersonController for one of the characters. This makes the character fall down from the Plane.
I also changed one of the characters to be tagged as Player and changed the state from PATROL to CHASE but that changed nothing. The other player never chases/follows the player I am controlling and moving around.
Why are the players falling down when I set IsTrigger to true in my project?
I see in the video that the instructor is using a Maze Plane. Is that a package I should import in the Assets or is it already somewhere in the Assets? I just added regular Plane for now because I could not find a Maze Plane.
Here is a link for my project from my OneDrive. The file name is Demo AI.rar:
Project in OneDrive
Here is a link for the video tutorial I am attempting to follow. It is supposes to be simple I suppose:
Tutorial
Here is the BasicAi class I'm using in my project, the same script from the tutorial video:
using System.Collections;
using UnityStandardAssets.Characters.ThirdPerson;
public class BasicAi : MonoBehaviour {
public NavMeshAgent agent;
public ThirdPersonCharacter character;
public enum State {
PATROL,
CHASE
}
public State state;
private bool alive;
// Variables for patrolling
public GameObject[] waypoints;
private int waypointInd = 0;
public float patrolSpeed = 0.5f;
// Variable for chasing
public float chaseSpeed = 1f;
public GameObject target;
// Use this for initialization
void Start () {
agent = GetComponent<NavMeshAgent> ();
character = GetComponent<ThirdPersonCharacter>();
agent.updatePosition = true;
agent.updateRotation = false;
state = BasicAi.State.PATROL;
alive = true;
StartCoroutine ("FSM");
}
IEnumerator FSM()
{
while (alive)
{
switch (state)
{
case State.PATROL:
Patrol ();
break;
case State.CHASE:
Chase ();
break;
}
yield return null;
}
}
void Patrol()
{
agent.speed = patrolSpeed;
if (Vector3.Distance (this.transform.position, waypoints [waypointInd].transform.position) >= 2) {
agent.SetDestination (waypoints [waypointInd].transform.position);
character.Move (agent.desiredVelocity, false, false);
} else if (Vector3.Distance (this.transform.position, waypoints [waypointInd].transform.position) <= 2) {
waypointInd += 1;
if (waypointInd > waypoints.Length) {
waypointInd = 0;
}
}
else
{
character.Move (Vector3.zero, false, false);
}
}
void Chase()
{
agent.speed = chaseSpeed;
agent.SetDestination (target.transform.position);
character.Move (agent.desiredVelocity, false, false);
}
void OnTriggerEnter(Collider coll)
{
if (coll.tag == "Player")
{
state = BasicAi.State.CHASE;
target = coll.gameObject;
}
}
}
Once a collider is a trigger it no longer collides with objects, your best bet is to place a child object that has a collider and setting that to the trigger, this way the original collider will still collide with your ground.
As for your other question how are you referencing your third person character, are you dragging it from the scene into the inspector, and you also have to bake your navmesh into your scene. I haven't looked at your project as that would take a lot of time, but maybe go through the tutorial again and see how they reference the character. With the inbuilt characters you normally have to access the namespace first.

Use parameters for variable animation

I'd like to animate my Score-GUI text counting up to a variable value but there are two things in my way:
1: How can I animate to a variable instead of a fixed value?
2: Why can't I add own properties (like int) to my script and animate them?
For #2 I created a property in my script. Yet the editor won't show it in the AddProperty-dialog (as shown below):
public int currentScore = 0;
public int score {
get { return currentScore; }
set { this.currentScore += value; }
}
EDIT: The animator is set up in the most basic way:
Since you only have 1 Animation. An Animator is irrelevant to the solution. This is tested and working. Now you need to make the Animation a Legacy type to get this working because we are not going to use the Animator.
Click the Animation on the Project -> look at the upper right section of the Inspector view, there is a little button there which will drop down a selection. "Debug" then Check the Legacy.
Set your Animation to whatever you want. I force the WrapMode in the script to be wrap mode once. So it will only play once.
Now in the Animation Component make sure you select the Animation that you want by default or it wont work. Cause we only use anim.Play(); Without parameters meaning, run the default animation that is set.
I created a Text UI and added an Animation that alpha is 0 from the start and at the end point making it 1. You have to do that on your own.
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
public class MyScore : MonoBehaviour {
// Use this for initialization
public int currentScore = 0;
public GameObject Myscore; // Drag the GameObject that has the Animation for your score.
public Text myScoreText; //Drag in the Inspector the Text object to reference
public Animation anim;
public int score
{
get { return currentScore; }
set { this.currentScore += value; }
}
void Start()
{
anim = Myscore.GetComponent<Animation>(); // Reference the Animation Component.
anim.wrapMode = WrapMode.Once; // Legacy animation Set to play once
AddScore();
}
public void AddScore()
{
score += 10;
myScoreText.text = score.ToString();
anim.Play();
Debug.Log("Current Score is "+ score);
Invoke("AddScore", 2);
}
}
Good luck.

How to detect a collision between one object and multiple objects in XNA 4.0 C#?

I am new to XNA and CSharp programming so I want to learn to make a treasure hunting game as a beginning so I made a player(as a class) which can walk up, down, left and right. I made a Gem class also which the player can collide with and the gem disappears and a sound is played. But I want to make some walls that the player can collide with and stop so I made a class called Tile.cs (The wall class) and I made a void in it
public void CollideCheck(bool tWalk, bool bottomWalk, bool leftWalk, bool rightWalk, Rectangle topRect, Rectangle bottomRect, Rectangle rightRect, Rectangle leftRect)
{
colRect = new Rectangle((int)position.X, (int)position.Y, texture.Width, texture.Height);
if (this.colRect.Intersects(topRect))
{
tWalk = false;
}
else
tWalk = true;
if (this.colRect.Intersects(bottomRect))
{
bottomWalk = false;
}
else
bottomWalk = true;
if (this.colRect.Intersects(leftRect))
{
leftWalk = false;
}
else
leftWalk = true;
if (this.colRect.Intersects(rightRect))
{
rightWalk = false;
}
else
rightWalk = true;
}
Then, in the Game1.cs (The main Class) I made an array of "Tiles":
Tile[] tiles = new Tile[5];
And in the update void I made this:
foreach (Tile tile in tiles)
{
tile.CollideCheck(player.topWalk, player.bottomWalk, player.leftWalk, player.rightWalk,
new Rectangle((int)player.Position.X, (int)player.Position.Y - (int)player.Speed.Y, player.currentAnim.FrameWidth, player.currentAnim.FrameHeight),
new Rectangle((int)player.Position.X, (int)player.Position.Y + (int)player.Speed.Y, player.currentAnim.FrameWidth, player.currentAnim.FrameHeight),
new Rectangle((int)player.Position.X + (int)player.Speed.X, (int)player.Position.Y, player.currentAnim.FrameWidth, player.currentAnim.FrameHeight),
new Rectangle((int)player.Position.X - (int)player.Speed.X, (int)player.Position.Y, player.currentAnim.FrameWidth, player.currentAnim.FrameHeight));
}
All those rectangles are the borders of the player but when I run the game the player doesn't collide with it so is there any way to fix this?
I can post the project if I am not very clear.
Your parameters are in only, but you set their values inside the call. You have to declare them as out variables so that their value is sent back to the caller. Using out also makes sure you always set a value to them before exiting the function.
So change your function declaration to public void CollideCheck(out bool tWalk, out bool bottomWalk, out bool leftWalk, out bool rightWalk, Rectangle topRect, Rectangle bottomRect, Rectangle rightRect, Rectangle leftRect) and you get the values back.

Resources