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.
Related
I am having 3 errors with 2 errors being NullReferenceException and 1 with ReceiveDamage has no receiver! error.
This is the enemy script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Enemy : Mover
{
// Experience
public int xpValue = 1;
// Logic
public float triggerLength = 1;
public float chaseLength = 5;
private bool chasing;
private bool collidingWithPlayer;
private Transform playerTransform;
private Vector3 startingPosition;
// Hitbox
public ContactFilter2D filter;
private BoxCollider2D hitbox;
private Collider2D[] hits = new Collider2D[10];
protected override void Start()
{
base.Start();
playerTransform = GameManager.instance.player.transform;
startingPosition = transform.position;
hitbox = transform.GetChild(0).GetComponent<BoxCollider2D>();
}
private void FixedUpdate()
{
// Is the player in range?
if (Vector3.Distance(playerTransform.position, startingPosition) < chaseLength)
{
if (Vector3.Distance(playerTransform.position, startingPosition) < triggerLength)
chasing = true;
if (chasing)
{
if (!collidingWithPlayer)
{
UpdateMotor((playerTransform.position - transform.position).normalized);
}
}
else
{
UpdateMotor(startingPosition - transform.position);
}
}
else
{
UpdateMotor(startingPosition - transform.position);
chasing = false;
}
// Check for overlaps
collidingWithPlayer = false;
boxCollider.OverlapCollider(filter, hits);
for (int i = 0; i < hits.Length; i++)
{
if (hits[i] == null)
continue;
if (hits[i].tag == "Fighter" && hits[i].name == "Player")
{
collidingWithPlayer = true;
}
// The array is not cleaned up, so we do it ourself
hits[i] = null;
}
}
protected override void Death()
{
Destroy(gameObject);
GameManager.instance.GrantXp(xpValue);
GameManager.instance.ShowText("+" + xpValue + " xp", 30, Color.magenta, transform.position, Vector3.up * 40, 1.0f);
}
}
I have two errors for the enemy script: 1. NullReferenceException: Object reference not set to an instance of an object Enemy.Start () (at Assets/Scripts/Enemy.cs:26), 2. NullReferenceException: Object reference not set to an instance of an object Enemy.FixedUpdate () (at Assets/Scripts/Enemy.cs:34)
The last error occurs in the collidable script. Collidable script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Collidable : MonoBehaviour
{
public ContactFilter2D filter;
private BoxCollider2D boxCollider;
private Collider2D[] hits = new Collider2D[10];
protected virtual void Start()
{
boxCollider = GetComponent<BoxCollider2D>();
}
protected virtual void Update()
{
// Collision work
boxCollider.OverlapCollider(filter, hits);
for (int i = 0; i < hits.Length; i++)
{
if (hits[i] == null)
continue;
OnCollide(hits[i]);
// The array is not cleaned up, so we do it ourself
hits[i] = null;
}
}
protected virtual void OnCollide(Collider2D coll)
{
Debug.Log("OnCollide was not implemented in " + this.name);
}
}
In this script there is one error: SendMessage ReceiveDamage has no receiver!
UnityEngine.GameObject:SendMessage (string,object) EnemyHitbox:OnCollide (UnityEngine.Collider2D) (at Assets/Scripts/EnemyHitbox.cs:23) Collidable:Update () (at Assets/Scripts/Collidable.cs:25)
So I recently finished Sebastian Lague's Create a Game series and everything works fine except for the music. I don't know the cause of issue but while in gameplay scene another theme just starts playing, same thing happens when I restart the game and this also happens in Sebastian's finale version of the game so I can't find the answer there. I didn't really try anything since I don't have an idea what cause of the issue may be, so I decided to write here and maybe someone will know the answer. Thanks in advance!
Audio Manager:
using UnityEngine;
using System.Collections;
using UnityEngine.SceneManagement;
public class AudioManager : MonoBehaviour
{
public enum AudioChannel { Master, Sfx, Music };
public float masterVolumePercent { get; private set; }
public float sfxVolumePercent { get; private set; }
public float musicVolumePercent { get; private set; }
private AudioSource sfx2DSource;
private AudioSource[] musicSources;
private int activeMusicSourceIndex;
public static AudioManager instance;
private Transform audioListener;
private Transform playerT;
private SoundLibrary library;
private void OnEnable()
{
SceneManager.sceneLoaded += OnLevelFinishedLoading;
}
private void OnDisable()
{
SceneManager.sceneLoaded -= OnLevelFinishedLoading;
}
void Awake()
{
if (instance != null)
{
Destroy(gameObject);
}
else
{
instance = this;
DontDestroyOnLoad(gameObject);
library = GetComponent<SoundLibrary>();
musicSources = new AudioSource[2];
for (int i = 0; i < 2; i++)
{
GameObject newMusicSource = new GameObject("Music source " + (i + 1));
musicSources[i] = newMusicSource.AddComponent<AudioSource>();
newMusicSource.transform.parent = transform;
}
GameObject newSfx2Dsource = new GameObject("2D sfx source");
sfx2DSource = newSfx2Dsource.AddComponent<AudioSource>();
newSfx2Dsource.transform.parent = transform;
audioListener = FindObjectOfType<AudioListener>().transform;
if (FindObjectOfType<PlayerInput>() != null)
{
playerT = FindObjectOfType<PlayerInput>().transform;
}
masterVolumePercent = PlayerPrefs.GetFloat("master vol", 1);
sfxVolumePercent = PlayerPrefs.GetFloat("sfx vol", 1);
musicVolumePercent = PlayerPrefs.GetFloat("music vol", 1);
}
}
void Update()
{
if (playerT != null)
{
audioListener.position = playerT.position;
}
}
public void SetVolume(float volumePercent, AudioChannel channel)
{
switch (channel)
{
case AudioChannel.Master:
masterVolumePercent = volumePercent;
break;
case AudioChannel.Sfx:
sfxVolumePercent = volumePercent;
break;
case AudioChannel.Music:
musicVolumePercent = volumePercent;
break;
}
musicSources[0].volume = musicVolumePercent * masterVolumePercent;
musicSources[1].volume = musicVolumePercent * masterVolumePercent;
PlayerPrefs.SetFloat("master vol", masterVolumePercent);
PlayerPrefs.SetFloat("sfx vol", sfxVolumePercent);
PlayerPrefs.SetFloat("music vol", musicVolumePercent);
PlayerPrefs.Save();
}
public void PlayMusic(AudioClip clip, float fadeDuration = 1)
{
activeMusicSourceIndex = 1 - activeMusicSourceIndex;
musicSources[activeMusicSourceIndex].clip = clip;
musicSources[activeMusicSourceIndex].Play();
StartCoroutine(AnimateMusicCrossfade(fadeDuration));
}
public void PlaySound(AudioClip clip, Vector3 pos)
{
if (clip != null)
{
AudioSource.PlayClipAtPoint(clip, pos, sfxVolumePercent * masterVolumePercent);
}
}
public void PlaySound(string soundName, Vector3 pos)
{
PlaySound(library.GetClipFromName(soundName), pos);
}
public void PlaySound2D(string soundName)
{
sfx2DSource.PlayOneShot(library.GetClipFromName(soundName), sfxVolumePercent * masterVolumePercent);
}
IEnumerator AnimateMusicCrossfade(float duration)
{
float percent = 0;
while (percent < 1)
{
percent += Time.deltaTime * 1 / duration;
musicSources[activeMusicSourceIndex].volume = Mathf.Lerp(0, musicVolumePercent * masterVolumePercent, percent);
musicSources[1 - activeMusicSourceIndex].volume = Mathf.Lerp(musicVolumePercent * masterVolumePercent, 0, percent);
yield return null;
}
}
private void OnLevelFinishedLoading(Scene scene, LoadSceneMode sceneMode)
{
if (playerT == null)
{
if (FindObjectOfType<PlayerInput>() != null)
playerT = FindObjectOfType<PlayerInput>().transform;
}
}
}
Music Manager:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class MusicManager : MonoBehaviour
{
[SerializeField] private AudioClip mainTheme;
[SerializeField] private AudioClip menuTheme;
private string sceneName;
private void OnEnable()
{
SceneManager.sceneLoaded += OnLevelFinishedLoading;
}
private void OnDisable()
{
SceneManager.sceneLoaded -= OnLevelFinishedLoading;
}
void PlayMusic()
{
AudioClip clipToPlay = null;
if(sceneName == "Main Menu")
{
if(clipToPlay == null)
clipToPlay = menuTheme;
}
else if(sceneName == "Gameplay")
{
if(clipToPlay == null)
clipToPlay = mainTheme;
}
if(clipToPlay != null)
{
AudioManager.instance.PlayMusic(clipToPlay, 2);
Invoke("PlayMusic", clipToPlay.length);
Debug.Log(clipToPlay.length);
}
}
private void OnLevelFinishedLoading(Scene scene, LoadSceneMode sceneMode)
{
if(sceneName != scene.name)
{
sceneName = scene.name;
Invoke("PlayMusic", .2f);
}
}
}
I have a Timer that counts down every 3 seconds (The white circle). It has a script attached called ReloadTimer.
I have a script that fires bullets (TankShooter) and reloads for 3 seconds.
How do I make it so that my countdown starts when I am reloading?
I tried looking at a lot of Unity forums and the advice didn't work.
ReloadTimer.cs
[ExecuteInEditMode]
public class ReloadTimer : MonoBehaviour
{
public Image filled;
public Text text;
public float maxValue = 3;
public float value = 0;
// UpdateReload is called once per frame
public void UpdateReload ()
{
value = Mathf.Clamp(value, 0, maxValue);
float amount = value / maxValue;
filled.fillAmount = amount;
text.text = value.ToString();
}
}
TankShooter
public int m_PlayerNumber = 1;
public Rigidbody m_Shell;
public Transform m_FireTransform;
public AudioSource m_ShootingAudio;
public AudioClip m_FireClip;
public float m_ShellVelocity = 100f;
private string m_FireButton;
public int maxAmmo = 5;
private int currentAmmo;
public float reloadTime = 2f;
private bool isReloading = false;
public ReloadTimer reloadTimer;
public class TankShootingT : NetworkBehaviour
{
public ReloadTimer reloadTimer;
private void Start()
{
if (!isLocalPlayer)
{
return;
}
currentAmmo = maxAmmo;
m_FireButton = "Fire" + m_PlayerNumber;
}
private void Update()
{
if (isReloading)
return;
if (currentAmmo <= 0)
{
StartCoroutine(Reload());
return;
}
reloadTimer.UpdateReload();
if (m_FireButton == "Fire1" && Input.GetButtonUp(m_FireButton))
{
// we released the button, have not fired yet
CmdShoot();
}
}
IEnumerator Reload()
{
isReloading = true;
Debug.Log("Reloading...");
yield return new WaitForSeconds(reloadTime);
currentAmmo = maxAmmo;
isReloading = false;
}
[Command]
private void CmdShoot()
{
currentAmmo--;
// Instantiate and launch the shell.
Rigidbody shellInstance = Instantiate(m_Shell, m_FireTransform.position, m_FireTransform.rotation) as Rigidbody;
shellInstance.velocity = m_ShellVelocity * m_FireTransform.forward;
// Server spawns the shell
NetworkServer.Spawn(shellInstance.gameObject);
m_ShootingAudio.clip = m_FireClip;
m_ShootingAudio.Play();
}
}
For starters, There isn't such thing as UpdateReload that would be "called once per frame" as this is not a predetermined Unity function, it is just a function that you created (You can read about this here). Another problem is that you didn't even call that function anywhere else in your scripts. And even if you did, Mathf.Clamp() needs to be placed in an Update() function so it can update it's value each frame.
I made some modifications to the scripts that you posted, but I haven't tested them yet. give it a try and let me know how it goes:
ReloadTimer.cs
public class ReloadTimer : MonoBehaviour
{
public static ReloadTimer Instance { set; get; }
public Image filled;
public Text text;
public float coolDownTime = 3;
public bool isCoolingDown = false;
void Awake()
{
Instance = this;
}
void Update()
{
if (isCoolingDown == true)
{
filled.fillAmount += 1.0f / coolDownTime * Time.deltaTime;
int percentageInt = Mathf.RoundToInt((filled.fillAmount / coolDownTime) * 10);
text.text = percentageInt.ToString();
}
}
}
TankShootingT.cs
public int m_PlayerNumber = 1;
public Rigidbody m_Shell;
public Transform m_FireTransform;
public AudioSource m_ShootingAudio;
public AudioClip m_FireClip;
public float m_ShellVelocity = 100f;
private string m_FireButton;
public int maxAmmo = 5;
private int currentAmmo;
public float reloadTime = 2f;
private bool isReloading = false;
public ReloadTimer reloadTimer;
public class TankShootingT : NetworkBehaviour
{
public ReloadTimer reloadTimer;
private void Start()
{
if (!isLocalPlayer)
{
return;
}
currentAmmo = maxAmmo;
m_FireButton = "Fire" + m_PlayerNumber;
}
private void Update()
{
if (isReloading)
return;
if (currentAmmo <= 0)
{
StartCoroutine(Reload());
return;
}
reloadTimer.UpdateReload();
if (m_FireButton == "Fire1" && Input.GetButtonUp(m_FireButton))
{
// we released the button, have not fired yet
CmdShoot();
}
}
IEnumerator Reload()
{
isReloading = true;
ReloadTimer.Instance.isCoolingDown = true;
Debug.Log("Reloading...");
yield return new WaitForSeconds(reloadTime);
currentAmmo = maxAmmo;
isReloading = false;
ReloadTimer.Instance.isCoolingDown = false;
ReloadTimer.Instance.filled.fillAmount = 0.0f;
}
[Command]
private void CmdShoot()
{
currentAmmo--;
// Instantiate and launch the shell.
Rigidbody shellInstance = Instantiate(m_Shell, m_FireTransform.position, m_FireTransform.rotation) as Rigidbody;
shellInstance.velocity = m_ShellVelocity * m_FireTransform.forward;
// Server spawns the shell
NetworkServer.Spawn(shellInstance.gameObject);
m_ShootingAudio.clip = m_FireClip;
m_ShootingAudio.Play();
}
}
Hope this helps a bit.
I have a boolean variable which I set to true when I want certain parts of my scene to move up. The problem is, it seems to be resetting to false every time I set it to true, during the same frame. I've made the bool into a property and set a breakpoint in the set method and it only ever gets called with "true" as a parameter.
Is there something I'm doing wrong, or is Unity doing some weird stuff behind?
private bool SceneMoveUp
{
get
{
return _sceneMoveUp;
}
set
{
_sceneMoveUp = value;
}
}
void Update () {
if (SceneMoveUp == true) {
transform.position = Vector3.MoveTowards(transform.position, SceneDestination, speed * Time.deltaTime);
}
}
EDIT: SceneMoveUp is a property inside a MonoBehaviour-derived class.
EDIT2: entire code
using UnityEngine;
using System.Collections;
public class PseudoScene : MonoBehaviour {
public Vector3 ZoomOutPosition;
public GameObject[] Letters;
public Vector3[] CameraPositions;
public PseudoSceneManager _manager;
public float speed;
private float DepartureTime;
private Vector3 TextureOffset;
private int LetterCount, CurrentIndex = 0;
private bool ZoomingOut = false;
private bool _sceneMoveUp;
private bool SceneMoveUp{ get
{
return _sceneMoveUp;
}
set
{
_sceneMoveUp = value;
}
}
static public bool MovingCamera = false;
private Vector3 BackgroundFinalScale;
private Vector3 SceneDestination;
[SerializeField]private Quaternion FinalRotation;
void Start () {
LetterCount = Letters.Length;
SceneMoveUp = false;
if (LetterCount == 1) {
CameraPositions = new Vector3[1];
CameraPositions[0] = transform.position;
CameraPositions[0].z = -10;
}
ChangeLetter();
}
public void LetterFilled () {
CurrentIndex++;
if (CurrentIndex < LetterCount) {
ChangeLetter();
} else {
if (LetterCount > 1) {
ZoomOut();
} else {
MoveScene();
}
Invoke("FinishScene", 3f);
}
}
void Update () {
if (ZoomingOut) {
Camera.main.transform.position = Vector3.Lerp(transform.position, ZoomOutPosition, 1f);
Camera.main.orthographicSize = Mathf.Lerp(Camera.main.orthographicSize, 13, 0.1f);
}
if (MovingCamera) {
Camera.main.transform.position = Vector3.MoveTowards(Camera.main.transform.position, CameraPositions[CurrentIndex], speed * Time.deltaTime);
if (Camera.main.transform.position == CameraPositions[CurrentIndex]) {
MovingCamera = false;
Checkpoint.DeactivateAllCheckpoints(true);
if (LetterCount > 1 && CurrentIndex >= 1) {
Checkpoint.DeactivateAllCheckpoints(true);
}
}
}
if (SceneMoveUp == true) {
transform.position = Vector3.MoveTowards(transform.position, SceneDestination, speed * Time.deltaTime);
}
}
void MoveScene () {
DepartureTime = Time.time;
SceneMoveUp = true;
Debug.logger.Log("set SceneMoveUp to ", SceneMoveUp.ToString());
SceneDestination = transform.position;
SceneDestination.y += 10;
}
public void FinishScene () {
_manager.SceneFinished();
}
//5.75
void ChangeLetter () {
Checkpoint.DeactivateAllCheckpoints(false);
MovingCamera = true;
}
void ZoomOut () {
ZoomingOut = true;
}
}
It seems there was a random bug which made it not work. I deleted the class, created a new one with the exact same code (copy-paste) and it now works. Thanks everyone for trying.
As crazy as this sounds, I had the exact same problem. After hours of trying to debug, I copy-pasted the exact code into a new class. Bam! It worked. I assume that I did something to cause the error and wish I new what it was. But copy-paste worked.
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.