Unity3D: How to show GUI.box if condition is true? - c#

I'm making a game in Unity3D with C#. I am using GUI.box to show a healthbar for the mobs, but I only want to show the GUI.box if there is a target.
This is my code at the moment.
public GameObject target;
public bool existsTarget;
// Use this for initialization
void Start()
{
PlayerAttack pa = (PlayerAttack)GetComponent("PlayerAttack");
target = pa.target;
existsTarget = false;
}
// Update is called once per frame
void Update()
{
if(target != null)
existsTarget = true;
else
existsTarget = false;
}
void OnGUI()
{
if(existsTarget)
GUI.Box(new Rect(500, 10, healthBarLength, 20), curHealth + "/" + maxHealth);
else {
GUI.Box(new Rect(Screen.width, 10, healthBarLength, 20), curHealth + "/" + maxHealth);
}
Unfortunately this doesn't show any healthbars at all. Any ideas as to why?
Posting the scripts here after popular demand.
public class Targetting : MonoBehaviour {
public List<Transform> targets;
public List<Transform> items;
public GameObject TheSelectedTarget {get; set;}
private Transform selectedTarget;
private Transform selectedItem;
private Transform myTransform;
// Use this for initialization
void Start () {
targets = new List<Transform>();
items = new List<Transform>();
selectedTarget = null;
selectedItem = null;
myTransform = transform;
TheSelectedTarget = null;
addAllEnemies();
addAllItems();
}
//adds all targets to a list
private void addAllEnemies() {
GameObject[] go = GameObject.FindGameObjectsWithTag("Enemy");
foreach(GameObject enemy in go){
addTarget(enemy.transform);
}
}
//adds a target
private void addTarget(Transform enemy) {
targets.Add(enemy);
}
//sorts target by distance
private void sortTargets() {
targets.Sort(delegate(Transform t1, Transform t2) {
return Vector3.Distance(t1.position, myTransform.position).CompareTo(Vector3.Distance(t2.position, myTransform.position));
});
}
//targets an enemy
private void targetEnemy() {
addAllEnemies();
if(selectedTarget == null) {
sortTargets();
selectedTarget = targets[0];
} else {
int index = targets.IndexOf(selectedTarget);
if(index < targets.Count -1) {
index++;
} else {
index = 0;
}
deselectTarget();
selectedTarget = targets[index];
}
selectTarget();
targets.Clear();
}
//selects a specific target, and colors it red
public void selectTarget() {
selectedTarget.renderer.material.color = Color.red;
PlayerAttack pa = (PlayerAttack)GetComponent("PlayerAttack");
pa.target = selectedTarget.gameObject;
TheSelectedTarget = pa.target;
}
//deselects the current selected target, and colors i grey
private void deselectTarget() {
selectedTarget.renderer.material.color = Color.gray;
selectedTarget = null;
}
//adds all items to a list
void addAllItems() {
GameObject[] go = GameObject.FindGameObjectsWithTag("Book");
foreach(GameObject book in go){
addItem(book.transform);
}
}
'
.... And then the script continues but without any relevance to this...
' public class EnemyHealth : MonoBehaviour
{
public string enemyName;
public int maxHealth = 100;
public int curHealth = 100;
public float healthBarLength;
public GameObject target;
public bool existsTarget;
public AudioSource dying;
// Use this for initialization
void Start()
{
//enemyName = this.enemyName;
healthBarLength = Screen.width / 3;
existsTarget = false;
}
// Update is called once per frame
void Update()
{
adjustCurHealth(0);
Targetting ta = (Targetting)GetComponent("Targetting");
target = ta.TheSelectedTarget;
Debug.Log (target);
if(target != null)
existsTarget = true;
else {
existsTarget = false;
}
}
void OnGUI()
{
if(existsTarget)
GUI.Box(new Rect(500, 10, healthBarLength, 20), curHealth + "/" + maxHealth);
else {
GUI.Box(new Rect(Screen.width, 10, healthBarLength, 20), curHealth + "/" + maxHealth);
}
}
public void adjustCurHealth(int adj)
{
curHealth += adj;
if (curHealth < 0)
curHealth = 0;
if (curHealth > 100)
curHealth = 100;
if (maxHealth < 0)
maxHealth = 1;
if(curHealth == 0)
{
//dying.Play ();
GameObject.Destroy(gameObject);
}
healthBarLength = (Screen.width / 3) * (curHealth / (float)maxHealth);
}
}

Are you ever setting the target anywhere other than the Start() method? The code you show will only ever show a GUI.box if the PlayerAttack.Target is not null at the start. Try moving this code to the Update() method.
PlayerAttack pa = (PlayerAttack)GetComponent("PlayerAttack");
target = pa.target;
Edit:
Check to see if the target is null, that could be the issue.
target = pa.target;
Debug.Log(target);
This will either print to the log as whatever GameObject it is, or null. If it's null, then there is no target.

Related

Unity C# script variable not changing in game when changed in script

Very new to Unity, I'm making a tactical RPG game similar to Fire Emblem. I've followed a tutorial on movement from this website and followed everything he did.
The player character can only move 5 tiles in the directions +z, -z, +x, -x on a 12x12 tile grid, however I want it to move 6. In the TacticsMove.cs script, there is this variable: public int move = 5; with the amount of the variable being how many tiles the player moves. I've changed the variable to public int move = 6; and saved the script, but everything is the exact same as before.
I want public int move = 6 to allow the player to move up to 6 tiles instead of 5. There are no comments on the tutorial or youtube videos of this happening so the next place im coming to is here. My code is below, I don't know if all of this is relevant. If you need me to add/remove something, tell me.
TacticsMove.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TacticsMove : MonoBehaviour
{
public bool turn = false;
List<Tile> selectableTiles = new List<Tile>();
GameObject[] tiles;
Stack<Tile> path = new Stack<Tile>();
Tile currentTile;
public bool moving = false;
public int move = 6;
public float jumpHeight = 2;
public float moveSpeed = 2;
public float jumpVelocity = 4.5f;
Vector3 velocity = new Vector3();
Vector3 heading = new Vector3();
float halfHeight = 0;
bool fallingDown = false;
bool jumpingUp = false;
bool movingEdge = false;
Vector3 jumpTarget;
public Tile actualTargetTile;
protected void Init()
{
tiles = GameObject.FindGameObjectsWithTag("Tile");
halfHeight = GetComponent<Collider>().bounds.extents.y;
TurnManager.AddUnit(this);
}
public void GetCurrentTile()
{
currentTile = GetTargetTile(gameObject);
currentTile.current = true;
}
public Tile GetTargetTile(GameObject target)
{
RaycastHit hit;
Tile tile = null;
if (Physics.Raycast(target.transform.position, -Vector3.up, out hit, 1))
{
tile = hit.collider.GetComponent<Tile>();
}
return tile;
}
public void ComputeAdjacencyLists(float jumpHeight, Tile target)
{
//tiles = GameObject.FindGameObjectsWithTag("Tile");
foreach (GameObject tile in tiles)
{
Tile t = tile.GetComponent<Tile>();
t.FindNeighbors(jumpHeight, target);
}
}
public void FindSelectableTiles()
{
ComputeAdjacencyLists(jumpHeight, null);
GetCurrentTile();
Queue<Tile> process = new Queue<Tile>();
process.Enqueue(currentTile);
currentTile.visited = true;
//currentTile.parent = ?? leave as null
while (process.Count > 0)
{
Tile t = process.Dequeue();
selectableTiles.Add(t);
t.selectable = true;
if (t.distance < move)
{
foreach (Tile tile in t.adjacencyList)
{
if (!tile.visited)
{
tile.parent = t;
tile.visited = true;
tile.distance = 1 + t.distance;
process.Enqueue(tile);
}
}
}
}
}
public void MoveToTile(Tile tile)
{
path.Clear();
tile.target = true;
moving = true;
Tile next = tile;
while (next != null)
{
path.Push(next);
next = next.parent;
}
}
public void Move()
{
if (path.Count > 0)
{
Tile t = path.Peek();
Vector3 target = t.transform.position;
//Calculate the unit's position on top of the target tile
target.y += halfHeight + t.GetComponent<Collider>().bounds.extents.y;
if (Vector3.Distance(transform.position, target) >= 0.05f)
{
bool jump = transform.position.y != target.y;
if (jump)
{
Jump(target);
}
else
{
CalculateHeading(target);
SetHorizotalVelocity();
}
//Locomotion
transform.forward = heading;
transform.position += velocity * Time.deltaTime;
}
else
{
//Tile center reached
transform.position = target;
path.Pop();
}
}
else
{
RemoveSelectableTiles();
moving = false;
TurnManager.EndTurn();
}
}
protected void RemoveSelectableTiles()
{
if (currentTile != null)
{
currentTile.current = false;
currentTile = null;
}
foreach (Tile tile in selectableTiles)
{
tile.Reset();
}
selectableTiles.Clear();
}
void CalculateHeading(Vector3 target)
{
heading = target - transform.position;
heading.Normalize();
}
void SetHorizotalVelocity()
{
velocity = heading * moveSpeed;
}
void Jump(Vector3 target)
{
if (fallingDown)
{
FallDownward(target);
}
else if (jumpingUp)
{
JumpUpward(target);
}
else if (movingEdge)
{
MoveToEdge();
}
else
{
PrepareJump(target);
}
}
void PrepareJump(Vector3 target)
{
float targetY = target.y;
target.y = transform.position.y;
CalculateHeading(target);
if (transform.position.y > targetY)
{
fallingDown = false;
jumpingUp = false;
movingEdge = true;
jumpTarget = transform.position + (target - transform.position) / 2.0f;
}
else
{
fallingDown = false;
jumpingUp = true;
movingEdge = false;
velocity = heading * moveSpeed / 3.0f;
float difference = targetY - transform.position.y;
velocity.y = jumpVelocity * (0.5f + difference / 2.0f);
}
}
void FallDownward(Vector3 target)
{
velocity += Physics.gravity * Time.deltaTime;
if (transform.position.y <= target.y)
{
fallingDown = false;
jumpingUp = false;
movingEdge = false;
Vector3 p = transform.position;
p.y = target.y;
transform.position = p;
velocity = new Vector3();
}
}
void JumpUpward(Vector3 target)
{
velocity += Physics.gravity * Time.deltaTime;
if (transform.position.y > target.y)
{
jumpingUp = false;
fallingDown = true;
}
}
void MoveToEdge()
{
if (Vector3.Distance(transform.position, jumpTarget) >= 0.05f)
{
SetHorizotalVelocity();
}
else
{
movingEdge = false;
fallingDown = true;
velocity /= 5.0f;
velocity.y = 1.5f;
}
}
protected Tile FindLowestF(List<Tile> list)
{
Tile lowest = list[0];
foreach (Tile t in list)
{
if (t.f < lowest.f)
{
lowest = t;
}
}
list.Remove(lowest);
return lowest;
}
protected Tile FindEndTile(Tile t)
{
Stack<Tile> tempPath = new Stack<Tile>();
Tile next = t.parent;
while (next != null)
{
tempPath.Push(next);
next = next.parent;
}
if (tempPath.Count <= move)
{
return t.parent;
}
Tile endTile = null;
for (int i = 0; i <= move; i++)
{
endTile = tempPath.Pop();
}
return endTile;
}
protected void FindPath(Tile target)
{
ComputeAdjacencyLists(jumpHeight, target);
GetCurrentTile();
List<Tile> openList = new List<Tile>();
List<Tile> closedList = new List<Tile>();
openList.Add(currentTile);
//currentTile.parent = ??
currentTile.h = Vector3.Distance(currentTile.transform.position, target.transform.position);
currentTile.f = currentTile.h;
while (openList.Count > 0)
{
Tile t = FindLowestF(openList);
closedList.Add(t);
if (t == target)
{
actualTargetTile = FindEndTile(t);
MoveToTile(actualTargetTile);
return;
}
foreach (Tile tile in t.adjacencyList)
{
if (closedList.Contains(tile))
{
//Do nothing, already processed
}
else if (openList.Contains(tile))
{
float tempG = t.g + Vector3.Distance(tile.transform.position, t.transform.position);
if (tempG < tile.g)
{
tile.parent = t;
tile.g = tempG;
tile.f = tile.g + tile.h;
}
}
else
{
tile.parent = t;
tile.g = t.g + Vector3.Distance(tile.transform.position, t.transform.position);
tile.h = Vector3.Distance(tile.transform.position, target.transform.position);
tile.f = tile.g + tile.h;
openList.Add(tile);
}
}
}
//todo - what do you do if there is no path to the target tile?
Debug.Log("Path not found");
}
public void BeginTurn()
{
turn = true;
}
public void EndTurn()
{
turn = false;
}
}
Tile.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Tile : MonoBehaviour
{
public bool walkable = true;
public bool current = false;
public bool target = false;
public bool selectable = false;
public List<Tile> adjacencyList = new List<Tile>();
//Needed BFS (breadth first search)
public bool visited = false;
public Tile parent = null;
public int distance = 0;
//For A*
public float f = 0;
public float g = 0;
public float h = 0;
// Use this for initialization
void Start ()
{
}
// Update is called once per frame
void Update ()
{
if (current)
{
GetComponent<Renderer>().material.color = Color.magenta;
}
else if (target)
{
GetComponent<Renderer>().material.color = Color.green;
}
else if (selectable)
{
GetComponent<Renderer>().material.color = Color.blue;
}
else
{
GetComponent<Renderer>().material.color = Color.white;
}
}
public void Reset()
{
adjacencyList.Clear();
current = false;
target = false;
selectable = false;
visited = false;
parent = null;
distance = 0;
f = g = h = 0;
}
public void FindNeighbors(float jumpHeight, Tile target)
{
Reset();
CheckTile(Vector3.forward, jumpHeight, target);
CheckTile(-Vector3.forward, jumpHeight, target);
CheckTile(Vector3.right, jumpHeight, target);
CheckTile(-Vector3.right, jumpHeight, target);
}
public void CheckTile(Vector3 direction, float jumpHeight, Tile target)
{
Vector3 halfExtents = new Vector3(0.25f, (1 + jumpHeight) / 2.0f, 0.25f);
Collider[] colliders = Physics.OverlapBox(transform.position + direction, halfExtents);
foreach (Collider item in colliders)
{
Tile tile = item.GetComponent<Tile>();
if (tile != null && tile.walkable)
{
RaycastHit hit;
if (!Physics.Raycast(tile.transform.position, Vector3.up, out hit, 1) || (tile == target))
{
adjacencyList.Add(tile);
}
}
}
}
}
PlayerMove.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMove : TacticsMove
{
// Use this for initialization
void Start ()
{
Init();
}
// Update is called once per frame
void Update ()
{
Debug.DrawRay(transform.position, transform.forward);
if (!turn)
{
return;
}
if (!moving)
{
FindSelectableTiles();
CheckMouse();
}
else
{
Move();
}
}
void CheckMouse()
{
if (Input.GetMouseButtonUp(0))
{
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
if (Physics.Raycast(ray, out hit))
{
if (hit.collider.tag == "Tile")
{
Tile t = hit.collider.GetComponent<Tile>();
if (t.selectable)
{
MoveToTile(t);
}
}
}
}
}
}
Im using unity version 2019.3.12f1.
Any help is appreciated.
As Etienne de Martel hints, Unity saves your public variables in the scene along with all the other GameObject/Component data, and restores that data on load
Field initializers are the default values for new components, they do not set the values for existing components even with a recompile.
I've been through this a few times myself.
From what I know, variables that have been serialized (which means it is visible in the inspector using [serialize] or it is set to public) will always overwrite scripts. This means that the moment u save ur script after u have create a variable and before u start the program, it can only be adjusted using the inspector

Start changing color again

So I have my control script, which changes color of the sprites. When I click onto the sprite it falls and stops changing color. On collision it checks whether the color is the same, then it teleports the sprite back up. So now my question is: How can I make it change the color again?
My color changer:
public class control : MonoBehaviour
{
public static bool m_isRunning = false;
public static bool loop = true;
public SpriteRenderer m_spriteRenderer;
private Rigidbody2D rb;
public static int random;
public static float loopdelay = 0f;
public static float intervalplayer = 1f; //interval
public static bool changecolorborder = true;
public static bool fall = false;
public static int gravity = 0;
public static bool transform1 = false;
private void Update()
{
random = Random.Range(1, 4);
if (fall)
{
rb.gravityScale = gravity;
}
if (transform1)
{
transform.position = transform.position + new Vector3(0.002f, 1.998f, 0);
}
if(Input.touchCount == 1)
{
Debug.Log("Helloo");
}
}
private void Start()
{
m_spriteRenderer = this.GetComponent<SpriteRenderer>();
rb = GetComponent<Rigidbody2D>();
StartCoroutine(Changecolor(0f));
}
private IEnumerator Changecolor(float loopdelay)
{
while (loop)
{
yield return new WaitForSeconds(intervalplayer);
if (loop)
{
if (random == 1)
{
Color newColor = new Color(0.68f, 0.63f, 0.76f);
m_spriteRenderer.color = newColor;
}
else if (random == 2)
{
Color newColor = new Color(0.89f, 0.25f, 0.23f);
m_spriteRenderer.color = newColor;
}
else if (random == 3)
{
Color newColor = new Color(0.68f, 0.88f, 0.33f);
m_spriteRenderer.color = newColor;
}
else
{
Color newColor = new Color(0.38f, 0.21f, 0.72f);
m_spriteRenderer.color = newColor;
}
}
}
}
private void OnMouseDown()
{
fall = true;
loop = !loop;
gravity = 1;
changecolorborder = !changecolorborder;
}
}
My collision checker:
public class collision : MonoBehaviour
{
public static int counter = 0;
public static float waitime = 1f;
public Rigidbody2D rb;
public void OnCollisionEnter2D(Collision2D collision)
{
Text textMy = GameObject.Find("Canvas/Text").GetComponent<Text>();
if (collision.gameObject.GetComponent<SpriteRenderer>().color != gameObject.GetComponent<SpriteRenderer>().color)
{
Destroy(collision.gameObject);
}
else
{
counter++;
textMy.text = counter.ToString();
control.gravity = 0;
StartCoroutine(waitfor());
}
}
IEnumerator waitfor()
{
yield return new WaitForSeconds(1);
control.transform1 = true;
yield return new WaitForSeconds(0.033f);
control.transform1 = false;
}
}
I guess reseting your values like in the beggining
fall = false;
loop = true;
gravity = 0;
changecolorborder = !changecolorborder;
And calling the coroutine again
StartCoroutine(Changecolor(0f));

Unity - Weird StackOverflow Exception thrown in output_log.txt after build

Today I'm coming to you because I have a weird StackOverflow Exception and do not know how to fix it at all...
First off, this seems to only happen on windows after I build the game.
This is what I see in the output_log.txt :
onMoneyChanged is being called! (4145)
UnityEngine.DebugLogHandler:Internal_Log(LogType, String, Object)
UnityEngine.DebugLogHandler:LogFormat(LogType, Object, String, Object[])
UnityEngine.Logger:Log(LogType, Object)
UnityEngine.Debug:Log(Object)
Player:set_Money(Int32) (at /Users/Name/Desktop/My Game/Assets/Scripts/Mobs/Player.cs:89)
Coin:OnPickup(ItemCollector) (at /Users/Name/Desktop/My Game/Assets/Scripts/Items/Coin.cs:12)
ItemCollector:Update() (at /Users/Name/Desktop/My Game/Assets/Scripts/Items/ItemCollector.cs:35)
(Filename: /Users/Name/Desktop/My Game/Assets/Scripts/Mobs/Player.cs Line: 89)
onMoneyChanged is being called! (4150)
UnityEngine.DebugLogHandler:Internal_Log(LogType, String, Object)
UnityEngine.DebugLogHandler:LogFormat(LogType, Object, String, Object[])
UnityEngine.Logger:Log(LogType, Object)
UnityEngine.Debug:Log(Object)
Player:set_Money(Int32) (at /Users/Name/Desktop/My Game/Assets/Scripts/Mobs/Player.cs:89)
Coin:OnPickup(ItemCollector) (at /Users/Name/Desktop/My Game/Assets/Scripts/Items/Coin.cs:12)
ItemCollector:Update() (at /Users/Name/Desktop/My Game/Assets/Scripts/Items/ItemCollector.cs:35)
(Filename: /Users/Name/Desktop/My Game/Assets/Scripts/Mobs/Player.cs Line: 89)
Uploading Crash Report
StackOverflowException: The requested operation caused a stack overflow.
at (wrapper delegate-invoke) System.Action:invoke_void__this__ ()
at (wrapper delegate-invoke) System.Action:invoke_void__this__ ()
at (wrapper delegate-invoke) System.Action:invoke_void__this__ ()
at (wrapper delegate-invoke) System.Action:invoke_void__this__ ()
at (wrapper delegate-invoke) System.Action:invoke_void__this__ ()
at (wrapper delegate-invoke) System.Action:invoke_void__this__ ()
at (wrapper delegate-invoke) System.Action:invoke_void__this__ ()
I have looked everywhere and can't seem to understand where it comes from. I might not be seeing something very simple...
Here is the player script:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Xml.Linq;
using UnityEngine;
using UnityEngine.Events;
using PixelUtilities;
public class Player : Mob, IUpgradable, IXmlSerializable {
#region Static Section
private static readonly AnimationParameter Skill2SpeedId = "Skill 2 Speed";
private static readonly string[] AttackAxisNames = new string[] {
null,
"Attack1",
"Attack2",
"Attack3"
};
//It seems this must be longer in duration than the transition into the attack state, due to the potential transition interruption sources!
private const float AttackUnjoggableTime = 0.65f;
#endregion
[Header("Player")]
[SerializeField] private float skill2Speed = 1;
[SerializeField] private Transform groundCheck;
[SerializeField] private float groundCheckRadius = 0.25f;
[SerializeField] private LayerMask groundLayers;
[SerializeField] private bool isGrounded;
[SerializeField] GameObject weaponSpecial;
private new Rigidbody2D rigidbody;
private new BoxCollider2D collider;
private float horizontal;
private float smoothedHorizontal;
private Vector3 velocity;
private int superCharge; //Represents the number of enemies defeated that counts towards allowing the player to use their super attack.
private bool canIncreaseSuperCharge = true;
private bool canSuperSmash;
private int money = 0;
//private int roundMoney = 0;
private int[] levels = new int[2];
//DO NOT show in the inspector. That will make it changeable without actually updating the data
//that needs to change based based on this upgradeLevel.
private int baseDamage;
private float timeLastAttacked;
public event Action onMoneyChanged;
public bool CanSuperSmash {
get { return canSuperSmash; }
set {
//Prevent from redundant setting, because we'll need to know
//just when the value changed from false to true
if (canSuperSmash == value)
return;
canSuperSmash = value;
weaponSpecial.SetActive(value);
if (value)
superCharge = GameManager.Mage.SpecialEnemyCount;
}
}
public BoxCollider2D Collider {
get { return collider; }
}
public int SuperCharge {
get { return superCharge; }
}
public int LevelCount {
get { return levels.Length; }
}
public int Money {
get { return money; }
set {
if (GameManager.IsDebugMode)
Debug.Log("Setting the player's money from " + money + " to " + value + ".");
money = value;
Debug.Log("onMoneyChanged is being called! (" + money + ")");
if (onMoneyChanged != null)
onMoneyChanged();
}
}
//public int RoundMoney {
// get { return roundMoney; }
// set {
// roundMoney = value;
// Debug.Log("roundMoney has been set to " + roundMoney + ".");
// }
//}
public override void Reset() {
base.Reset();
groundLayers = LayerMask.GetMask("Ground");
}
public override void Awake() {
base.Awake();
collider = GetComponentInChildren<BoxCollider2D>();
HPStatus.onDeath += OnDeath;
baseDamage = StandTallCurves.GetNthStepInEnemyHealthCurve(0) / 2;
}
public override void Start() {
rigidbody = GetComponent<Rigidbody2D>();
}
public int GetLevel(int levelIndex) {
return levels[levelIndex];
}
public void SetLevel(int levelIndex, int value) {
value = Mathf.Max(0, value);
levels[levelIndex] = value;
switch (levelIndex) {
case 0:
baseDamage = StandTallCurves.GetNthStepInEnemyHealthCurve(value) / 2;
break;
case 1:
HPStatus.HP = HPStatus.MaxHP = StandTallCurves.GetNthStepInEnemyHealthCurve(value);
break;
}
}
public override void StartAttack(int attackNumber) {
base.StartAttack(attackNumber);
timeLastAttacked = Time.time;
}
protected override void OnUpdate() {
isGrounded = Physics2D.OverlapCircle(groundCheck.position, groundCheckRadius, groundLayers);
if (CanPerformActions)
AcceptAttackInput();
AcceptMovementInput();
//AcceptJumpInput();
//AcceptRotationalInput();
if (GameManager.IsDeveloperMode) {
if (Input.GetKeyDown(KeyCode.C)) {
Money += 1000;
}
if (Input.GetKeyDown(KeyCode.Y)) {
CanSuperSmash = true;
}
if (Input.GetKeyDown(KeyCode.T) && (Input.GetKey(KeyCode.LeftControl) || Input.GetKey(KeyCode.LeftCommand))) {
Time.timeScale = (Time.timeScale == 1) ? 5 : 1;
}
}
}
private void AcceptMovementInput() {
horizontal = hInput.GetAxis("Horizontal");
//smoothedHorizontal = Input.GetAxis("Horizontal");
velocity = rigidbody.velocity;
velocity.x = Mathf.Sign(horizontal) * FinalMovementSpeed;
rigidbody.velocity = velocity;
//Section for updating their rotation
if (horizontal < 0) {
Quaternion newRotation = transform.rotation;
newRotation.y = 180;
transform.rotation = newRotation;
}
if (horizontal > 0) {
Quaternion newRotation = transform.rotation;
newRotation.y = 0;
transform.rotation = newRotation;
}
}
private void AcceptAttackInput() {
for (int i = 1; i <= 2; i++) {
if (hInput.GetButtonDown(AttackAxisNames[i])) {
StartAttack(i);
return;
}
}
//Attack 3 is special for the player -- their super smash -- and is handled differently.
if (hInput.GetButtonDown(AttackAxisNames[3])) {
if (canSuperSmash) {
StartSuperSmash();
} else {
if (GameManager.IsDebugMode) {
Debug.Log("Attempted to super smash, but " + name + " was unable to super smash!");
}
}
}
}
protected override float CalculateFinalMovementSpeed() {
float finalMovementSpeed = Mathf.Abs(horizontal) * MoveSettings.MoveSpeed;
finalMovementSpeed *= MovementFactor;
return finalMovementSpeed;
}
protected override void UpdateContinuousAnimatorParameters() {
animator.SetBool(Animations.IsMovingId, Time.time - timeLastAttacked > AttackUnjoggableTime && Mathf.Abs(horizontal) > 0.08f && Mathf.Abs(velocity.x) > 0.08f);
//animator.SetFloat(Skill2SpeedId, skill2Speed);
}
/* Uncomment to enable jumping
private void AcceptJumpInput() {
if (Input.GetButtonDown("Jump") && isGrounded) {
rigidbody.velocity = new Vector3(rigidbody.velocity.x, JumpFactor * MoveSettings.JumpSpeed, 0);
if (JumpFactor > 0)
animator.SetTrigger(JumpId);
}
}*/
/// <summary>
/// This tells the whether or not the super charge count can be increased.
/// </summary>
public void SetSuperChargeActive(bool value) {
canIncreaseSuperCharge = value;
}
public bool GainSuperCharge() {
return GainSuperCharge(1);
}
public bool GainSuperCharge(int amount) {
//If they're already charged up, then don't allow superCharge to increment
if (!GameManager.Mage.gameObject.activeSelf || !canIncreaseSuperCharge || canSuperSmash)
return false;
superCharge = Mathf.Clamp(superCharge + amount, 0, GameManager.Mage.SpecialEnemyCount);
if (superCharge == GameManager.Mage.SpecialEnemyCount) {
CanSuperSmash = true; //Important to call the C# property here, NOT directly access the field, "canSuperSmash".
}
return true;
}
private void StartSuperSmash() {
SetSuperChargeActive(false);
CanSuperSmash = false;
StartCoroutine(AttackAfterDelay(3, 0)); //0 was initially 0.8f;
}
public void ClearSuperCharge() {
if (GameManager.IsDebugMode)
Debug.Log("superCharge set to 0!");
superCharge = 0;
}
private IEnumerator AttackAfterDelay(int attackNumber, float initialDelay) {
if (initialDelay > 0)
yield return new WaitForSeconds(initialDelay);
StartAttack(attackNumber);
}
public override void OnDrawGizmosSelected() {
base.OnDrawGizmosSelected();
if (groundCheck != null) {
Gizmos.color = new Color(0.6f, 1, 0, 1);
Gizmos.DrawWireSphere(groundCheck.position, groundCheckRadius);
}
attackChecker.DrawGizmos(Color.red);
}
private void InstantKillAllInView() {
Camera camera = Camera.main;
Vector3 cameraPos = camera.transform.position;
float height = 2 * camera.orthographicSize;
float width = height * camera.aspect; //h * (w/h) = w
RaycastHit2D[] hits = Physics2D.BoxCastAll((Vector2) cameraPos, new Vector2(width, height), 0, Vector2.right, 0.01f, enemyLayers, -0.01f, 0.01f);
for (int i = 0; i < hits.Length; i++) {
Mob target = hits[i].transform.GetComponent<Mob>();
if (target == null)
continue;
target.InstantSuperKill(this);
}
}
public void DamageOthersInRangeFromPlayer() {
DamageOthersInRange(baseDamage);
}
private void OnDeath(DamageInfo finalDamage) {
GameManager.StartGameOverScreen();
}
public void Load(XElement element) {
if (element == null)
return;
int intValue;
XElement child = element.Element("Money");
if (child != null && int.TryParse(child.Value, out intValue))
Money = intValue;
child = element.Element("HealthUpgrade");
if (child != null) {
//Old serialized layout
//if (int.TryParse(child.Value, out intValue))
// HealthUpgradeLevel = intValue;
//child = element.Element("DamageUpgrade");
//if (child != null && int.TryParse(child.Value, out intValue))
// DamageUpgradeLevel = intValue;
} else {
//New serialized layout
child = element.Element("Levels");
if (child != null)
LoadLevels(child, ref levels);
}
}
public XElement Save() {
XElement element = new XElement(GetType().Name);
element.Add(new XElement("Money", money));
//e.Add(new XElement("HealthUpgrade", healthUpgradeLevel));
//e.Add(new XElement("DamageUpgrade", damageUpgradeLevel));
element.Add(SaveLevels(ref levels));
return element;
}
#region Public Animator Methods
public void AnimatorAllowSuperSmashToRestart() {
ClearSuperCharge();
SetSuperChargeActive(true);
}
#endregion
}
Here is the Coin script:
using UnityEngine;
[RequireComponent(typeof(Rigidbody2D))]
public class Coin : MonoBehaviour, IItem {
[SerializeField] private int moneyAmount = 5;
public void OnValidate() {
moneyAmount = Mathf.Max(0, moneyAmount);
}
public void OnPickup(ItemCollector collector) {
collector.Owner.Money += moneyAmount;
//collector.Owner.RoundMoney += moneyAmount;
}
}
And finally, the itemCollector script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ItemCollector : MonoBehaviour {
[SerializeField] private float radius = 0.5f;
[SerializeField] private LayerMask itemMask;
private Player owner;
private Collider2D[] results = new Collider2D[16];
private int resultsCount;
public Player Owner {
get { return owner; }
}
public void Awake() {
owner = GetComponentInParent<Player>();
if (owner == null) {
if (GameManager.IsDebugMode) {
Debug.LogError(" require a " + typeof(Player).Name + " to be in a parent!" +
"\nThe " + GetType().Name + " will be destroyed, as it would not be able to function.");
}
DestroyImmediate(gameObject);
}
}
public void Update() {
resultsCount = Physics2D.OverlapCircleNonAlloc(transform.position, radius, results, itemMask);
for (int i = 0; i < resultsCount; i++) {
IItem item = results[i].GetComponent<IItem>();
if (item != null) {
MonoBehaviour m = item as MonoBehaviour;
if (m != null && m.enabled) {
item.OnPickup(this);
m.enabled = false;
GameObject.Destroy(m.gameObject);
}
}
}
}
public void OnDrawGizmosSelected() {
Gizmos.DrawWireSphere(transform.position, radius);
}
}
Thank you in advance for you help.
Regards!
For anyone who has a problem like that.
I fixed the problem. I had a .onMoneyChanged in an update function that was making the game crash.
I moved it to the onEnable and onDisable method and now it works just fine.

Unity - Physics.OverlapSphere is not detecting instantiated GameObjects

I am having a problem with my RTS game where my enemy units will not attack any base buildings I create after the level starts. They go to attack every other building that was there when the level starts, but none of the built ones.
There is a list being set up of the closest targets to units and they will go to attack their closest target, but any newly instantiated buildings or units, don't get attacked for some reason.
The function DecideWhatToDo() is called on all units in the WorldObject script when they are not doing anything. It then calls FindNearbyObjects() from the WorkManager script.
Everything works up until new units and buildings are created, has anyone experienced this kind of problem before?
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
using RTS;
public class WorldObject : MonoBehaviour {
BoxCollider boxCollider;
bool isDead;
bool isSinking;
public string objectName;
public Texture2D buildImage;
public int cost, sellValue, maxHitPoints;
public float hitPoints;
public virtual bool IsActive { get { return true; } }
public float weaponRange = 10.0f;
public float weaponRechargeTime = 1.0f;
public float weaponAimSpeed = 1.0f;
public AudioClip attackSound, selectSound, useWeaponSound;
public float attackVolume = 1.0f, selectVolume = 1.0f, useWeaponVolume = 1.0f;
public int ObjectId { get; set; }
public float detectionRange = 20.0f;
public GameObject explosionPrefab, splat;
protected NavMeshAgent agent;
protected AudioElement audioElement;
protected Animator anim;
protected List<WorldObject> nearbyObjects;
protected Rect playingArea = new Rect(0.0f, 0.0f, 0.0f, 0.0f);
protected Player player;
protected string[] actions = { };
protected bool currentlySelected = false;
protected Bounds selectionBounds;
protected GUIStyle healthStyle = new GUIStyle();
protected float healthPercentage = 1.0f;
protected WorldObject target = null;
protected bool attacking = false;
protected bool movingIntoPosition = false;
protected bool aiming = false;
private List<Material> oldMaterials = new List<Material>();
private float currentWeaponChargeTime;
//we want to restrict how many decisions are made to help with game performance
//the default time at the moment is a tenth of a second
private float timeSinceLastDecision = 0.0f, timeBetweenDecisions = 0.1f;
protected virtual void Awake()
{
anim = GetComponent<Animator>();
boxCollider = GetComponent<BoxCollider>();
selectionBounds = ResourceManager.InvalidBounds;
CalculateBounds();
}
protected virtual void Start()
{
agent = GetComponent<NavMeshAgent>();
SetPlayer();
if (player) SetTeamColor();
InitialiseAudio();
}
protected virtual void Update()
{
if (isSinking)
{
this.transform.Translate(-Vector3.up * 2.5f * Time.deltaTime);
}
if (ShouldMakeDecision()) DecideWhatToDo();
currentWeaponChargeTime += Time.deltaTime;
if (attacking && !movingIntoPosition && !aiming)
{
PerformAttack();
}
}
/**
* A child class should only determine other conditions under which a decision should
* not be made. This could be 'harvesting' for a harvester, for example. Alternatively,
* an object that never has to make decisions could just return false.
*/
protected virtual bool ShouldMakeDecision()
{
if (!attacking && !movingIntoPosition && !aiming)
{
//we are not doing anything at the moment
if (timeSinceLastDecision > timeBetweenDecisions)
{
timeSinceLastDecision = 0.0f;
Debug.Log("");
return true;
}
timeSinceLastDecision += Time.deltaTime;
}
return false;
}
protected virtual void DecideWhatToDo()
{
//determine what should be done by the world object at the current point in time
Vector3 currentPosition = transform.position;
nearbyObjects = WorkManager.FindNearbyObjects(currentPosition, detectionRange);
if (CanAttack())
{
List<WorldObject> enemyObjects = new List<WorldObject>();
foreach (WorldObject nearbyObject in nearbyObjects)
{
Resource resource = nearbyObject.GetComponent<Resource>();
if (resource) continue;
if (nearbyObject.GetPlayer() != player) enemyObjects.Add(nearbyObject);
}
WorldObject closestObject = WorkManager.FindNearestWorldObjectInListToPosition(enemyObjects, currentPosition);
if (closestObject)
{
attacking = true;
//agent.isStopped = true;
BeginAttack(closestObject);
}
}
}
public Player GetPlayer()
{
return player;
}
protected virtual void OnGUI()
{
if (currentlySelected && !ResourceManager.MenuOpen) DrawSelection();
}
protected virtual void InitialiseAudio()
{
List<AudioClip> sounds = new List<AudioClip>();
List<float> volumes = new List<float>();
if (attackVolume < 0.0f) attackVolume = 0.0f;
if (attackVolume > 1.0f) attackVolume = 1.0f;
sounds.Add(attackSound);
volumes.Add(attackVolume);
if (selectVolume < 0.0f) selectVolume = 0.0f;
if (selectVolume > 1.0f) selectVolume = 1.0f;
sounds.Add(selectSound);
volumes.Add(selectVolume);
if (useWeaponVolume < 0.0f) useWeaponVolume = 0.0f;
if (useWeaponVolume > 1.0f) useWeaponVolume = 1.0f;
sounds.Add(useWeaponSound);
volumes.Add(useWeaponVolume);
audioElement = new AudioElement(sounds, volumes, objectName + ObjectId, this.transform);
}
public void SetPlayer()
{
player = transform.root.GetComponentInChildren<Player>();
}
public bool IsOwnedBy(Player owner)
{
if (player && player.Equals(owner))
{
return true;
}
else
{
return false;
}
}
public void CalculateBounds()
{
selectionBounds = new Bounds(transform.position, Vector3.zero);
foreach (Renderer r in GetComponentsInChildren<Renderer>())
{
selectionBounds.Encapsulate(r.bounds);
}
}
//!!!!!MULTI SELECTION!!!!!
public virtual void SetSelection(bool selected, Rect playingArea)
{
currentlySelected = selected;
if (selected)
{
if (audioElement != null) audioElement.Play(selectSound);
this.playingArea = playingArea;
}
CalculateBounds();
}
//!!!!!MULTI SELECTION!!!!!
public Bounds GetSelectionBounds()
{
return selectionBounds;
}
public string[] GetActions()
{
return actions;
}
public void SetColliders(bool enabled)
{
Collider[] colliders = GetComponentsInChildren<Collider>();
foreach (Collider collider in colliders) collider.enabled = enabled;
}
public void SetTransparentMaterial(Material material, bool storeExistingMaterial)
{
if (storeExistingMaterial) oldMaterials.Clear();
Renderer[] renderers = GetComponentsInChildren<Renderer>();
foreach (Renderer renderer in renderers)
{
if (storeExistingMaterial) oldMaterials.Add(renderer.material);
renderer.material = material;
}
}
public void RestoreMaterials()
{
Renderer[] renderers = GetComponentsInChildren<Renderer>();
if (oldMaterials.Count == renderers.Length)
{
for (int i = 0; i < renderers.Length; i++)
{
renderers[i].material = oldMaterials[i];
}
}
}
public void SetPlayingArea(Rect playingArea)
{
this.playingArea = playingArea;
}
public virtual void SetHoverState(GameObject hoverObject)
{
//only handle input if owned by a human player and currently selected
if (player && player.human && currentlySelected)
{
//something other than the ground is being hovered over
if (hoverObject.name != "Ground")
{
Player owner = hoverObject.transform.root.GetComponent<Player>();
Unit unit = hoverObject.transform.parent.GetComponent<Unit>();
Building building = hoverObject.transform.parent.GetComponent<Building>();
if (owner)
{ //the object is owned by a player
if (owner.username == player.username) player.hud.SetCursorState(CursorState.Select);
else if (CanAttack()) player.hud.SetCursorState(CursorState.Attack);
else player.hud.SetCursorState(CursorState.Select);
}
else if (unit || building && CanAttack()) player.hud.SetCursorState(CursorState.Attack);
else player.hud.SetCursorState(CursorState.Select);
}
}
}
public virtual bool CanAttack()
{
//default behaviour needs to be overidden by children
return false;
}
public virtual void PerformAction(string actionToPerform)
{
//it is up to children with specific actions to determine what to do with each of those actions
}
public virtual void MouseClick(GameObject hitObject, Vector3 hitPoint, Player controller)
{
//only handle input if currently selected
if (currentlySelected && hitObject && hitObject.name != "Ground")
{
WorldObject worldObject = hitObject.transform.parent.GetComponent<WorldObject>();
//clicked on another selectable object
if (worldObject)
{
Resource resource = hitObject.transform.parent.GetComponent<Resource>();
if (resource && resource.isEmpty()) return;
Player owner = hitObject.transform.root.GetComponent<Player>();
if (owner)
{ //the object is controlled by a player
if (player && player.human)
{ //this object is controlled by a human player
//start attack if object is not owned by the same player and this object can attack, else select
if (player.username != owner.username && CanAttack())
{
BeginAttack(worldObject);
}
else ChangeSelection(worldObject, controller);
}
else ChangeSelection(worldObject, controller);
}
else ChangeSelection(worldObject, controller);
}
}
}
protected virtual void BeginAttack(WorldObject target)
{
//if (audioElement != null) audioElement.Play(attackSound);
this.target = target;
if (TargetInRange())
{
anim.SetBool("Attacking", true);
attacking = true;
PerformAttack();
}
else AdjustPosition();
}
protected void SetTeamColor()
{
TeamColor[] teamColors = GetComponentsInChildren<TeamColor>();
foreach (TeamColor teamColor in teamColors) teamColor.GetComponent<Renderer>().material.color = player.teamColor;
}
protected virtual void DrawSelectionBox(Rect selectBox)
{
GUI.Box(selectBox, "");
CalculateCurrentHealth(0.35f, 0.65f);
DrawHealthBar(selectBox, "");
}
protected virtual void CalculateCurrentHealth(float lowSplit, float highSplit)
{
healthPercentage = (float)hitPoints / (float)maxHitPoints;
if (healthPercentage > highSplit) healthStyle.normal.background = ResourceManager.HealthyTexture;
else if (healthPercentage > lowSplit) healthStyle.normal.background = ResourceManager.DamagedTexture;
else healthStyle.normal.background = ResourceManager.CriticalTexture;
}
protected void DrawHealthBar(Rect selectBox, string label)
{
healthStyle.padding.top = -20;
healthStyle.fontStyle = FontStyle.Bold;
GUI.Label(new Rect(selectBox.x, selectBox.y - 7, selectBox.width * healthPercentage, 5), label, healthStyle);
}
protected virtual void AimAtTarget()
{
aiming = true;
//this behaviour needs to be specified by a specific object
}
private void ChangeSelection(WorldObject worldObject, Player controller)
{
//this should be called by the following line, but there is an outside chance it will not
SetSelection(false, playingArea);
if (controller.SelectedObject) controller.SelectedObject.SetSelection(false, playingArea);
controller.SelectedObject = worldObject;
worldObject.SetSelection(true, controller.hud.GetPlayingArea());
}
private void DrawSelection()
{
GUI.skin = ResourceManager.SelectBoxSkin;
Rect selectBox = WorkManager.CalculateSelectionBox(selectionBounds, playingArea);
//Draw the selection box around the currently selected object, within the bounds of the playing area
GUI.BeginGroup(playingArea);
DrawSelectionBox(selectBox);
GUI.EndGroup();
}
private bool TargetInRange()
{
Vector3 targetLocation = target.transform.position;
Vector3 direction = targetLocation - transform.position;
if (direction.sqrMagnitude < weaponRange * weaponRange)
{
return true;
}
return false;
}
private void AdjustPosition()
{
Unit self = this as Unit;
if (self)
{
movingIntoPosition = true;
Vector3 attackPosition = FindNearestAttackPosition();
self.StartMove(attackPosition);
attacking = true;
}
else
{
attacking = false;
}
}
private Vector3 FindNearestAttackPosition()
{
Vector3 targetLocation = target.transform.position;
Vector3 direction = targetLocation - transform.position;
float targetDistance = direction.magnitude;
float distanceToTravel = targetDistance - (0.9f * weaponRange);
return Vector3.Lerp(transform.position, targetLocation, distanceToTravel / targetDistance);
}
private void PerformAttack()
{
if (!target)
{
attacking = false;
anim.SetBool("Attacking", false);
anim.SetBool("IsRunning", false);
return;
}
if (!TargetInRange())
{
AdjustPosition();
}
else if (!TargetInFrontOfWeapon())
{
AimAtTarget();
}
else if (ReadyToFire())
{
//attacking = true;
UseWeapon();
}
//if (TargetInRange() && (attacking = true))
//{
// AdjustPosition();
//}
}
private bool TargetInFrontOfWeapon()
{
Vector3 targetLocation = target.transform.position;
Vector3 direction = targetLocation - transform.position;
if (direction.normalized == transform.forward.normalized) return true;
else return false;
}
private bool ReadyToFire()
{
if (currentWeaponChargeTime >= weaponRechargeTime)
{
return true;
}
return false;
}
protected virtual void UseWeapon()
{
if (audioElement != null && Time.timeScale > 0) audioElement.Play(useWeaponSound);
currentWeaponChargeTime = 0.0f;
//this behaviour needs to be specified by a specific object
}
public void TakeDamage(float damage)
{
//GameObject.Instantiate(impactVisual, target.transform.position, Quaternion.identity);
hitPoints -= damage;
if (hitPoints <= 0)
{
Instantiate(explosionPrefab, transform.position + new Vector3(0, 5, 0), Quaternion.identity);
Instantiate(splat, transform.position, Quaternion.identity);
Destroy(gameObject);
}
}
}
using UnityEngine;
using System.Collections.Generic;
namespace RTS
{
public static class WorkManager
{
public static Rect CalculateSelectionBox(Bounds selectionBounds, Rect playingArea)
{
//shorthand for the coordinates of the centre of the selection bounds
float cx = selectionBounds.center.x;
float cy = selectionBounds.center.y;
float cz = selectionBounds.center.z;
//shorthand for the coordinates of the extents of the selection bounds
float ex = selectionBounds.extents.x;
float ey = selectionBounds.extents.y;
float ez = selectionBounds.extents.z;
//Determine the screen coordinates for the corners of the selection bounds
List<Vector3> corners = new List<Vector3>();
corners.Add(Camera.main.WorldToScreenPoint(new Vector3(cx + ex, cy + ey, cz + ez)));
corners.Add(Camera.main.WorldToScreenPoint(new Vector3(cx + ex, cy + ey, cz - ez)));
corners.Add(Camera.main.WorldToScreenPoint(new Vector3(cx + ex, cy - ey, cz + ez)));
corners.Add(Camera.main.WorldToScreenPoint(new Vector3(cx - ex, cy + ey, cz + ez)));
corners.Add(Camera.main.WorldToScreenPoint(new Vector3(cx + ex, cy - ey, cz - ez)));
corners.Add(Camera.main.WorldToScreenPoint(new Vector3(cx - ex, cy - ey, cz + ez)));
corners.Add(Camera.main.WorldToScreenPoint(new Vector3(cx - ex, cy + ey, cz - ez)));
corners.Add(Camera.main.WorldToScreenPoint(new Vector3(cx - ex, cy - ey, cz - ez)));
//Determine the bounds on screen for the selection bounds
Bounds screenBounds = new Bounds(corners[0], Vector3.zero);
for (int i = 1; i < corners.Count; i++)
{
screenBounds.Encapsulate(corners[i]);
}
//Screen coordinates start in the bottom left corner, rather than the top left corner
//this correction is needed to make sure the selection box is drawn in the correct place
float selectBoxTop = playingArea.height - (screenBounds.center.y + screenBounds.extents.y);
float selectBoxLeft = screenBounds.center.x - screenBounds.extents.x;
float selectBoxWidth = 2 * screenBounds.extents.x;
float selectBoxHeight = 2 * screenBounds.extents.y;
return new Rect(selectBoxLeft, selectBoxTop, selectBoxWidth, selectBoxHeight);
}
public static GameObject FindHitObject(Vector3 origin)
{
Ray ray = Camera.main.ScreenPointToRay(origin);
RaycastHit hit;
if (Physics.Raycast(ray, out hit, ResourceManager.RayCastLimit)) return hit.collider.gameObject;
return null;
}
public static Vector3 FindHitPoint(Vector3 origin)
{
Ray ray = Camera.main.ScreenPointToRay(origin);
RaycastHit hit;
Debug.DrawRay(ray.origin, ray.direction * ResourceManager.RayCastLimit, Color.yellow);
if (Physics.Raycast(ray, out hit, ResourceManager.RayCastLimit)) return hit.point;
return ResourceManager.InvalidPosition;
}
public static List<WorldObject> FindNearbyObjects(Vector3 position, float range)
{
Collider[] hitColliders = Physics.OverlapSphere(position, range);
HashSet<int> nearbyObjectIds = new HashSet<int>();
List<WorldObject> nearbyObjects = new List<WorldObject>();
for (int i = 0; i < hitColliders.Length; i++)
{
Transform parent = hitColliders[i].transform.parent;
if (parent)
{
WorldObject parentObject = parent.GetComponent<WorldObject>();
if (parentObject && !nearbyObjectIds.Contains(parentObject.ObjectId))
{
nearbyObjectIds.Add (parentObject.ObjectId);
nearbyObjects.Add (parentObject);
}
}
}
return nearbyObjects;
}
public static WorldObject FindNearestWorldObjectInListToPosition(List<WorldObject> objects, Vector3 position)
{
if (objects == null || objects.Count == 0) return null;
WorldObject nearestObject = objects[0];
float sqrDistanceToNearestObject = Vector3.SqrMagnitude(position - nearestObject.transform.position);
for (int i = 1; i < objects.Count; i++)
{
float sqrDistanceToObject = Vector3.SqrMagnitude(position - objects[i].transform.position);
if (sqrDistanceToObject < sqrDistanceToNearestObject)
{
sqrDistanceToNearestObject = sqrDistanceToObject;
nearestObject = objects[i];
}
}
return nearestObject;
}
}
}
The first thing you need to check is if inside
FindNearbyObjects()
The variable
hitColliders = Physics.OverlapSphere(position, range);
Changes it's size when you instantiate new buildings. In case that is not the case, it may be because you are not adding colliders to the buildings when you instantiate them.
However, I think there are better ways for you to detect buildings without using this Physics.OverlapSphere(), which may be expensive in performance. If I were you I will would give a special tag to the buildings (the original and the instantiated ones) and I will use that in my logic to detect them. So they will be potential targets in your method:
DecideWhatToDo()
Here you can read about how to tag the GameObjects:
https://docs.unity3d.com/Manual/Tags.html

Unity HTC VIVE Teleportation

I am developing for the HTC VIVE and am trying to create a teleportation script that would allow the user to teleport to a certain location (predefined by me) when the user grabs a certain object. I currently have a teleportation code that works like a normal teleporter where the user points at a location and the room is moved to that location. I have modified this so that no matter where the user is pointing they will always teleport to the specific location. This is a first step but I am really looking to trigger this teleportation when the user picks up a certain object, does anyone have any ideas on where to star or how to do this?
Here is the code for the modified teleporter:
namespace VRTK{
using UnityEngine;
using System.Collections;
public delegate void TeleportEventHandler(object sender, DestinationMarkerEventArgs e);
public class VRTK_BasicTeleport : MonoBehaviour
{
public float blinkTransitionSpeed = 0.6f;
[Range(0f, 32f)]
public float distanceBlinkDelay = 0f;
public bool headsetPositionCompensation = true;
public string ignoreTargetWithTagOrClass;
public bool limitToNavMesh = false;
public event TeleportEventHandler Teleporting;
public event TeleportEventHandler Teleported;
protected Transform eyeCamera;
protected bool adjustYForTerrain = false;
protected bool enableTeleport = true;
private float blinkPause = 0f;
private float fadeInTime = 0f;
private float maxBlinkTransitionSpeed = 1.5f;
private float maxBlinkDistance = 33f;
public void InitDestinationSetListener(GameObject markerMaker)
{
if (markerMaker)
{
foreach (var worldMarker in markerMaker.GetComponents<VRTK_DestinationMarker>())
{
worldMarker.DestinationMarkerSet += new DestinationMarkerEventHandler(DoTeleport);
worldMarker.SetInvalidTarget(ignoreTargetWithTagOrClass);
worldMarker.SetNavMeshCheck(limitToNavMesh);
worldMarker.SetHeadsetPositionCompensation(headsetPositionCompensation);
}
}
}
protected virtual void Start()
{
Utilities.SetPlayerObject(this.gameObject, VRTK_PlayerObject.ObjectTypes.CameraRig);
adjustYForTerrain = false;
eyeCamera = Utilities.AddCameraFade();
InitDestinationMarkerListeners();
InitHeadsetCollisionListener();
enableTeleport = true;
}
protected void OnTeleporting(object sender, DestinationMarkerEventArgs e)
{
if (Teleporting != null)
Teleporting(this, e);
}
protected void OnTeleported(object sender, DestinationMarkerEventArgs e)
{
if (Teleported != null)
Teleported(this, e);
}
protected virtual void Blink(float transitionSpeed)
{
fadeInTime = transitionSpeed;
SteamVR_Fade.Start(Color.black, 0);
Invoke("ReleaseBlink", blinkPause);
}
protected virtual bool ValidLocation(Transform target)
{
//If the target is one of the player objects or a UI Canvas then it's never a valid location
if(target.GetComponent<VRTK_PlayerObject>() || target.GetComponent<VRTK_UIGraphicRaycaster>())
{
return false;
}
bool validNavMeshLocation = false;
if (target)
{
NavMeshHit hit;
validNavMeshLocation = NavMesh.SamplePosition(target.position, out hit, 1.0f, NavMesh.AllAreas);
}
if (!limitToNavMesh)
{
validNavMeshLocation = true;
}
return (validNavMeshLocation && target && target.tag != ignoreTargetWithTagOrClass && target.GetComponent(ignoreTargetWithTagOrClass) == null);
}
protected virtual void DoTeleport(object sender, DestinationMarkerEventArgs e)
{
if (enableTeleport && ValidLocation(e.target) && e.enableTeleport)
{
OnTeleporting(sender, e);
Vector3 newPosition = GetNewPosition(e.destinationPosition, e.target);
CalculateBlinkDelay(blinkTransitionSpeed, newPosition);
Blink(blinkTransitionSpeed);
SetNewPosition(newPosition, e.target);
OnTeleported(sender, e);
}
}
protected virtual void SetNewPosition(Vector3 position, Transform target)
{
this.transform.position = CheckTerrainCollision(position, target);
}
protected virtual Vector3 GetNewPosition(Vector3 tipPosition, Transform target)
{
float newX = 0;
float newY = 17;
float newZ = 0;
return new Vector3(newX, newY, newZ);
}
protected Vector3 CheckTerrainCollision(Vector3 position, Transform target)
{
if (adjustYForTerrain && target.GetComponent<Terrain>())
{
var terrainHeight = Terrain.activeTerrain.SampleHeight(position);
position.y = (terrainHeight > position.y ? position.y : terrainHeight);
}
return position;
}
private void CalculateBlinkDelay(float blinkSpeed, Vector3 newPosition)
{
blinkPause = 0f;
if (distanceBlinkDelay > 0f)
{
float distance = Vector3.Distance(this.transform.position, newPosition);
blinkPause = Mathf.Clamp((distance * blinkTransitionSpeed) / (maxBlinkDistance - distanceBlinkDelay), 0, maxBlinkTransitionSpeed);
blinkPause = (blinkSpeed <= 0.25 ? 0f : blinkPause);
}
}
private void ReleaseBlink()
{
SteamVR_Fade.Start(Color.clear, fadeInTime);
fadeInTime = 0f;
}
private void InitDestinationMarkerListeners()
{
var controllerManager = GameObject.FindObjectOfType<SteamVR_ControllerManager>();
InitDestinationSetListener(controllerManager.left);
InitDestinationSetListener(controllerManager.right);
foreach (var destinationMarker in GameObject.FindObjectsOfType<VRTK_DestinationMarker>())
{
if (destinationMarker.gameObject != controllerManager.left && destinationMarker.gameObject != controllerManager.right)
{
InitDestinationSetListener(destinationMarker.gameObject);
}
}
}
private void InitHeadsetCollisionListener()
{
var headset = GameObject.FindObjectOfType<VRTK_HeadsetCollisionFade>();
if (headset)
{
headset.HeadsetCollisionDetect += new HeadsetCollisionEventHandler(DisableTeleport);
headset.HeadsetCollisionEnded += new HeadsetCollisionEventHandler(EnableTeleport);
}
}
private void DisableTeleport(object sender, HeadsetCollisionEventArgs e)
{
enableTeleport = false;
}
private void EnableTeleport(object sender, HeadsetCollisionEventArgs e)
{
enableTeleport = true;
}
}
And here is the code for the pointer:
namespace VRTK{
using UnityEngine;
using System.Collections;
public class VRTK_BezierPointer : VRTK_WorldPointer
{
public float pointerLength = 10f;
public int pointerDensity = 10;
public bool showPointerCursor = true;
public float pointerCursorRadius = 0.5f;
public float beamCurveOffset = 1f;
public GameObject customPointerTracer;
public GameObject customPointerCursor;
public LayerMask layersToIgnore = Physics.IgnoreRaycastLayer;
private GameObject projectedBeamContainer;
private GameObject projectedBeamForward;
private GameObject projectedBeamJoint;
private GameObject projectedBeamDown;
private GameObject pointerCursor;
private GameObject curvedBeamContainer;
private CurveGenerator curvedBeam;
// Use this for initialization
protected override void Start()
{
base.Start();
InitProjectedBeams();
InitPointer();
TogglePointer(false);
}
protected override void Update()
{
base.Update();
if (projectedBeamForward.gameObject.activeSelf)
{
ProjectForwardBeam();
ProjectDownBeam();
DisplayCurvedBeam();
SetPointerCursor();
}
}
protected override void InitPointer()
{
pointerCursor = (customPointerCursor ? Instantiate(customPointerCursor) : CreateCursor());
pointerCursor.name = string.Format("[{0}]WorldPointer_BezierPointer_PointerCursor", this.gameObject.name);
Utilities.SetPlayerObject(pointerCursor, VRTK_PlayerObject.ObjectTypes.Pointer);
pointerCursor.layer = LayerMask.NameToLayer("Ignore Raycast");
pointerCursor.SetActive(false);
curvedBeamContainer = new GameObject(string.Format("[{0}]WorldPointer_BezierPointer_CurvedBeamContainer", this.gameObject.name));
Utilities.SetPlayerObject(curvedBeamContainer, VRTK_PlayerObject.ObjectTypes.Pointer);
curvedBeamContainer.SetActive(false);
curvedBeam = curvedBeamContainer.gameObject.AddComponent<CurveGenerator>();
curvedBeam.transform.parent = null;
curvedBeam.Create(pointerDensity, pointerCursorRadius, customPointerTracer);
base.InitPointer();
}
protected override void SetPointerMaterial()
{
if (pointerCursor.GetComponent<Renderer>())
{
pointerCursor.GetComponent<Renderer>().material = pointerMaterial;
}
foreach (Renderer mr in pointerCursor.GetComponentsInChildren<Renderer>())
{
mr.material = pointerMaterial;
}
base.SetPointerMaterial();
}
protected override void TogglePointer(bool state)
{
state = (pointerVisibility == pointerVisibilityStates.Always_On ? true : state);
projectedBeamForward.gameObject.SetActive(state);
projectedBeamJoint.gameObject.SetActive(state);
projectedBeamDown.SetActive(state);
}
protected override void DisablePointerBeam(object sender, ControllerInteractionEventArgs e)
{
base.DisablePointerBeam(sender, e);
TogglePointerCursor(false);
curvedBeam.TogglePoints(false);
}
protected override void OnDestroy()
{
base.OnDestroy();
if (projectedBeamDown != null)
{
Destroy(projectedBeamDown);
}
if (pointerCursor != null)
{
Destroy(pointerCursor);
}
if (curvedBeam != null)
{
Destroy(curvedBeam);
}
if (projectedBeamContainer != null)
{
Destroy(projectedBeamContainer);
}
if (curvedBeamContainer != null)
{
Destroy(curvedBeamContainer);
}
}
private GameObject CreateCursor()
{
var cursorYOffset = 0.02f;
var cursor = GameObject.CreatePrimitive(PrimitiveType.Cylinder);
cursor.GetComponent<MeshRenderer>().shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off;
cursor.GetComponent<MeshRenderer>().receiveShadows = false;
cursor.transform.localScale = new Vector3(pointerCursorRadius, cursorYOffset, pointerCursorRadius);
Destroy(cursor.GetComponent<CapsuleCollider>());
return cursor;
}
private void TogglePointerCursor(bool state)
{
var pointerCursorState = (showPointerCursor && state ? showPointerCursor : false);
var playAreaCursorState = (showPlayAreaCursor && state ? showPlayAreaCursor : false);
pointerCursor.gameObject.SetActive(pointerCursorState);
base.TogglePointer(playAreaCursorState);
}
private void InitProjectedBeams()
{
projectedBeamContainer = new GameObject(string.Format("[{0}]WorldPointer_BezierPointer_ProjectedBeamContainer", this.gameObject.name));
Utilities.SetPlayerObject(projectedBeamContainer, VRTK_PlayerObject.ObjectTypes.Pointer);
projectedBeamContainer.transform.parent = this.transform;
projectedBeamContainer.transform.localPosition = Vector3.zero;
projectedBeamForward = new GameObject(string.Format("[{0}]WorldPointer_BezierPointer_ProjectedBeamForward", this.gameObject.name));
Utilities.SetPlayerObject(projectedBeamForward, VRTK_PlayerObject.ObjectTypes.Pointer);
projectedBeamForward.transform.parent = projectedBeamContainer.transform;
projectedBeamJoint = new GameObject(string.Format("[{0}]WorldPointer_BezierPointer_ProjectedBeamJoint", this.gameObject.name));
Utilities.SetPlayerObject(projectedBeamJoint, VRTK_PlayerObject.ObjectTypes.Pointer);
projectedBeamJoint.transform.parent = projectedBeamContainer.transform;
projectedBeamJoint.transform.localScale = new Vector3(0.01f, 0.01f, 0.01f);
projectedBeamDown = new GameObject(string.Format("[{0}]WorldPointer_BezierPointer_ProjectedBeamDown", this.gameObject.name));
Utilities.SetPlayerObject(projectedBeamDown, VRTK_PlayerObject.ObjectTypes.Pointer);
}
private float GetForwardBeamLength()
{
var actualLength = pointerLength;
Ray pointerRaycast = new Ray(transform.position, transform.forward);
RaycastHit collidedWith;
var hasRayHit = Physics.Raycast(pointerRaycast, out collidedWith, pointerLength, ~layersToIgnore);
//reset if beam not hitting or hitting new target
if (!hasRayHit || (pointerContactTarget && pointerContactTarget != collidedWith.transform))
{
pointerContactDistance = 0f;
}
//check if beam has hit a new target
if (hasRayHit)
{
pointerContactDistance = collidedWith.distance;
}
//adjust beam length if something is blocking it
if (hasRayHit && pointerContactDistance < pointerLength)
{
actualLength = pointerContactDistance;
}
return actualLength;
}
private void ProjectForwardBeam()
{
var setThicknes = 0.01f;
var setLength = GetForwardBeamLength();
//if the additional decimal isn't added then the beam position glitches
var beamPosition = setLength / (2 + 0.00001f);
projectedBeamForward.transform.localScale = new Vector3(setThicknes, setThicknes, setLength);
projectedBeamForward.transform.localPosition = new Vector3(0f, 0f, beamPosition);
projectedBeamJoint.transform.localPosition = new Vector3(0f, 0f, setLength - (projectedBeamJoint.transform.localScale.z / 2));
projectedBeamContainer.transform.localRotation = Quaternion.identity;
}
private void ProjectDownBeam()
{
projectedBeamDown.transform.position = new Vector3(projectedBeamJoint.transform.position.x, projectedBeamJoint.transform.position.y, projectedBeamJoint.transform.position.z);
Ray projectedBeamDownRaycast = new Ray(projectedBeamDown.transform.position, Vector3.down);
RaycastHit collidedWith;
var downRayHit = Physics.Raycast(projectedBeamDownRaycast, out collidedWith, float.PositiveInfinity, ~layersToIgnore);
if (!downRayHit || (pointerContactTarget && pointerContactTarget != collidedWith.transform))
{
if (pointerContactTarget != null)
{
base.PointerOut();
}
pointerContactTarget = null;
destinationPosition = Vector3.zero;
}
if (downRayHit)
{
projectedBeamDown.transform.position = new Vector3(projectedBeamJoint.transform.position.x, projectedBeamJoint.transform.position.y - collidedWith.distance, projectedBeamJoint.transform.position.z);
projectedBeamDown.transform.localScale = new Vector3(0.1f, 0.1f, 0.1f);
pointerContactTarget = collidedWith.transform;
destinationPosition = projectedBeamDown.transform.position;
base.PointerIn();
}
}
private void SetPointerCursor()
{
if (pointerContactTarget != null)
{
TogglePointerCursor(true);
pointerCursor.transform.position = projectedBeamDown.transform.position;
base.SetPlayAreaCursorTransform(pointerCursor.transform.position);
UpdatePointerMaterial(pointerHitColor);
}
else
{
TogglePointerCursor(false);
UpdatePointerMaterial(pointerMissColor);
}
}
private void DisplayCurvedBeam()
{
Vector3[] beamPoints = new Vector3[]
{
this.transform.position,
projectedBeamJoint.transform.position + new Vector3(0f, beamCurveOffset, 0f),
projectedBeamDown.transform.position,
projectedBeamDown.transform.position,
};
curvedBeam.SetPoints(beamPoints, pointerMaterial);
if (pointerVisibility != pointerVisibilityStates.Always_Off)
{
curvedBeam.TogglePoints(true);
}
}
}
}
How are you trying to pick the object. Do you use some sort of ray cast or just pick up on collision ? Nevertheless whatever you want to do triggering the teleportation when the object is picked up should be as simple as calling the teleport script from whatever script you using to pick up the object.
for eg:
void OnTriggerEnter(Collider other)
{
if (other.gameObject.CompareTag ("Pick Up"))
{
<<call your teleport script here>>
}
}
Unity has really nice documentation for scripting and you can find a lot of tutorials that explain the basics, even if you go through one of them you should be able to do mostly anything you want with relative ease.

Categories