I trying to get the enemy ship to shoot the player ship tagged player
I receive one error: Assets/Scripts/EnemyAttack.cs(11,13): error CS0246: The type or namespace name `EnemyAtack' could not be found. Are you missing an assembly reference? I tried creating a class for the enemy attack but did not work. Any feedback is appreciated.
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyAttack : MonoBehaviour
{
[SerializeField] GameObject[] enemyGuns;
// Start is called before the first frame update
void Start()
{
AddSphereCollider();
}
private void AddSphereCollider()
{
Collider sphereCollider = gameObject.AddComponent<SphereCollider>();
sphereCollider.isTrigger = false;
}
void OnCollisionEnter(Collision col)
{
if (col.gameObject.name == "player")
{
Destroy(col.gameObject);
}
}
}
Stop() and PlayOneShot() are both functions associated with the AudioSource class.
AudioSources are used to play AudioClips, in this case you need to add an AudioSource reference to your monobehaviour and add an AudioSource to your prefab, then link the reference and call your PlayOneShot() and Stop() functions on the AudioSource instead.
The other issue is your AudioClip is named LaserSound and your Monobehaviour is also called LaserSound.
Rename one or the other.
Change
[SerializeField] private AudioClip LaserSound;
to
[SerializeField] private AudioClip laserSound;
and that should work. "AudioClip LaserSound" is basically the equivalent of "Classname AnotherClassname"
Related
I'm trying to implement chest mechanic in my game. When a user touches to chest, chest disappears and heart shows up. When player touches the instantiated heart, it must disappear and add 1 to life value, but the script is not working.
Chest.cs:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Chest : MonoBehaviour
{
public GameObject heart;
public GameObject _heart; //Instantiated heart.
void OnTriggerEnter2D(Collider2D col){
if (col.gameObject.tag == "Player"){
Vector3 insPos = transform.position;
_heart = Instantiate(heart,new Vector3(insPos.x,insPos.y+0.5f,insPos.z),Quaternion.identity);
_heart.AddComponent<Heart>();
_heart.GetComponent<Heart>().ls = GameObject.FindGameObjectWithTag("Player").GetComponent<LifeSystem>();
Destroy(gameObject);
}
}
}
Heart.cs:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Heart : MonoBehaviour
{
public LifeSystem ls;
void OnTriggerEnter2D(Collider2D col){
if (col.gameObject.tag == "Player"){
SoundManager.PlaySound("CollectCoinSound");
ls.lifes += 1;
Destroy(gameObject);
}
}
}
I check the components of the instantiated heart when player touches the chest and I can see that life system reference is added and so heart script is.
Thanks for your time.
You need to meet these conditions in order for OnTriggerEnter2D to be called on the spawned Hearth:
At least one between Player and Hearth need to have a Rigidbody2D component
Both Player and Hearth need to have a collider with IsTrigger = true
Player and Hearth GameObjects need to be on two interacting layers in the collision matrix
The Hearth component needs to be either on the same GameObject with a collider or on the same GameObject with the RigidBody2D
I actually simplified rules 1 and 2 a bit to show the most common use-case: if you want to know the actual rules for collisions, you can find them here (see the matrix at the bottom).
Besides the general collision rules I would make sure your fields have the correct type in the first place and already attach the Heart component to your prefab.
Also there is no need for find .. You already know the reference to the player you are colliding with
public class Chest : MonoBehaviour
{
public Heart heartPrefab;
void OnTriggerEnter2D(Collider2D col)
{
if (col.CompareTag("Player"))
{
Instantiate(heart, transform.position + Vector3.up * 0.5f), Quaternion.identity);
Destroy(gameObject);
}
}
}
and then simply do
public class Heart : MonoBehaviour
{
private void OnTriggerEnter2D(Collider2D col)
{
if (col.TryGetComponent<LifeSystem>(out var ls))
{
SoundManager.PlaySound("CollectCoinSound");
ls.lifes += 1;
Destroy(gameObject);
}
}
}
and rather have the LifeSystem attached to your player object.
In general I would kind of expect both eventually triggered at the same time since the heart might be already triggered if spawning right where the player is
I am making a game and in the game im trying to make the enemy go towards the player when the player steps into the sight of the enemy. I cant figure out how to make the name (player) mean anything im very new at this its my second attempt on makin a game please help me im very confused im running c#
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Enemy : MonoBehaviour
{
private Transform _target;
[SerializeField] private float _speed = 9;
void Awake() {
_target = FindObjectOfType(Player)().transform;
}
void update() {
transform.position = Vector3.MoveTowards(transform.position,_target.position, _speed * Time.deltaTime);
}
}
You need to use the typeof operator instead of passing the class name.
void Awake() {
_target = FindObjectOfType(typeof(Player))().transform;
}
I have already tried to look into this... but no luck..
Sprite renderer, and mover references, work fine they appear in the inspector as I want them to.
However I am having issues in FILE 2 I am unsure of how to Serialize the Animator in the inspector.
FILE 1
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[CreateAssetMenu(fileName = "EnemyConfig", menuName = "Enemies/Enemy config", order = 0)]
public class EnemyConfig : ScriptableObject
{
public float moverSpeed;
//public float zRotation;
public Sprite sprite;
public Animator animator;
}
FILE 2
//EnemyController.CS
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyController : MonoBehaviour
{
[HideInInspector]
public EnemyConfig config;
[SerializeField]
private SpriteRenderer spriteRenderer;
//Want to get a reference to the animator component appear in the inspector
//This is my issue...--------------------------------------]
[SerializeField]
private GetComponent<Animator> animatorController;
//----------------------------
private Mover mover;
private void Start()
{
mover = GetComponent<Mover>();
if(mover != null)
{
mover.speed = config.moverSpeed;
}
if(config.sprite != null)
{
spriteRenderer.sprite = config.sprite;
}
// related to the animator
if(config.animator != null)
{
animatorController.animator = config.animator;
}
}
}
Here you can see how the Sprite reference, and mover reference appear in the inspector.
I am trying to do the same with the Animator
GetComponent<T> is a method, it is not a type. So, you can't declare a field with this as its type. I would be surprised if this code actually even compiles. What you want is simply
[SerializeField]
private Animator animator;
Note that AnimatorController is an Editor-only class; you can't include it in your game code. Hence why you want Animator here.
Another thing to consider is, is the Animator component going to be on the same game object? If so, you don't need to serialize the reference - that would only be useful if it's going to be on a different game object, and you need to store that link at edit time.
If the Animator component is on the same object, you can do this:
private Animator animator;
void Start()
{
animator = GetComponent<Animator>();
}
The advantage is that you won't have to make sure the reference stays up-to-date, it will be connected whenever the gameplay starts. This, by the way, is the correct use of GetComponent<T> - since it's a method, you can call it within another method, not where you had it in your File2.
Brand new to C# and Unity.Please be nice I've been at this all night. Every tutorial I poor through says changing an object from invisible to visible is as simple as setting the game object to on. However Unity gives me an error when I declare a game object in this script. The objective is, when the trigger is entered, several game objects called 'spawn' will become visible.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class collider : MonoBehaviour
{
public gameObject Spawn; // I get error On this line that type is expected,
//not property. It wants a Transform>
private Rigidbody rb;
void Start ()
{
rb = GetComponent<Rigidbody>();
}
void OnTriggerEnter(BoxCollider other)
{
if (other.gameObject.CompareTag("Player"))
{
Spawn.SetActive(true);
}
}
}
gameObject isn't a type, but GameObject is.
Get rid of public gameObject Spawn; and use public GameObject Spawn; to declare a GameObject property called Spawn
I need some help with a feature I'm implementing for a game made in Unity 2D.
The player must take a key in order to unlock a door (maybe showing an animation) and when the player go in front of that door if he has the key, he will automatically go to the next level.
I need help, cause the door is not letting go to the next level.
Here is the KEY code/script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
public class KeyScript : MonoBehaviour {
//public AudioSource coinSoundEffect;
public AudioClip key1;
void Awake () {
//source = GetComponent<AudioSource>();
}
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
}
void OnCollisionEnter2D (Collision2D other) {
Debug.Log("Chiave Presa");
if(other.gameObject.tag =="Player")
GameObject.Find("KeyDoor").SendMessage("HitKey");
SoundManager2D.playOneShotSound(key1);
}
}
Here is the DOOR code/script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
public class DoorScript : MonoBehaviour {
public bool key = false;
public string nextLevelName;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
}
void HitKey (){
Debug.Log("La porta รจ sbloccata");
key = true;
Destroy (GameObject.Find ("Key"));
}
void OnCollisionEnter2D (Collision2D other){
if(other.gameObject.tag == "Player"){
if (key == true){
Application.LoadLevel(nextLevelName);
//Destroy(gameObject);
//GameObject.Find("Key").SendMessage("DestroyKey"); //If you also want to destroy the key
//GoToNextLevel ();
}
}
}
void OnTriggerEnter2D (Collision2D other)
{
Application.LoadLevel(nextLevelName);
}
public virtual void GoToNextLevel()
{
//loadingImage.SetActive(true);
Application.LoadLevel(nextLevelName);
}
}
The code works but when the player goes in front of the door, he is not passing to the next level.
Any help or hint appreciated.
Cheers
First of all, you're missing one thing:
unity is Component based engine
This means you should make interactions between Components, not GameObjects.
In your script there's a public field public bool key which should not be accessible from the outside. But if you're looking for simple and wrong answer that will work then you can just replace this line :
GameObject.Find("KeyDoor").SendMessage("HitKey");
Into this one :
GameObject.Find("KeyDoor").GetComponent<DoorScript>().key = true;
In that case you'll end up with messy code and unstable game. What I can recommend to you as an good alternative is to rewrite your logic a bit.
Instead of making a MonoBehaviour which is not needed you can just create a Component :
public class KeyComponent : Component
{
[SerializeField]
AudioClip m_KeyPickupSound;
[SerializeField]
bool m_IsPickedUp;
public bool PickedUp
{
get { return m_IsPickedUp; }
}
public void PickUp()
{
m_IsPickedUp = true;
SoundManager2D.playOneShotSound(m_KeyPickupSound);
}
}
Now attach this into your Player's Components list and in your door script do:
void OnCollisionEnter2D (Collision2D other)
{
if(other.GetComponent<KeyComponent>() != null && other.GetComponent<KeyComponent>().PickedUp)
{
SceneManager.LoadScene(2);
}
}
Now only thing left is to update your Player's MonoBehaviour and add simple collision check :
void OnCollisionEnter2D(Collision2D other)
{
if(other.tag == "TAG_FOR_KEY")
GetComponent<DoorScript>().PickUp();
}
Now you're interacting with Components and not GameObject which then require less effort changing some scripts.
First off, you should change Application.LoadLevel to SceneManager.LoadScene. The first is obsolete in the newer versions of unity.
Second you need to make sure that your scenes are actually registered in File -> BuildSettings and the parameter you pass to LoadScene matches either the index in that list or the name as string.
Make sure your player needs to have a Rigidbody2D and a Collider2D and the door has a Collider2D component
If your doors Collider2D is a trigger you must use void OnTriggerEnter2D(Collider2D other).
Another problem may be that "Level 2" isn't added to your build settings, make sure that it is added to the level's list.
Answering your last comment as it seemed the problem was that the Collider2D on the door, you can make this in a lot of ways, the easiest way is this:
Add a public string variable called nextLevelName in your Door's script, then when calling LoadLevel, use this variable. You can change the value from the inspector in each level. The problem with this is that if you rearrange the levels then you need to change the strings in each level.
The best solution in that case is this one:
int currentLevelNum = SceneManager.GetActiveScene().buildIndex;
SceneManager.LoadScene(currentLevelNum+1);
This way if you have your levels in order in your build settings you don't need to do anything else.