I made this little script that should turn the light of a point light off and on ... unfortunately only the off button works, after which it doesn't turn on again .... maybe there is some error in the script?
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TurnLight : MonoBehaviour {
public GameObject light;
private bool on = true ;
void OnTriggerStay(Collider other) {
if (other.tag == "Player" && Input.GetKey(KeyCode.E) && !on)
{
light.SetActive(true);
on = true;
}
else if (other.tag == "Player" && Input.GetKey(KeyCode.E) && on)
{
light.SetActive(false);
on = false;
}
}
}
Please Check this link to understand OnTriggerStay Function
On Trigger Stay
Also Please check those to differentiate between
Get Key and
Get Key Down
the problem is calling of OnTriggerStay happens continuously and you are using GetKey functions which will return true all times if the player pressed.
So when you use GetKey this will cause Single press on E will be redden multiple times.
Here is my solution
public GameObject light;
bool isPlayerStandingNear = false;
private void Update()
{
if(isPlayerStandingNear)
{
//Debug.Log("isPlayerStandingNear");
if(Input.GetKeyDown(KeyCode.E))
{
Debug.Log("Light State : "+ light.active);
light.SetActive(!light.active);
}
}
}
void OnTriggerStay(Collider other)
{
if (other.tag == "Player")
{
isPlayerStandingNear = true;
}
}
private void OnTriggerExit(Collider other)
{
if (other.tag == "Player")
{
isPlayerStandingNear = false;
}
}
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;
}
}
me and my colleagues are creating a 2D sidescroller game in Unity with C#.
The player, is supposed to be able to pick objects (by touching them) and throw them.
Our plan is this:
1) make variables for the objects, their booleans and their rigid bodies.
2) verify if the object is touching the player
3) if it's true, then the object will parent to the player (setting their position to the player's hand).
4) to throw, the code will check if the player has the object (by using a boolean) and then it will unparent and throw by addforce.
The code doesn't have any errors and it works except on the throwing part (the player can grab and ungrab but can't throw).
The player can pick and unpick but not throwing and i don't understand why because the code looks right and the console doesn't show me any errors :/
Have a look to my code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Inventory : MonoBehaviour
{
public bool ispicked1 = false;
public GameObject pickable1;
public Rigidbody2D pickable1rb;
public GameObject Parent;
public float force;
void Start() {
pickable1rb = GetComponent<Rigidbody2D>();
}
void Update() {
if (ispicked1 == true) {
pickable1.transform.position = Parent.transform.position;
}
else if (ispicked1 == false) {
pickable1.transform.parent = null;
}
if (Input.GetMouseButton(1) && ispicked1 == true) {
ispicked1 = false;
pickable1rb.AddForce(transform.up * force, ForceMode2D.Impulse);
}
}
private void OnCollisionEnter2D(Collision2D collision) {
if (collision.gameObject.name == "pickable1") {
Debug.Log("Tocou em objecto");
ispicked1 = true;
pickable1.transform.SetParent(Parent.transform);
}
}
}
Side question: i want the player to throw at the direction he's facing, what is the best way to do that? I can only choose between right, left or up :/
UPDATE:
I solved all the problems and i created a side script for the object to be thrown and they are 100% working! Here are the codes:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Inventory : MonoBehaviour
{
public bool ispicked1 = false;
public bool ispicked2 = false;
public GameObject pickable1;
public GameObject pickable2;
public GameObject Parent;
public bool isThrown = false;
public ThrowableObject throwableinstance1;
public ThrowableObject throwableinstance2;
public bool isfull = false;
void Start() {
throwableinstance1 = GameObject.Find("pickable1").GetComponent<ThrowableObject>();
throwableinstance2 = GameObject.Find("pickable2").GetComponent<ThrowableObject>();
}
void Update() {
if (ispicked1 == true) {
pickable1.transform.position = Parent.transform.position;
isfull = true;
}
else if (ispicked1 == false) {
pickable1.transform.parent = null;
}
if (ispicked2 == true) {
pickable2.transform.position = Parent.transform.position;
isfull = true;
} else if (ispicked2 == false) {
pickable2.transform.parent = null;
}
if (Input.GetMouseButton(1) && ispicked1 == true) {
ispicked1 = false;
isThrown = true;
throwableinstance1.Throw();
isfull = false;
}
if (Input.GetMouseButton(1) && ispicked2 == true) {
ispicked2 = false;
isThrown = true;
throwableinstance2.Throw();
isfull = false;
}
}
private void OnCollisionEnter2D(Collision2D collision) {
if (collision.gameObject.name == "pickable1" && isfull == false) {
ispicked1 = true;
pickable1.transform.SetParent(Parent.transform);
}
if (collision.gameObject.name == "pickable2" && isfull == false) {
ispicked2 = true;
pickable2.transform.SetParent(Parent.transform);
}
}
}
Here's the code to throw the pickable object:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ThrowableObject : MonoBehaviour
{
public Inventory inventoryinstance;
public Rigidbody2D throwablerb;
public Transform Player;
public GameObject PickableObject;
public EnemyHealth1 enemyhealth1instance;
public EnemyHealth2 enemyhealth2instance;
public EnemyHealth3 enemyhealth3instance;
void Start()
{
inventoryinstance = GameObject.Find("Player").GetComponent<Inventory>();
enemyhealth1instance = GameObject.Find("enemy1").GetComponent<EnemyHealth1>();
enemyhealth2instance = GameObject.Find("enemy2").GetComponent<EnemyHealth2>();
enemyhealth3instance = GameObject.Find("enemy3_leper").GetComponent<EnemyHealth3>();
}
public void Throw()
{
if(Player.localScale.x < 1)
{
throwablerb.AddForce(transform.right * -1);
} else if(Player.localScale.x > 0)
{
throwablerb.AddForce(transform.right);
}
}
private void OnCollisionEnter2D(Collision2D collision) {
if (collision.gameObject.name == "enemy1") {
enemyhealth1instance.GetComponent<EnemyHealth1>().EnemyHealthbar1-= 1;
Destroy(PickableObject);
}
if (collision.gameObject.name == "enemy2") {
enemyhealth2instance.GetComponent<EnemyHealth2>().EnemyHealthbar2-=1;
Destroy(PickableObject);
}
if (collision.gameObject.name == "enemy3_leper") {
enemyhealth3instance.GetComponent<EnemyHealth3>().EnemyHealthbar3-=1;
Destroy(PickableObject);
}
}
private void OnTriggerEnter2D(Collider2D col)
{
if (col.gameObject.name == "enemy1_hitbox") {
enemyhealth1instance.GetComponent<EnemyHealth1>().EnemyHealthbar1-=1;
Destroy(PickableObject);
}
}
}
While you're answering my question, I'll do some quick code reviewing:
Overall, it feels weird to be keeping track and maintaining "holding & throwing an item" in a class called "Inventory" that has references to a separate object, that is being held & a reference to the player. What is this script? The item, the player or a third party; a separate inventory? (Questions to ask yourself, you don't need to answer them - just think about it 😊)
pickable1
pickable1object
pickable1rb
These variable names makes little sense to me in current context; why not just isPickedUp, object, rb?
if (pickable1 == true) {
pickable1object.transform.position = Playerparent.transform.position;
}
if (pickable1 == false) {
pickable1object.transform.parent = null;
}
pickable1 will not be both true and false, doing 2 ifs are just unnecessary computations. What you're looking for here is an if/else or if/elseif.
Furthermore, if you child it to the player, logically, shouldn't you NOT have to set the position every frame? Else, what's the purpose of childing?
void FixedUpdate() {
if (Input.GetMouseButton(1)) {
// [...]
}
// [...]
}
Logically, you shouldn't be checking for input in the fixed update since inputs are tied to a frame, meaning Update(). In this case, it may accidentally work reliably most of the time because you're not checking if the player CLICKED a button, rather you're checking if player is HOLDING a button. (GetMouseButton vs GetMouseButtonDown). If you were to check for if the player CLICKED a button in the FixedUpdate, it would only work on the few lucky frames where FixedUpdate and Update were running at the exact same time.
Regarding your question: The code looks alright, it's probably not behave in the way you expect. From what I can tell in the code it will...
If player has picked up an item, it will have force added to it if holding down Mouse 1 for as long as player is holding down mouse.
Why nothing is happening may be due to inspector values being off. Debug the values of force and see if the code is triggering at all. Consider moving the parent = null code (or just remove the parenting alltogether).
It could also be that as soon as you push the item outside of the player, it falls down and triggers OnCollisionEnter and is grabbed by the player again.
The problem with your code is that you use transform.up which will just cause it to throw upwards rather than the direction the player is facing. So you can use transform.right for the direction the player is facing. You can use both to create more of an arc.
You'll have some problems with pivoting with the way you have it setup.
What I recommend is to have two transforms which are children of the player to pivot the sprite properly. (You can change the position of the transform in the keyframes of the player's animation)
The code would look something like this:
public class Inventory : MonoBehaviour
{
private bool carryingItem => pickedUpItem == null;
private PickableItem pickedUpItem;
[SerializeField] private Vector2 throwingForce;
[SerializeField] private Transform spawnPosition; //Should be a child of the player gameobject. This will be position of the object
[SerializeField] private Transform handTransform; //Should also be a child of the player gameobject. This needs to be animated for the keyframes that move the hand
void Update()
{
if (carryingItem && Input.GetMouseButtonDown(1))
{
pickedUpItem.transform.SetParent(null);
pickedUpItem.transform.position = spawnPosition.position;
pickedUpItem.GetComponent<Rigidbody2D>().AddForce(transform.right * throwingForce.x + transform.up * throwingForce.y);
pickedUpItem = null;
}
}
private void OnCollisionEnter2D(Collision2D other)
{
var pickable = other.transform.GetComponent<PickableItem>();
if (pickable && pickedUpItem == null) //This kind of depends on the game design because maybe you want to pick it up if you're carrying something already
{
pickedUpItem = pickable;
pickable.transform.SetParent(handTransform);
}
pickable.transform.localPosition.Set(0,0,0);
}
}
You set the picked up item to the parent where you want to be pivoted around.
I am trying to have my player walk onto a GameObject and if they are on that object and they press the space key show a debug log.
private void OnTriggerEnter2D(Collider2D other)
{
if (other.gameObject.tag == "Level_1" && Input.GetKeyDown(KeyCode.Space))
{
Debug.Log("Both Conditions Reached");
}
}
This would only trigger if they were holding down the space bar as they entered the object. You would do better to check if they were currently colliding with the object when the spacebar is pressed. (or do the check for both in Update)
Call this in your player object:
private void OnTriggerEnter2D(Collider2D other) {
if (other.gameObject.tag == "Level_1") {
player.isInside = true;
}
}
private void OnTriggerExit2D(Collider2D other) {
if (other.gameObject.tag == "Level_1") {
player.isInside = false;
}
}
And use this to check for the spacebar:
public void Update() {
if (Input.GetKeyDown(KeyCode.Space) && player.isInside == true) {
Debug.Log("Both Conditions Reached");
}
}
How can I activate part of the code in other script?
Attention: I don't need to activate all scripts. For example, a bunch of bullets flies around a player. And when one collide with a player, then need to activate part of the script of the collided object (that touched the player).
PlayerControl.cs
void OnCollisionEnter2D(Collision2D col)
{
if (col.gameObject.tag == "Bullet1")
{
lasthit = 1f;
// I need to activate Destroyy() in Bullet1 script
}
}
Bullet1.cs
public void Destroyy()
{
Debug.Log("Destroyed!"); // I need to activate this part of the code
} // ONLY in Bullet1.cs
The code below shows how to do it:
void OnCollisionEnter2D(Collision2D col)
{
if (col.gameObject.tag == "Bullet1")
{
lasthit = 1f;
// I need to activate Destroyy() in Bullet1 script
// HERE'S HOW:
if(col.gameObject.GetComponent<Bullet1>() != null)
col.gameObject.GetComponent<Bullet1>().Destroyy();
}
}
Just getComponent is be easier
void OnCollisionEnter2D(Collision2D col)
{
Bullet1 b = col.gameObject.GetComponent<Bullet1>();
if (b == null)
{
return;
}
lasthit = 1f;
b.Destroyy();
}
Actiovating bool in Bullet1 script
Player.cs
void OnCollisionEnter2D(Collision2D col)
{
if (col.gameObject.tag == "Bullet1")
{
col.gameObject.GetComponent<Bullet1pt().booldestroy = true;
}
}
Bullet1.cs
public bool booldestroy;
private void Update()
{
if (booldestroy)
{
Destroyy();
}
}
I’ve placed in the scene an object with a trigger and I want the console sends me a message detecting if the player is in or out of the trigger when I click a button . When I play, it only sends me a message when the player is into the trigger.
Code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MapDetect : MonoBehaviour {
void OnTriggerStay(Collider other)
{
if (other.gameObject.tag == "Player") {
Debug.Log ("Map ON");
}
else {
if (other.gameObject.tag == "Player") {
Debug.Log ("Map OFF");
}
}
}
}
Use OnTriggerEnter and OnTriggerExit instead of OnTriggerStay to keep the current state:
public class MapDetect : MonoBehaviour {
private bool isTriggered;
void OnTriggerEnter(Collider other)
{
if (other.gameObject.CompareTag("Player"))
isTriggered = true;
}
void OnTriggerExit(Collider other)
{
if (other.gameObject.CompareTag("Player"))
isTriggered = false;
}
void Update(){
if(Input.GetKey(KeyCode.Space)){
Debug.Log(isTriggered);
}
}
}
Your logic is totally wrong. You're only checking if the TRIGGER STAYS IN YOUR BOUNDS but still trying to log "Map OFF" message which will never happen.
Instead of OnTriggerStar method use OnTriggerEnter and OnTriggerExit. Then print the message only when needed ( or in debug mode ) :
void OnTriggerEnter(Collider other)
{
if ( other.gameObject.CompareTag("Player") )
{
m_IsPlayerOnTheMap = true;
}
}
void OnTriggerExit(Collider other)
{
if( other.gameObject.CompareTag("Player") )
{
m_IsPlayerOnTheMap = false;
}
}
void Update()
{
#if DEBUG
if ( m_IsPlayerOnTheMap )
{
Debug.Log("Map ON");
}
else
{
Debug.Log("Map OFF");
}
#endif
}
private bool m_IsPlayerOnTheMap = false;
Try:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MapDetect : MonoBehaviour {
void OnTriggerEnter(Collider other)
{
if (other.gameObject.CompareTag("Player"))
{
Debug.Log ("Map ON");
}
}
void OnTriggerExit(Collider other)
{
if (other.gameObject.CompareTag("Player"))
{
Debug.Log ("Map OFF");
}
}
}
This will switch it on when you enter and off when you exit (althout all it does right now is print the result).
Hope it helps.