Is there a way to disable and enable player input?
Currently, I have a script that takes in player input and I’m wondering if in another script,
I can temporarily disable player input and later re-enable it.
Edit: I want to display player input and have the player-object move via script (like its moving on a conveyor belt).
Sorry, I’m still fairly new to all this.
Thanks for your time and hep.
at the moment, no. The most simple approach to this is to have a boolean you can set somewhere (gamemanager is handy) and use that to govern the user input.
the unity devs recently announced a new approach they are working on for input control, from the limited information I’ve seen about it they might have included this feature but it’ll be a while coming yet.
I’ve always wrapped the Input class with my own class that forwards the input tests. This way 1) I don’t have magic strings everywhere, and 2) I can easily change from keyboard/mouse to gamepad by just using a different implementation of the wrapper, and 3) you can turn it off by toggling the wrapper.
Here’s a really basic example… very basic.
public class MyGamePad
{
public bool isDisabled;
public Vector2 GetMovementAxis()
{
if (this.isDisabled) return Vector2.zero;
return Input.GetAxis("Movement");
}
public bool GetAttackDown()
{
if (this.isDisabled) return false;
return Input.GetButtonDown("Attack");
}
//... etc etc
}
Hi guys, sorry long post and sorry if this is against forum rules but I got a problem trying to implement your folks’ suggestion (or at least I like to think that’s what I’m doing, haha).
So when I try to run this, I get the NullReferenceException error at the PlayerTest01 MovementInput function (the part that is commented out).
Specifically:
if(conveyorReference.conveyorInfo.isDisabled)
I think I have the necessary parts, but I’m at a loss. Any help would be greatly appreciated.
using UnityEngine;
using System.Collections;
[RequireComponent (typeof(Controller03))]
public class PlayerTest01 : MonoBehaviour {
Controller03 controller03;
Conveyor conveyorReference;
void Start()
{
controller03 = GetComponent<Controller03>();
conveyorReference = GetComponent<Conveyor>();
}
void Update()
{
MovementInput();
JumpInput();
}
Vector2 MovementInput()
{
/*
if(conveyorReference.conveyorInfo.isDisabled)
{
Debug.Log("We did it?");
return Vector3.zero;
}
*/
// else
}
using UnityEngine;
using System.Collections;
public class Conveyor : Controller03 {
public LayerMask conveyorMask;
public Vector3 move;
[HideInInspector]
public BoxCollider2D conveyorBoxCollider2D;
public ConveyorInfo conveyorInfo;
void Awake()
{
// Debug.Log("Awake.");
}
void Update()
{
Debug.Log("isDisabled: " + conveyorInfo.isDisabled);
conveyorInfo.Reset();
Vector3 velocity = move * Time.deltaTime;
ConveyorPassengers(velocity);
}
void ConveyorPassengers(Vector3 velocity)
{
RaycastHit2D hit = Physics2D.BoxCast(transform.position, new Vector3(12.5f, 0.1f), 0, Vector2.up);
if(hit && hit.transform.CompareTag("Player"))
{
conveyorInfo.isDisabled = true;
}
}
public struct ConveyorInfo
{
public bool isDisabled;
public void Reset()
{
isDisabled = false;
}
}
}
In your PlayerTest01 class, you have made the method MovementInput(). The method’s type is a Vector2, which means that you are returning a Vector2 object/class. Also, you return a Vector3 variable, but the method’s type is Vector2. So either change the method type to Vector3, or change the return to Vector2.zero.
Now I have not tested it because I’m currently installing Unity 3.4 Beta, but I am pretty sure doing this should solve your issue:
void Update() {
Vector2 input = MovementInput();
}
Vector2 MovementInput() {
if(conveyorReference.conveyorInfo.isDisable) {
Debug.Log("We did it?");
return Vector2.zero; //Notice that in your original code, you said Vector3.zero when the method's type is Vector2.
}
}
if you want to try to shrink things down a little you can consider using the [ spoiler] [ /spoiler] tags. Not needed all the time, but can be handy sometimes.
i.e.
theReasonForAllThings
Ah, so that’s how you do that. I’ve seen that spoiler function elsewhere online, it’s so useful.
Thanks LeftyRighty. : )
Edit:
I believe I found the problem: I hadn’t messed with the Scene portion for about a week and didn’t notice that the script was attached to two game objects. One was from before, and I thought the new Conveyor script was, well new. Thanks for everyone’s help and time.
For those with a null reference exception, this might be a good read if you’re new:
@Shinobi_Lord , if that code’s throwing a nullref, conveyorReference is null. ConveyorInfo is a struct, so even if it’s not been initialized, it would have the default value.
You’re getting the conveyorReference in Start. If it’s null, that means that your GetComponent is returning null - which means that your PlayerTest01 and your Conveyor scripts are not on the same object. Another possibility is that the Conveyor has gotten destroyed somehow.
A usual reason for errors like this is that you have set up everything correct in the inspector, but there’s another instance of the script in the scene. So you might have another PlayerTest01 script somewhere. You can search for PlayerTest01 in the search bar on top of the hierarchy.
How did you even get hold of the beta for a several years old unity version?
Actually, I got a question now: if I can only have one instance of the script in the scene, how would I incorporate multiple game objects using the script?
For example, multiple jump modifying platforms at different positions/locations throughout the scene.
I’m guessing some kind of Game Manager script, but then how would I be able to be more specific about boxcast origins among other things?
(Sorry just running this through my head quickly, I’m hitting a lot of stop lights.)
Well looks like I’m back with another problem! (Or at least the same one, just with more specific data on how to cause it).
So first, I’m gonna reintroduce the part of the code with the error:
void ConveyorPassengers(Vector3 velocity)
{
HashSet<Transform> movedPassengers = new HashSet<Transform>();
RaycastHit2D hit = Physics2D.BoxCast(transform.position, new Vector3(12.5f, 0.05f), 0, Vector2.up);
Debug.Log("Boxcast.");
if (hit && hit.transform.CompareTag("Player"))
{
playerTest01.isDisabled = true;
Debug.Log("The code was reached.");
if(!movedPassengers.Contains(hit.transform))
{
movedPassengers.Add(hit.transform);
Debug.Log("The hit object: " + hit.transform);
}
}
}
So when the code is run like this, it’s fine, but it does not function how I want it to. (The boxcast’s origin (and size) causes it to NOT intersect with the Player).
When I adjust the boxcast origin to have it intersect with the Player, then the infamous line of this thread:
playerTest01.isDisabled = true;
returns a NullReferenceException.
If anyone (again, hahaha), has any ideas, it’d be greatly appreciated. . .
Thanks for all of your time and help.
Also, I think I’m doing some “hard-coding” (I think that’s the term, and I’ve heard that is somewhat bad) for the boxcast’s origin (line 5), so if anyone could point out how I could get the boxcast origin done more smoothly that’d be great too. (I’m trying to get it to cast from the top of the attached game object upwards.)
You haven’t hardcoded the box’ origin; you have set it to transform.position. It’s the size you have hardcoded.
Instead of disabling the player when it gets in touch with your platform, you should just grab the player from the box cast result and disable it there:
RaycastHit2D hit = Physics2D.BoxCast(transform.position, new Vector3(12.5f, 0.05f), 0, Vector2.up);
//Get the Player01Test from the collider hit. The player variable will be null if there's no Player01Test on the same collider
PlayerTest01 player = hit.collider.GetComponent<Player01Test>();
//If we hit the player.
if(player != null) {
player.isDisabled = true;
...
}
Checking for components is a lot better than comparing tags, as it’s less prone to errors. In your code, you have made the assumptions that if a collider has the tag “player”, it’s the same object as the Player01 object you found on Awake.
This also allows you to ditch the playerTest01 variable, which is the source of your problems. You don’t want to have your conveyor belts know about the player, you just want them to react to the player (or whatever) hitting them. When you’re writing scripts, it’s important to try to have very few dependencies between the scripts - they should as much as possible be self-contained small pieces of behaviour that functions independently of the rest of the game. That way, changing one script won’t cause other scripts to change, and one script breaking won’t have a huge chain-reaction that breaks everything else.
You should (eventually) probably ditch the BoxCast, and use a trigger collider instead. Then you won’t need to hard-code (or figure out) the size of the box cast - you just have a collide you can see is big enough for the job. I’d suggest making this work with what you have already first, though.
I’m not the author of that, I just keep it around because there’s so many questions that’s best answered by linking that article. It’s easier to say “click the thing in my sig” than googling for the article, cutting and pasting the url, and making the post
Trigger colliders require a rigidbody - but not on the collider. For an OnTriggerEnter2D to happen, at least one of the colliders has to be a trigger, and at least one of the triggers has to have a rigidbody2D. The rigidbody can be kinematic, though, which means that it won’t be pushed around like a physics object.
But, as I said, wait with that until you have your current code working. For now, try to replace your boxcast code with the little snippet I posted.
I am sorry about tbat, I goofed. I meant Unity 5.4 beta LOL. It doesn’t matter though because I tried to make a new test project just to mess with Unity 5.4, but it said that I needed a pro license. Made me a little salty because I think Unity would benefit way more if they let everyone download the beta and provide feedback.