I have a scene with multiple triggers and a Player with collider. My idea is to have one script to deal with all interactions between triggers and Player collider. I thought that using the same script to different GameObjects would be enough but this thing doesn't work properly. While working with one trigger I need to change one GameObject attached to this trigger but the other GameObjects with this script are changing as well.
One more detail about script is that I have two types of triggers: one is for GameObjects that need some input from user, some doesn't need it. I check it by checking two fields firstChoiceText and secondChoiceText. And if they are empty, the interaction with GameObject doesn't need any choice from the player. Otherwise, I show a plane with two option and change the text of this options using firstChoiceTextfield and secondChoiceTextfield.
So the main idea of script is that when the Player enter the trigger the script activates E key of keyboard. And if we press the E button and if this interaction wasn't done yet, we go further. We check the type of trigger and if we need to make a choice, we activate so called choiceMode of PlayerScript. PlayerScript is just a script for movements of the player, and we need choiceMode just to use W and S keys to select the choice. We make our choice and return to usual movement of the player. If we don't need to make a choice we just do some action and mark the trigger as isDone.
Everything works great with one trigger but when I use several triggers and GameObjects with InteractionScript, all this triggers are mixed up. While working with one trigger I accidentally change the other script. And I don't quite understand how to separate this scripts from each other.
Can anybody give me some piece of advice?
using UnityEngine;
using UnityEngine.UI;
public class InteractionScript : MonoBehaviour
{
[SerializeField]
private GameObject buttonE;
[SerializeField]
private GameObject choiceMenu;
[SerializeField]
private PlayerScript ps;
private int choiceNum = 0;
[SerializeField]
private Transform choicePoint;
[SerializeField]
private Text firstChoiceTextfield;
[SerializeField]
private Text secondChoiceTextfield;
[SerializeField]
private string firstChoiceText;
[SerializeField]
private string secondChoiceText;
[SerializeField]
private bool enteredMe;
[SerializeField]
private bool isDone;
void OnTriggerEnter2D() {
if (!isDone) {
enteredMe = true;
buttonE.SetActive(true);
Debug.Log("++");
}
}
void OnTriggerExit2D() {
if (!isDone) {
buttonE.SetActive(false);
enteredMe = false;
}
}
void Update() {
if (!isDone) {
if (Input.GetKeyDown(KeyCode.E) && buttonE.activeSelf && enteredMe) {
if (firstChoiceText != "" && secondChoiceText != "") {
choiceMenu.SetActive(true);
buttonE.SetActive(false);
ps.choiceMode = true;
Debug.Log("with choice");
} else {
Debug.Log("without choice");
//Action
buttonE.SetActive(false);
isDone = true;
}
}
}
if (ps.choiceMode) {
firstChoiceTextfield.text = firstChoiceText;
secondChoiceTextfield.text = secondChoiceText;
if (Input.GetKeyDown(KeyCode.W)) {
choiceNum += 1;
}
if (Input.GetKeyDown(KeyCode.S)) {
choiceNum -= 1;
}
if (choiceNum > 1) {
choiceNum = 0;
} else if (choiceNum < 0) {
choiceNum = 1;
}
if (choiceNum == 0) {
choicePoint.localPosition = new Vector3(0f, 24f, 0f);
if (Input.GetKeyDown(KeyCode.Return)) {
Debug.Log("choice1");
choiceMenu.SetActive(false);
isDone = true;
enteredMe = false;
ps.choiceMode = false;
}
} else if (choiceNum == 1) {
choicePoint.localPosition = new Vector3(0f, -21.5f, 0f);
if (Input.GetKeyDown(KeyCode.Return)) {
Debug.Log("choice2");
choiceMenu.SetActive(false);
isDone = true;
enteredMe = false;
ps.choiceMode = false;
}
}
}
}
}
Related
I have a simple jumping action in my game. The player presses jump, gets launched into the air, transitions to an air-state and falls down to ground again. The usual stuff.
However, if the player lands on the ground and the user is still holding the jump key, the player automatically jumps again upon landing. I don't want that. I want the user to let go of the key before being able to jump again.
Here's a simplified version of my player movement code, with only the nessessary stuff in.
public class GenesisPhysics : MonoBehaviour {
public bool isGrounded = true;
public bool jumpIsPressed;
public IA inputActions; // New input system's Input Action Asset C# class
private void Awake()
{
inputActions = new IA();
// Movement actions stuff...
inputActions.PlayerControls2D.Jump.performed += jumpContext => jumpIsPressed = true;
inputActions.PlayerControls2D.Jump.canceled += jumpContext => jumpIsPressed = false;
}
private void FixedUpdate()
{
if(isGrounded)
{
ExecuteGroundStateLoop()
} else {
ExecuteAirStateLoop()
}
}
private void ExecuteGroundStateLoop()
{
// Do stuff...
if(jumpPressed) {
isGrounded = false;
// Set x and y speeds to be applied in Air state
} else {
// Do some more stuff...
}
}
private void ExecuteAirStateLoop()
{
// Applying gravity, jump force, checking for ground and other stuff...
// If ground is found, set isGrounded to true.
}
void OnEnable()
{
inputActions.Enable()
}
void OnDisable()
{
inputActions.Disable()
}
}
This might not be enough code to fix the issue. I'll update this post if more is needed.
Create a new bool variable "jumpPressAvailable" and set it to true in the beginning. Use this new variable to control, if a jump is available. For example, if jump button is pressed, set "jumpPressAvailable" to false, and if jump button is released or "NOT pressed", set "jumpPressAvailable" to true again. A jump can only be started if jump button is pressed and "jumpPressAvailable" is true.
public bool jumpPressAvailable=true;
Add some lines in the Ground State Loop:
if(jumpPressed && jumpPressAvailable) {
isGrounded = false;
jumpPressAvailable = false;
// Set x and y speeds to be applied in Air state
} else {
if(jumpPressed == false)
{
jumpPressAvailable = true;
}
// Do some more stuff...
}
I'm probably not doing this properly at all. I'm trying to make a script that will allow dropping and throwing of a weapon, and I'm trying to keep the script on the weapon for prefab.
void PrepareObject() {
Rigidbody gameObjectsRigidBody = Stick.AddComponent<Rigidbody>();
gameObjectsRigidBody.mass = 0.1f;
Debug.Log("added rigidbody to weapon");
}
public void OnThrow() {
anims.SetTrigger("isThrowing");
PrepareObject();
StartCoroutine(LetGo());
}
private IEnumerator LetGo() {
Debug.Log("let go of weapon");
yield return new WaitForSeconds(1f);
Hand.transform.DetachChildren();
beingThrown = true;
}
public void OnInteract() {
playerInRange = Physics.CheckSphere(Stick.transform.position, interactRange, layerPlayer);
Debug.Log("Pressed interact");
if (playerInRange && beingThrown) {
Debug.Log("attempted pickup");
Stick.transform.SetParent(HandTransform);
} else return;
beingThrown = false;
}
When using this code, I get OnInteract() while I'm holding the weapon, but as soon as I LetGo(), I no longer get OnInteract(). I am using the Unity Input System BroadcastMessage() on the parent.. I'm kind of lost on what to do, any suggestions?
Im working on an 2d local multiplayer platformer Game. In the game are obstacles (Spikes), when the player collides with them the player will die. I want the Players of the game to decide if they would like to enable or disable the Spikes (the link leads to an image that will help understanding my problem)by pressing a Key. I already wrote a script for that and added it to my dontdestroyOnLoad GameManager. So all my spikes I built are the same Prefabs. My idea was to disable the main Prefab from the Project folder to disable all the spikes in every scene, until you press a Key to reactivate them again. The Problem is, that only the texture itself in the Project Panel disables and not the Spikes Prefabs in the Hierarchy, because the prefabs turn into regular gameObjects. How can I fix this?
My Script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//using System.Threading;
public class DisableSpikes : MonoBehaviour
{
[Header("Spikes")]
public KeyCode disableSpikes;
public float time;
public GameObject prefabSpikes;
public bool toggleSpikes = true;
[Header("Player Green")]
public KeyCode disableGreen;
public GameObject prefabGreen;
public bool toggleGreen = true;
[Header("Reset Score")]
public KeyCode resetScore;
// Start is called before the first frame update
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(disableSpikes) && toggleSpikes == true)
{
prefabSpikes.SetActive(false);
Debug.Log("Disable");
//Thread.Sleep(1000);
Invoke("SetFalse", time);
}
if (Input.GetKeyDown(disableSpikes) && toggleSpikes == false)
{
prefabSpikes.SetActive(true);
Debug.Log("Anable");
//Thread.Sleep(1000);
Invoke("SetTrue", time);
}
if (Input.GetKeyDown(disableGreen) && toggleGreen == true)
{
prefabGreen.SetActive(false);
Debug.Log("Disable");
//Thread.Sleep(1000);
Invoke("SetFalse", time);
}
if (Input.GetKeyDown(disableGreen) && toggleGreen == false)
{
prefabGreen.SetActive(true);
Debug.Log("Anable");
//Thread.Sleep(1000);
Invoke("SetTrue", time);
}
if (Input.GetKeyDown(resetScore))
{
ScoreScriptBlue.scoreValueBlue = 0;
ScoreScriptRed.scoreValueRed = 0;
ScoreScriptGreen.scoreValueGreen = 0;
RoundScript.scoreValueRound = 0;
TimeScript.scoreValueTime = 0;
}
}
public void SetFalse()
{
toggleGreen = false;
toggleSpikes = false;
}
public void SetTrue()
{
toggleGreen = true;
toggleSpikes = true;
}
}
void Update() {
if (Input.GetKeyDown(disableSpikes) && toggleSpikes == true){
// show
// renderer.enabled = true;
gameObject.GetComponent<Renderer>().enabled = true;
}
if (Input.GetKeyDown(disableSpikes) && toggleSpikes == false) {
// hide
// renderer.enabled = false;
gameObject.GetComponent<Renderer>().enabled = false;
}
}
I am very new to programming and Unity so please have patience. I am trying to disable a collider for a specified amount of time upon pressing a button (In this case, the button "s"). I have been trying to do this by using the "WaitForSeconds" command but I have never used it before and I don't know it works, but I tried anyway and as I expected it didn't work. I have to mention that the simulation does run with no errors but when I press "s" the collider doesn't disable at all. As I have mentioned I am very new to programming and Unity so I apologize if I don't understand some solutions you may suggest. Anyways here is the code
{
public bool IsFacingR = true;
public bool IsFacingL = false;
public Rigidbody2D RB;
public BoxCollider2D m_col;
void Update()
{
if (Input.GetKeyDown(KeyCode.D))
{
IsFacingR = true;
IsFacingL = false;
}
if (Input.GetKeyDown(KeyCode.A))
{
IsFacingR = false;
IsFacingL = true;
}
if (Input.GetKeyDown(KeyCode.S))
{
Slider();
StartCoroutine(SlideCol());
m_col.enabled = false;
}
}
void Slider()
{
if (IsFacingR == true)
{
RB.AddForce(Vector2.right * 9999f);
}
if (IsFacingL == true)
{
RB.AddForce(-Vector2.right * 9999f);
}
}
IEnumerator SlideCol()
{
yield return new WaitForSeconds(1);
m_col.enabled = true;
}
}
Well i tried your code in my project and it works fine. I can see collider disable for one second. Maybe there is someting that makes your collider always enable.
I'm learning Unity but my key press isn't being detected
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Player : MonoBehaviour
{
public Rigidbody myBody;
private float time = 0.0f;
private bool isMoving = false;
private bool isJumpPressed = false;
void Start(){
myBody = GetComponent<Rigidbody>();
}
void Update()
{
isJumpPressed = Input.GetKeyDown(KeyCode.Space);
Debug.Log(isJumpPressed);
}
void FixedUpdate(){
if(isJumpPressed){
myBody.velocity = new Vector3(0,10,0);
isMoving = true;
Debug.Log("jump");
}
if(isMoving){
time = time + Time.fixedDeltaTime;
if(time>10.0f)
{
//Debug.Log( Debug.Log(gameObject.transform.position.y + " : " + time));
time = 0.0f;
}
}
}
}
why isJumpPressed always false. What am I doing wrong? From what I understand this should work but I'm obviously missing something
UPDATE:
Thanks to everyone who proposed ideas. I got the isJumpPressed to return true when I stopped trying to detect the space bar.
isJumpPressed = Input.GetKeyDown("a");
anyone got any ideas why this would work and not
isJumpPressed = Input.GetKeyDown(KeyCode.Space);
or
isJumpPressed = Input.GetKeyDown("space");
UPDATE 2:
Apparently this is a bug in Linux. I've read it won't happen when the game is built just in the editor. I've found a workaround at
https://forum.unity.com/threads/space-not-working.946974/?_ga=2.25366461.1247665695.1598713842-86850982.1598713842#post-6188199
If any Googler's Stumble upon this issue reference the following code because this is working for me.
public class Player : MonoBehaviour
{
public Rigidbody myBody;
private float time = 0.0f;
private bool isMoving = false;
private bool isJumpPressed = false;
void Start(){
myBody = GetComponent<Rigidbody>();
}
void Update()
{
isJumpPressed = Input.GetKeyDown(SpacebarKey());
if(isJumpPressed)
{
Debug.Log(isJumpPressed);
}
}
void FixedUpdate(){
if(isJumpPressed){
myBody.velocity = new Vector3(0,10,0);
isMoving = true;
Debug.Log("jump");
}
if(isMoving){
time = time + Time.fixedDeltaTime;
if(time>10.0f)
{
//Debug.Log( Debug.Log(gameObject.transform.position.y + " : " + time));
time = 0.0f;
}
}
}
public static KeyCode SpacebarKey() {
if (Application.isEditor) return KeyCode.O;
else return KeyCode.Space;
}
}
The problem is that FixedUpdate and Update are not called one after the other. Update is called once per frame and FixedUpdate is called once per physics update (default is 50 updates per second).
So the following could happen:
Update is called -> GetKeyDown is true (this frame only) -> isJumpPressed = true
Update is called -> GetKeyDown is false -> isJumpPressed = false
FixedUpdate is called -> isJumpPressed is false
Here is an example that prints "Update Jump" every time you press space, and "FixedUpdate Jump" only sometimes when you press space. Do not do this:
bool isJumpPressed;
void Update()
{
isJumpPressed = Input.GetKeyDown(KeyCode.Space);
if (isJumpPressed)
{
Debug.Log("Update Jump");
}
}
private void FixedUpdate()
{
if (isJumpPressed)
{
Debug.Log("FixedUpdate Jump");
}
}
Do this instead:
bool isJumpPressed;
void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
isJumpPressed = true;
Debug.Log("Update Jump");
}
}
private void FixedUpdate()
{
if (isJumpPressed)
{
Debug.Log("FixedUpdate Jump");
isJumpPressed = false;
}
}
One possible problem is that your project might be using the new Input System package. If you are using this package, the old Input Manager functions will not work. To check this, go to Edit > Project Settings... > Player > Other Settings and Active Input Handling should be set to Input Manager (Old) (or Both might also work).
If you actually want to use the Input System package, you have to install it if you don't already have it, and you would check if the spacebar is pressed like so:
using UnityEngine.InputSystem;
...
jumpPressed = Keyboard.current.space.wasPressedThisFrame;
I had the same issue. Spend some hours trying to figure out.
Maybe all was good from the beginning until I figured out.
When you I executed the play to see the result and test the movement, by mistake I chose the scene tab. If I want to see the result (to play) I must click the "Game Tab". In Game Tab the keys were detected.enter image description here