Input.GetKeyDown(KeyCode.E) Isn't Working - c#

I have recently been making an inventory system, but I can't manage to get the UI to show up with Input.GetKeyDown like I've wanted to. Here is my code:
using UnityEngine;
public class Inventory : MonoBehaviour
{
public GameObject invUI;
public GameObject soulFragmentPanel;
private void Update()
{
if(Input.GetKeyDown(KeyCode.E))
{
invUI.SetActive(true);
soulFragmentPanel.SetActive(false);
}
if (Input.GetKeyUp(KeyCode.E))
{
invUI.SetActive(false);
soulFragmentPanel.SetActive(true);
}
if (invUI.activeSelf)
{
soulFragmentPanel.SetActive(false);
}
}
}

Can you check in unity? you turn off that object which contains the Inventory script.
you have to set the invUI and soulFragmentPanel in single canvas and take Inventory script in that canvas.
so your code is working properly.

Related

How to switch display/non-display by right-clicking in C# of Unity

I tried to toggle the visibility of the object with the following code.
However, when I right-clicked the first time, the object was hidden, but when I right-clicked the second time, the object was not displayed.
The object should appear on the second right click.
What's wrong with this code?
using UnityEngine;
public class EnvironmentSettings : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
if (Input.GetMouseButtonDown(1))
{
Debug.Log(this.gameObject.activeSelf);
if(this.gameObject.activeSelf)
{
this.gameObject.SetActive(false);
}
else
{
this.gameObject.SetActive(true);
}
}
}
}
If you disable the game object that hold the script, it can't work anymore since it's not active!
That's why you can hide the object, but not wake it up.
Use a TargetGameObject field, that you'll enable/disable. Like this :
public class EnvironmentSettings : MonoBehaviour
{
public GameObject TargetGameObject;
private void Update()
{
if (Input.GetMouseButtonDown(1))
TargetGameObject.SetActive(!TargetGameObject.activeSelf);
}
}
Put this script on a GameManger, or at least something that won't be disabled during play time, such as the main camera. Then slide your TargetGameObject to toggle into the field from the scene view.

Calling a script from NPCs in Unity to trigger dialogue

I have followed Brackeys tutorial on Youtube (https://www.youtube.com/watch?v=_nRzoTzeyxU) on how to create a dialogue system for a game. I am currently attempting to adapt this system to where the player can walk up to an NPC and press the "Submit" button to access their dialogue, instead of clicking a button on the canvas/UI like the video shows. To those who have played games like Super Mario64, The Legend of Zelda: Ocarina of time, or most games with text dialogue you may recognize this.
The Interactable script I created detects whether the player is within the collision sphere or not that the NPC has, and allows the player to press the "Submit" button on what is supposed to call the dialogue for the NPC in range. I'm just not sure how to call the script that I named DialogueTrigger that holds the dialogue for the NPC. That, or what I'm trying to accomplish is not being accomplished in the way that I am trying. Any help would be appreciated.
Interactable Script: `
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Interactable : MonoBehaviour {
private GameObject triggeringNpc;
private bool triggering;
public DialogueTrigger Diag;
void Start()
{
}
void Update()
{
if(triggering)
{
Debug.Log("Within Range");
if (Input.GetButtonDown("Submit"))
{
Debug.Log("Pressed the Interact Button");
Diag.TriggerDialogue();
}
}
}
void OnTriggerEnter(Collider other)
{
if(other.tag == "NPC")
{
triggering = true;
triggeringNpc = other.gameObject;
}
}
void OnTriggerExit(Collider other)
{
if(other.tag == "NPC")
{
triggering = false;
triggeringNpc = null;
}
}
}
`
Right now I can put a script for one NPC in the script and it works, but I would rather it call whatever Dialogue Trigger Script that the NPC has. I'm sure there's something I'm missing here.
This one is for Dialogue Trigger
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class DialogueTrigger : MonoBehaviour
{
public Dialogue dialogue;
public void TriggerDialogue ()
{
FindObjectOfType<DialogueManager>().StartDialogue(dialogue);
Debug.Log("dm called"); } else { Debug.Log("dm is null"); }
}
}
Solved this as soon as I posted it. Turns out I just needed to combine the Interactable script with the dialogue triggers script and rearranging the collision tags to hit the player that was tagged "Player" rather than having a separate script that detected collision to the NPC.

Go to next level when Key is grabbed by Player Unity 2d

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.

Check the previous loaded scene

I'm making a game in Unity3D with C# for mobile devices and can't figure out how to check which scene was loaded before the current scene. I need to check this to change the spawn point from the player gameobject. First I added a simple script to my buttons (loadnextscene and loadprevscene)
public class SwitchScene : MonoBehaviour {
public int sceneNumber;
public void LoadScene(int sceneNumber) {
Application.LoadLevel(sceneNumber);
}
}
A second scripts handles the touch input from the user and changes the movement of the player object.
So, for example: If the player clicks on the "load previous scene" button in the second Level to switch to the first level again, I want to set the spawn point of the player object on the right half on the screen and not on the left side like when the game was started the first time.
I tried it with Singleton and PlayerPrefs, but it did not work out.
You need to save the scene number to some variable before LoadScene, then check it after the scene loaded.
The only problem is that this variable will be destroyed after the new scene is loaded. So, to prevent it, you can use DontDestroyOnLoad. Here is what you do:
First, create a new empty game object, and attach the following script to it:
using UnityEngine;
using System.Collections;
public class Indestructable : MonoBehaviour {
public static Indestructable instance = null;
// For sake of example, assume -1 indicates first scene
public int prevScene = -1;
void Awake() {
// If we don't have an instance set - set it now
if(!instance )
instance = this;
// Otherwise, its a double, we dont need it - destroy
else {
Destroy(this.gameObject) ;
return;
}
DontDestroyOnLoad(this.gameObject) ;
}
}
And now, before you load, save the scene number in the Indestructable object:
public class SwitchScene : MonoBehaviour {
public int sceneNumber;
public void LoadScene(int sceneNumber) {
Indestructable.instance.prevScene = Application.loadedLevel;
Application.LoadLevel(sceneNumber);
}
}
And last, in your scene Start() check Indestructable.instance.prevScene and do your magic accordingly.
More info here:
http://docs.unity3d.com/ScriptReference/Object.DontDestroyOnLoad.html
*I did not compile the code, so there may be some errors, but this is the general idea.
Why did the PlayerPrefs approach did not work?
I think its the easiest way to solve your problem.
public class FirstLevel : MonoBehaviour {
public void Start() {
PlayerPrefs.SetString("SceneNumber", SceneManager.GetActiveScene().name);
}
}
And then in the second scene simply read the saved PlayerPrefs
public class SecondLevel : MonoBehaviour {
string PrevScene;
public void Start() {
PrevScene = PlayerPrefs.GetString("SceneNumber");
// if there will be a third scene, etc.
PlayerPrefs.SetString("SceneNumber", SceneManager.GetActiveScene().name);
}
public void GoToPrevScene() {
SceneManager.LoadScene(PrevScene);
}
}
You can solve this problem with a single static member variable in the SwitchScene class. No need for the singleton pattern or DontDestroyOnLoad.
public class SwitchScene : MonoBehaviour
{
public int sceneNumber;
private static int previousScene;
private int oldPreviousScene;
void Start()
{
oldPreviousScene = previousScene;
previousScene = sceneNumber;
}
public void HandleLoadPrevButtonClick()
{
SceneManager.LoadScene(oldPreviousScene);
}
}

how do I extend a class from another script in c# Unity

I'm trying to extend a base class on my player object.
player has damage script that looks like this
using UnityEngine;
using System.Collections;
public class Damage : MonoBehaviour
{
public int health = 100;
public virtual void ReceiveDamage(int damageAmount)
{
Debug.Log ("Original");
}
}
And then the same player has another script like this :
using UnityEngine;
using System.Collections;
public class playerDamage : Damage
{
public override void ReceiveDamage(int damageAmount)
{
Debug.Log ("Extended");
}
}
But when I call the script from a 3rd scrip on another object like this:
var damageScript = collision.gameObject.GetComponent<Damage>();
if( damageScript)
{
damageScript.ReceiveDamage(damageAmount);
}
the only response to the log is "Original"
Shouldn't the child be called and "Extended" written to the log?
There are several ways to do this. The easiest one is to SendMessage.
collision.gameObject.SendMessage("ReceiveDamage", damageAmount);
Whatever implementation of ReceivedDamage that the collision GameObject has, that will be the one that is called. This is awesome because you don't need to specify the type yourself nor use GetComponent.
Important Extra Information
In any implementation that you choose the key step is to make sure that the right script is attached to the collision.gameObject. If you attach both scripts then you are playing with fire.
To avoid playing with fire please make Damage an abstract class.
public abstract class Damage : MonoBehaviour
{
public int health = 100;
public virtual void ReceiveDamage(int damageAmount)
{
Debug.Log ("Original");
}
}
Abstract will give you the same functionality you want, except that Unity3d won't let you attach Damage to the GameObjects, which is good to avoid mistakes. You will always have the option to have the original ReceiveDamage and the choice to override it on future classes that inherit from Damage, like this:
public class Example : Damage
{
// This one still has ReceiveDamage but it happens in the base class.
}
or
public class PlayerDamage : Damage
{
public override void ReceiveDamage(int damageAmount)
{
Debug.Log("Extended");
}
}
I think when you call this line:
var damageScript = collision.gameObject.GetComponent<Damage>();
It gets the component by name, which in this case would be the Damage script, not the playerDamage script.
In you script it should be:
var damageScript = collision.gameObject.GetComponent<playerDamage>();
if( damageScript)
{
damageScript.ReceiveDamage(damageAmount);
}

Categories