This is my code. Tried repasting the code. And multiple other things like writing the function again.
The brackets wont connect(at the start and the end of the code) when I make new function. The closing bracket from new function will jump to the one that summarizes the whole code. Even placing it properly does nothing. Thanks in advance.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Shooter : MonoBehaviour
{
[SerializeField] GameObject projectile;
[SerializeField] Transform gunPos;
public void Fire()
{
if (!gunPos) { return; }
GameObject projectileInstance = Instantiate(projectile, gunPos.transform.position, Quaternion.identity) as GameObject;
}
private void SetLaneSpawner()
{
public AttackerSpawner[] spawners = FindObjectsOfType<AttackerSpawner>();
}
private void Start()
{
SetLaneSpawner();
}
public void Update()
{
if (null)
{
Debug.Log("pew pew");
//TODO attack animation
}
else
{
Debug.Log("wait");
//TODO idle animation
}
}
}
The error is in the line:
public AttackerSpawner[] spawners = FindObjectsOfType<AttackerSpawner>();
// Remove the public so it becomes.
AttackerSpawner[] spawners = FindObjectsOfType<AttackerSpawner>();
Accessibility modifiers (public, private, etc) can only be applied at the class and property level. You cannot use them inside a function.
Related
I have a problem, I need to block the creation of a new object (prefab) if there is already one prefab on the stage.I solved it with GameObject.FindWithTag, but maybe there is some other way
using UnityEngine;
public class CreateBullet : MonoBehaviour
{
public Transform firePoint;
public GameObject ballPrefab;
void Update()
{
if (Input.GetMouseButtonDown(0))
{
if (GameObject.FindWithTag("ballBullet") == null)
{
CreatingBulletBall();
}
}
}
void CreatingBulletBall()
{
Instantiate(ballPrefab, firePoint.position, firePoint.rotation);
}
}
Here is what you should do:
Create script Bullet.cs with code from below;
Add it as component to the bullet prefab;
Change the CreateBullet class as shown below;
Assign bullet prefab to the ballPrefab field of the CreateBullet component (if unassigned after script change).
How it works: if _bullet field is null, new bullet is created and stored there. When bullet is destroyed, it fires event Destroyed. Callback OnBulletDestroyed will assign null to _bullet, so it can be created again.
File CreateBullet.cs:
public class CreateBullet : MonoBehaviour
{
public Transform firePoint;
public Bullet ballPrefab;
private void Update()
{
if (Input.GetMouseButtonDown(0))
TryCreateBulletBall();
}
private Bullet? _bullet = null;
private void TryCreateBulletBall()
{
if (this._bullet != null)
return;
this._bullet = Instantiate(ballPrefab, firePoint.position, firePoint.rotation);
this._bullet.Destroyed += this.OnBulletDestroyed;
}
private void OnBulletDestroyed()
{
this._bullet.Destroyed -= this.OnBulletDestroyed;
this._bullet = null;
}
}
File Bullet.cs:
public class Bullet : MonoBehaviour
{
public event Action? Destroyed;
private void OnDestroy()
{
this.Destroyed?.Invoke();
}
}
Not tested, but it should work. It works.
Update:
About performance:
In terms of performance it's perfectly fine. It is idiomatic to store the reference to the object once (through Inspector, in Start/Awake hooks, when object is instantiated, etc), instead of calling any of Find...() or GetComponent() methods in the Update hook. In fact, docs for Find() method state that you should avoid calling it every frame.
Simplified version of code.
As #derHugo noted in comment, it's sufficient to have this code only:
File CreateBullet.cs:
public class CreateBullet : MonoBehaviour
{
public Transform firePoint;
public GameObject ballPrefab;
private void Update()
{
if (Input.GetMouseButtonDown(0))
TryCreateBulletBall();
}
private GameObject _bullet;
private void TryCreateBulletBall()
{
if (this._bullet)
return;
this._bullet = Instantiate(ballPrefab, firePoint.position, firePoint.rotation);
}
}
my snippets doesn't work in vscode , i use Unity 3.5 and VScode lastest version
and public class not show in gameobject
there is my code :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class kontrol : MonoBehaviour
{
public float berat, tinggiLoncat;
public private void OnParticleCollision(GameObject bird) {
};
// Start is called before the first frame update
void Start()
{
}
void OnMouseDown() {
bird.GetComponent<Rigidbody2D> ().gravityScale = berat;
bird;GetComponent<Rigidbody2D> ().velocity = new Vector2 ( bird;GetComponent<Rigidbody2D>().velocity.x, tinggiLoncat);
}
// Update is called once per frame
void Update()
{
}
}
This isnt working because you have many syntax errors and the script isn't compiling so you cant add it obviously.
public private void OnParticleCollision(GameObject bird) { // Public Private? Choose one!
}; //no semicolon after methods
bird.GetComponent<Rigidbody2D> ().gravityScale
bird;GetComponent<Rigidbody2D> ().velocity //why are you using a semicolon, you did it right in the first place.
GetComponent is expensive. Use it once in Awake or Start, and save the reference. For example:
class SomeComponent: MonoBehaviour {
Rigidbody rb;
void Awake() {
rb = GetComponent<Rigidbody>();
}
void Update() {
// do something with rb
}
}
You're using semicolons instead of periods.
Here's the first script which is just for the gems to be "collected".
using UnityEngine;
public class GemDestructionScript : MonoBehaviour
{
public int gemsCollected = 0;
void Awake()
{
}
void Update()
{
}
void OnCollisionEnter2D(Collision2D col)
{
if (col.gameObject.tag.Equals("Player1"))
{
gemsCollected++;
GetComponent<SpriteRenderer>().enabled = false;
GetComponent<CircleCollider2D>().enabled = false;
}
}
}
This is the 2nd script which is for the gemsCollected to be displayed on the canvas.
using UnityEngine;
using UnityEngine.UI;
using System;
public class GemCounter : GemDestructionScript
{
private Canvas canvas;
void Start()
{
}
void Update()
{
Transform child = transform.Find("Text");
Text t = child.GetComponent<Text>();
t.text = Convert.ToString(gemsCollected);
}
}
The problem is that the gemsCollected variable doesn't update on the canvas, it just stays at 0 the whole time.
Thanks in advance.
I fail to see the need for GemCounter to inherit from GemDestruction. Inheritance is more commonly used when having different Categories build upon each other.
A good, simple example of this is the Fruit example from Unity
In your case I would recommend using 2 separate Classes that are not linked via Inheritance. This will save you the headache of properly accessing whatever Data you need, unless it's really important for you to use Inheritance.
When you've split the classes and moved your gemsCollected to the Counter, instead of on the Gems themselves, you can just have the Gems "report in" when they are collected. This way the Counter can keep track of how many Gems have been collected and displays them on the UI. Every Object should have their job, and only use things that are relevant for that Job.
Example:
public class GemDestructionScript : MonoBehaviour
{
GemCounter counter;
private void Start()
{
// Find where-ever you keep the GemCounter Script (the Canvas in your case)
counter = GameObject.Find("Canvas").GetComponent<GemCounter>();
}
void OnCollisionEnter2D(Collision2D col)
{
if (col.gameObject.tag.Equals("Player1"))
{
counter.AddGem();
GetComponent<SpriteRenderer>().enabled = false;
GetComponent<CircleCollider2D>().enabled = false;
}
}
}
public class GemCounter : MonoBehaviour
{
public int gemsCollected = 0;
Text GemCounterText;
private void Start()
{
// Finding the Text Object in every Frame would be inefficient, so unless that object is constantly changing, just get it once during Start/Awake/before using it
GemCounterText = GameObject.Find("Text").GetComponent<Text>();
}
public void UpdateGemCount()
{
GemCounterText.text = gemsCollected.ToString();
}
public void AddGem()
{
gemsCollected++;
UpdateGemCount();
}
}
I am trying to create a simple dialogue system for my game in Unity. I've set up a special trigger for a Dialogue to start and the code is passing right variable but somehow it gets stuck at clearing the queue and throws a NullReferenceException.
I've seen through debugger that all variables and triggers work perfectly fine till cs:27 inside DialogueManager.cs. I've also checked the inspector to make sure everything is correctly assigned.
Dialogue class:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[System.Serializable]
public class Dialogue
{
public string name;
[TextArea(3,10)]
public string[] sentences;
}
DialogueTrigger class:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class NPC_DialogTrigger : MonoBehaviour
{
// Player
public Transform player;
// GameMaager to close
public GameObject Gameplay;
// Camera and Canvas to turn on
public GameObject DialogueManager;
// NPC Details
public GameObject InteractionNPCNameTextField;
public Transform interactionTransform;
public float radius = 3f;
private bool isBusy = false;
// DialogueStart
public GameObject DialogueStart;
void Start()
{
InteractionNPCNameTextField.gameObject.SetActive(false);
}
void Update()
{
float distance = Vector3.Distance(player.position, interactionTransform.position);
if (distance <= radius)
{
if (isBusy == false)
{
InteractionNPCNameTextField.gameObject.SetActive(true);
if (Input.GetKeyDown(KeyCode.E))
{
Dialogue();
Debug.Log("Started Dialogue procedure.");
}
}
}
else if (distance > radius)
{
InteractionNPCNameTextField.gameObject.SetActive(false);
}
}
public void Dialogue()
{
Gameplay.SetActive(false);
DialogueManager.SetActive(true);
DialogueStart.GetComponent<DialogueStart>().TriggerDialogue();
Debug.Log("Triggered Dialogue.");
}
void OnDrawGizmosSelected()
{
if (interactionTransform == null)
{
interactionTransform = transform;
}
Gizmos.color = Color.yellow;
Gizmos.DrawWireSphere(interactionTransform.position, radius);
}
}
DialogueStart class:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class DialogueStart : MonoBehaviour
{
public Dialogue dialogue;
public void TriggerDialogue()
{
FindObjectOfType<DialogueManager>().StartDialogue(dialogue);
Debug.Log("Dialogue sent to dialogue manager.");
}
}
DialogueManager class:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using TMPro;
public class DialogueManager : MonoBehaviour
{
public Text nameText;
public Text DialogueText;
private Queue<string> sentences;
public GameObject DialogueManagerUI;
void Start()
{
if (sentences == null)
{
sentences = new Queue<string>();
}
}
public void StartDialogue (Dialogue dialogue)
{
Debug.Log("Received dialogues: " + dialogue);
nameText.text = dialogue.name;
Debug.Log("Start Dialogue: " + sentences.Count);
sentences.Clear();
Debug.Log("Sentences Cleared: " + sentences);
foreach (string sentence in dialogue.sentences)
{
sentences.Enqueue(sentence);
}
DisplayNextSentence();
}
public void DisplayNextSentence()
{
if(sentences.Count == 0)
{
EndDialogue();
return;
}
string sentence = sentences.Dequeue();
DialogueText.text = sentence;
}
void EndDialogue()
{
Debug.Log("End of conversation.");
}
private void Update()
{
if (DialogueManagerUI.activeInHierarchy)
{
Cursor.lockState = CursorLockMode.None;
Cursor.visible = true;
}
else if (!DialogueManagerUI.activeInHierarchy)
{
Cursor.lockState = CursorLockMode.Locked;
Cursor.visible = false;
}
}
}
Visual Studio doesn't give me any errors.
Unity error code -> Screenshot
Debugger right before issue -> Screenshot2
Seems to me like the Queue is never assigned to sentences and it remains empty.
If it is so - why?
It sounds like DialogueManager.StartDialogue probably via DialogueStart.TriggerDialogue is called from somewhere in either Awake or at least before your Start was executed.
Especially
DialogueManager.SetActive(true);
lets assume the DialogueManager object is inactive at first anyway. So maybe your stuff is called before it is set to active.
This might also be due to the Start where you set
InteractionNPCNameTextField.gameObject.SetActive(false);
so any component on this GameObject might not have its Start method getting called. Maybe you referenced the wrong GameObject here?
Debugging would help to figure out in which order your methods get called.
In general my thumb rule for initializing is
Do everything that depends only on yourself in Awake
Do everything that depends on other components being setup already in Start
This way you can (almost) always be sure that stuff is already initialized when you need it.
However, these are only guesses but
The simple solution here:
You could already solve this by simply initializing the sentences right away using
private readonly Queue<string> sentences = new Queue<string>();
now it is definitely initialized even before Start or Awake get called!
I want to have a singleton which will store, update and show player score through all levels (scenes), but something works wrong.
This my singletone script GameStatus.cs:
using UnityEngine;
using TMPro;
public class GameStatus : MonoBehaviour
{
public static GameStatus instance;
[SerializeField] int pointsPerBlock = 50;
[SerializeField] TextMeshProUGUI scoreText;
[SerializeField] public static int currentScore = 0;
private void Awake()
{
if (instance != null)
{
Destroy(gameObject);
}
else
{
instance = this;
DontDestroyOnLoad(gameObject);
}
}
public void AddToScore()
{
currentScore += pointsPerBlock;
scoreText.text = currentScore.ToString();
}
}
I also have another script for objects player need to destroy, called Block.cs. Here it is:
using UnityEngine;
public class Block : MonoBehaviour
{
Level level;
GameStatus gameStatus;
private void Start()
{
level = FindObjectOfType<Level>();
gameStatus = FindObjectOfType<GameStatus>();
level.CountBreakableBlocks();
}
private void OnCollisionEnter2D(Collision2D collision)
{
DestroyBlock();
}
private void DestroyBlock()
{
level.BlockDestroyed();
gameStatus.AddToScore();
Destroy(gameObject);
}
}
And on level 1 everything works fine, but when the game goes to the next level this happens:
Player score stops updating.
If I use Debug.Log(currentScore); in GameStatus.cs I can see that this variable doesn't change when player breaks blocks, but if use Debug.Log(gameStatus.currentScore); in Block.cs then I can see that this variable is getting updated.
Debug.Log(FindObjectsOfType().Length); shows that there is one GameStatus object in the first level and two objects in the next levels, although I can't see the second one GameStatus in hierarchy.
So my question is - what's wrong and how to fix it?
If you use singleton, there is no point to make
currentScore
static variable, just make it
public int currentScore;
Also in your block cs you can just call
GameStatus.instance.AddToScore();
No need to make reference at start