I want to have the player start from a start position at first. Then start from a checkpoint after they've completed level one. I've tried different iterations of this script, it is supposed to use a bool check if the player has passed through a trigger, and if they have their position will be equal to the checkpoint at Start. It has to remember the bool when the game is turned off and on again.
Right now the player always starts from the checkpoint.
I tried making my own boolean with playprefs but ended up using BoolPrefs, which still didn't work.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Player : MonoBehaviour
{
public Rigidbody player;
public Transform startPoint;
public Transform checkPoint;
private void Start()
{
if (PlayerPrefsX.GetBool("level01Complete", false))
{
player.transform.position = startPoint.position;
}
if (PlayerPrefsX.GetBool("level01Complete", true))
{
player.transform.position = checkPoint.position;
}
}
private void OnTriggerEnter(Collider other)
{
if (other.gameObject.tag == "HubTrigger")
{
PlayerPrefsX.SetBool("level01Complete", true);
}
else
{
PlayerPrefsX.SetBool("level01Complete", false);
}
}
}
Here is the BoolPrefs script I'm using currently.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerPrefsX
{
public static void SetBool(string name, bool booleanValue)
{
PlayerPrefs.SetInt(name, booleanValue ? 1 : 0);
}
public static bool GetBool(string name)
{
return PlayerPrefs.GetInt(name) == 1 ? true : false;
}
public static bool GetBool(string name, bool defaultValue)
{
if (PlayerPrefs.HasKey(name))
{
return GetBool(name);
}
return defaultValue;
}
}
I am new to using PlayerPrefs so there may just be something obvious that I'm overlooking.
HubTrigger is the trigger you pass through after completing level one. So it should be that the first time you play you start from one spot, then once you pass through hubtrigger, you've completed level one and from then on you start from the checkpoint when you load the game.
PlayerPrefsX looks fine. It just seems like you're using it incorrectly. You should check if (PlayerPrefsX.GetBool("level01Complete", false)), and if that's true, then set the checkpoint position, and set the start position otherwise:
private void Start()
{
if (PlayerPrefsX.GetBool("level01Complete", false))
{
player.transform.position = checkPoint.position;
}
else
{
player.transform.position = startPoint.position;
}
}
For OnTriggerEnter, you really only should set level01Complete there in the event you beat level 1:
private void OnTriggerEnter(Collider other)
{
if (other.gameObject.tag == "HubTrigger")
{
PlayerPrefsX.SetBool("level01Complete", true);
}
}
Related
So I'm new to C# I somewhat know Python I couldn't understand how functions work I tried doing something like this:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class collisiondetectorleft : MonoBehaviour
{
public class Triggerdetecting()
{
public void OnTriggerStay(Collider other)
{
if (other.attachedRigidbody)
other.attachedRigidbody.AddForce((Vector3.up * 10);
}
}
void FixedUpdate()
{
if (Input.GetKeyDown("space"))
{
//I'm so lost
Triggerdetecting objTriggerdetecting = new Triggerdetecting();
}
}
}
I'm trying to create some sort of hitbox by detecting trigger if a button pressed and meets the condition make the object more faster. I tried few ways to call function non of them worked. Thank you for your time. If you unable to understand what I meant you can ask me I'll try to explain in other ways.
Want something like this:
def detection():
if OnTriggerStay == True:
moveobject up
if Input.GetKeyDown("space")) == True:
detection()
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class collisiondetectorleft : MonoBehaviour
{
//create bool to set it true or false while inside the object
private bool _canHit;
private void Update()
{
if (_canHit)
{
if (Input.GetKeyDown(KeyCode.A))
{
_canHit = false;
//task
}
}
}
//set _canHit true if object enters trigger
private void OnTriggerEnter(Collider other)
{
if (other.attachedRigidbody)
_canHit = true;
}
//set _canHit false if object exits trigger
private void OnTriggerExit(Collider other)
{
if (other.attachedRigidbody)
_canHit = false;
}
}
I was able to detect and log while true but I didn't figured how to react to object that triggers
I would go the same route as you did in your answer attempt.
The last bit missing in order to b able to actually use the according object is simple: Instead of a bool rather directly store the object
public class collisiondetectorleft : MonoBehaviour
{
private Collider _currenTarget;
private void Update()
{
if (_currenTarget && Input.GetKeyDown(KeyCode.A))
{
Debug.Log($"I am interacting with {_currentTarget}");
_currenTarget = null;
}
}
private void OnTriggerEnter(Collider other)
{
if (!other.attachedRigidbody) return;
_currenTarget = other;
}
private void OnTriggerExit(Collider other)
{
if (other != _currenTarget) return;
_currenTarget = null;
}
}
My unity project is freezing and there are no errors before clicking play button after that it freezes the code:
In this code I am trying to detect if the player is triggering enemy collider with OnTriggerStay2D
so if it does I want the code to add score every second with IEnumerator function. But if the player is not colliding with the enemy for more than 2 seconds it gets destroyed.
The code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Trigger : MonoBehaviour
{
public GameObject other;
bool touching = false;
int score = 0;
public void Update()
{
AddScore();
}
private void OnTriggerStay2D(Collider2D other)
{
Debug.Log("Touching");
touching = true;
}
public void AddScore()
{
if(touching == true)
{
while (touching == true)
{
score++;
StartCoroutine(wait());
}
Debug.Log(score);
}
else
{
Debug.Log("Not Touching");
StartCoroutine(waiter());
}
}
IEnumerator waiter()
{
yield return new WaitForSecondsRealtime(2);
Destroy(other);
}
IEnumerator wait()
{
yield return new WaitForSecondsRealtime(1);
}
}
Just delete while (touching == true), that is breaking your game.
The if condition should be enough for the logic.
What I'm trying to do is have my player stop moving so I can play animation through a trigger-event or just a custscene.
What I expect was for one of them to trigger the timer then play animation>player move.. like a cut-scene
Also there are no errors In any of them They just didn't stop player from moving or just stop the player when starting the game(or when I press play it just set forwardMovement to 0)
Here's the code I use:
public class Player_controls : MonoBehaviour
{
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UIElements;
public class Player_controls : MonoBehaviour
{
public int forwardMovement = 1000;
public void Update()
{
rb.AddForce(0, 0, forwardMovement * Speed * Time.deltaTime);
}
}
}
Things that I tried:
public void ForwardMovement()
{
forwardMovement = 0;
Invoke("Action", 2f);
}
public void Action ()
{
forwardMovement = 1000 ;
}
Which only works for ForwardMovement(); method nothing else
I tried these two things also:
Public static class MonoExtensions
{
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
public float Delayer = 10f;
public static class MonoExtensions
{
public static void Timed_delay(this MonoBehaviour mono,Action function, float Delayer)
{
mono.StartCoroutine(Timed_delayRoutine(function,Delayer));
}
static IEnumerator Timed_delayRoutine(Action function, float Delayer)
{
yield return new WaitForSeconds(Delayer);
function();
}
public class `Player_Controls`: MonoBehaviour
{
public void PM ()
{
forwardMovement = 0;
}
void OnTriggerEnter(Collider other)
{
if (CompareTag("Power_up"))
{
this.Timed_delay(PM, Delayer);
}
}
}
Which just stop the player from moving an nothing else.
What I also tried was:
public class Player_Controls : MonoBehaviour
{
void Start()
{
StartCoroutine(ForwardMovement());
}
IEnumerator ForwardMovement()
{
forwardMovement = 0;
yield return new waitforseconds(Delayer);
forwardMovement = 1050;
}
void OnTriggerEnter(collider other)
{
if (CompareTag("Power_up"))
{
ForwardMovement();
}
}
}
Which did not work as in(it works but the timer part does nothing, so the player can't move when started the game )
Different way I tried
public class Player_Controls : MonoBehaviour
{
OnTriggerEnter(collider other)
{
Startcroutine(ForwardMovement ));
}
}
it didn't work but no Errors.
I tried this one by jazzhar:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UIElements;
public class Player_controls : MonoBehaviour
{
// Drag the player in the inspector here;
public Rigidbody rb;
// Youre speed variable for movement.
public float Speed = 5;
// Youre speed variable for movement.
public int forwardMovement = 1000;
// Set this "stopmoving" bool to true to prevent movement.
public bool stopMoving = false;
// Create and select the right layer in the inspector.
public LayerMask WichObjectStopsMovement;
public void Update()
{
// if stopMoving = true than Dont Add force.
if (stopMoving == false)
{
rb.AddForce(0, 0, forwardMovement * Speed * Time.deltaTime);
}
}
private void OnCollisionEnter(Collision collision)
{
// if you're player touches a object and that object's layer
// is the same as "WichObjectStopsMovement" than disable Movement.
if (collision.collider.gameObject.layer == WichObjectStopsMovement)
{
stopMoving = false;
}
}
}
It sorta works in a way if you set if
if (stopMoving == true)
{
rb.AddForce(0, 0, forwardMovement * Speed * Time.deltaTime);
}
and
if (collision.collider.gameObject.layer == WichObjectStopsMovement)
{
stopMoving = true;
}
then the player would be able to move but it will not trigger if hit the cube
it didn't work either but no Errors.
And some other timers I did but forgotten....
_________________________________________________________________March/6/21
public float Delayer = 10.0f;
I think found solution by doing this
private void OnTriggerEnter(Collider other)
{
if (CompareTag("Power_up"))
{
Delayer -= Time.deltaTime; <- this part giving me the error
if (Delayer => 0)
{
forwardMovement = 0;
}
}
}
but their one problem it giving me the this error Cannot convert lambda expression to type 'bool' because it is not a delegate type [Assembly-CSharp]csharp(CS1660) I don't know much about this even searching about doesn't help either
__________________________________________________________________March 28/21
this script is under player controls
this one works I made sure by doing Debug.Log("test");
void OnTriggerExit(Collider collision)
{
if (collision.gameObject.CompareTag("Power_up"))
{
forwardMovement = 0;
}
if (forwardMovement <= 0)
{
Debug.Log("test");
}
This might be a solution to you're problem, Fire-Source!:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UIElements;
public class Player_controls : MonoBehaviour
{
// Drag the player in the inspector here;
public Rigidbody rb;
// Youre speed variable for movement.
public float Speed = 5;
// Youre speed variable for movement.
public int forwardMovement = 1000;
// Set this "stopmoving" bool to true to prevent movement.
public bool stopMoving = false;
// Create and select the right layer in the inspector.
public LayerMask WichObjectStopsMovement;
public void Update()
{
// if stopMoving = true than Dont Add force.
if (stopMoving == false)
{
rb.AddForce(0, 0, forwardMovement * Speed * Time.deltaTime);
}
}
private void OnCollisionEnter(Collision collision)
{
// if youre player touches a object and that object's layer
// is the same as "WichObjectStopsMovement" than disable Movement.
if (collision.collider.gameObject.layer == WichObjectStopsMovement)
{
stopMoving = false;
}
}
}
This code uses a LayerMask, to create 1 click on any object and in the inspector go:
Click on Layer:
Add Layer:
Write in User Layer 6, StopMovement (or anything else).
Than in the object that should stop player movement:
Click on layer:
Than select the Layer that says StopMovement.
And in you're player's script drag the object into the rb variable.
and in "WichObjectStopsMovement" assign the StopMovement layer.
This should take care of everything is that ok?
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'm attempting to allow the players to open the door once they have located the key
The 'hasKey' value is currently managing if the players has the key with either true or false. i now need to know how to use this 'hasKey' boolean in another script; i've been trying for hours and getting no where so i'll post my code below and maybe someone knows whats going on, thanks in advance!
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
public class Detection : MonoBehaviour {
public GameObject objectToEnable;
public static bool Enabled = false;
public bool hasKey = false;
public DoorOpener _DoorOpener;
private void Update()
{
Debug.Log(hasKey);
if (Enabled)
{
objectToEnable.SetActive(true);
}
}
void OnMouseEnter()
{
Debug.Log("Enter");
}
void OnMouseExit()
{
Debug.Log("Exit");
}
void OnMouseUp()
{
Enabled = true;
hasKey = true;
Debug.Log("Pressed");
}
}
public class DoorOpener : MonoBehaviour
{
Animator animator;
bool JailDoorOpen;
public Detection _Detection;
void Start()
{
JailDoorOpen = false;
animator = GetComponent<Animator>();
}
void OnTriggerEnter(Collider JailDoorO)
{
if ((JailDoorO.gameObject.tag == "Player") && (_Detection.hasKey == true))
{
Debug.Log("Open Door");
JailDoorOpen = true;
jDoors("Open");
}
}
void jDoors (string direction)
{
animator.SetTrigger(direction);
}
}
enter code here
In your second script you have declared:
public Detection _Detection;
but you have not said what _Detection is assigned to. So it is just a blank instance of your Detection script. You need to reference the script that is attached to the specific object you are looking for.
For example if Detection and DoorOpener are both on the same gameobject you would do.
_Detection = gameObject.getComponent<Detection>();
or otherwise you could do something like...
_Detection = GameObject.FindWithTag('TagOfObjWithDetScript').getComponent<Detection>();
now the value of haskey in DoorOpener matches the value of haskey in the specific instance of the Detection script you are using.
If this is a local multiplayer game, you could store the boolean on the door object. You could also store it in a KeyManager and access it through a static variable.
If this is a network multiplayer game, you're going to have to store the variable in a manager somewhere and update each client when the state of that boolean changes.