I am trying to make a check point, I want to make it so when the character hits the checkpoint, the collider turns off (I am open to using a raycast but that wasn't the current plan). I am still new to unity and I can't get the code to compile. I think my issue may be just not calling objects properly???
public class checkpoint : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
cp = GetComponent<Collider>();
cp.isTrigger = true;
object = GameObject.Find("Check Point");
}
private void OnTriggerEnter(cp)
{
cp.GetComponent(BoxCollider).isTrigger = false;
}
}
Not sure what is wrong
When you look at the code in your IDE, you will see red outlines underneath the exact points in your code that have issues. When you hover your cursor over these points the IDE will tell you what the issue is.
You can even use the Show potential fixes functionality and the IDE can often fix the issue for you automatically.
Here is the code modified so that it compiles.
public class checkpoint : MonoBehaviour
{
Collider cp;
// Start is called before the first frame update
void Start()
{
cp = GetComponent<Collider>();
cp.isTrigger = true;
GameObject gameObject = GameObject.Find("Check Point");
}
private void OnTriggerEnter(Collider other)
{
cp.isTrigger = false;
}
}
You were missing declarations for your cp and object variables. Additionally object is a reserved keyword in C#, so you can't use it as a variable name.
On the OnTriggerEnter function declaration the cp parameter was missing its type Collider.
In the body of the method the GetComponent call has incorrect syntax.
UPDATE: You can use the Destroy method to destroy the Collider component when something enters inside its bounds for the first time.
[RequireComponent(typeof(Collider))]
public class Checkpoint : MonoBehaviour
{
void Reset()
{
var collider = GetComponent<Collider>();
collider.isTrigger = true;
}
private void OnTriggerEnter(Collider other)
{
var collider = GetComponent<Collider>();
Destroy(collider);
}
}
If you want to destroy the whole GameObject that contains the checkpoint component and the Collider component you can use Destroy(gameObject);.
Related
I created a transparent cube trigger and I placed it in front of closed doors, so whenever the player walks near the door a message appears saying "this door is locked".
However, I want the message to be gone whenever the player is Not pointing to the door. currently, it shows even when I turn around, the player needs to walk away from the door to make the message disappear.
Here is my code:
public class DoorsTrigger : MonoBehaviour
{
public GameObject partNameText;
private void OnTriggerEnter(Collider other)
{
if (other.CompareTag("Player"))
{
partNameText.SetActive(true);
}
}
private void OnTriggerExit(Collider other)
{
if (other.CompareTag("Player"))
{
partNameText.SetActive(false);
}
}
}
How can I modify it to achieve my goal?
Here is a simple example using Vector3.Angle() to get the direction the player is facing relative to that trigger.
public class DoorsTrigger : MonoBehaviour
{
public GameObject partNameText;
private void OnTriggerEnter(Collider other)
{
if (other.CompareTag("Player"))
{
//Assuming 'other' is the top level gameobject of the player,
// or a child of the player and facing the same direction
Vector3 dir = (this.transform.position - other.gameObject.transform.position);
//Angle will be how far to the left OR right you can look before it doesn't register
float angle = 40f;
if (Vector3.Angle(other.gameObject.transform.forward, dir) < angle) {
partNameText.SetActive(true);
}
}
}
private void OnTriggerExit(Collider other)
{
//Make sure the text is actually showing before trying to disable it again
if (other.CompareTag("Player") && partNameText.activeSelf)
{
partNameText.SetActive(false);
}
}
}
Alternatively, you can keep your trigger mostly as is, and do a ray cast from the player to see if they are looking at the door.
//Put this snippet in a function and call it inside the player's Update() loop
RaycastHit hit;
Ray ray = new Ray(this.transform.position, this.transform.forward);
if(Physics.Raycast(ray, out hit))
{
//Tag the gameObject the trigger is on with "Door"
if(hit.collider.isTrigger && hit.collider.CompareTag("Door"))
{
//Here is where you would call a function on the door trigger to activate the text.
// Or better would be to just have that code be on the player.
// That way you can avoid unnecessary calls to another gameObject just for a UI element!
}
}
I wanted to create an collider on my players sword, that if he attacks that he would detect and via an animation event turn off/on an gameobject called (Damage Point) who was an script attached that would subtract the enemys health.
But somewhere it does not detect correctly. I tried to add the OnDrawGizmos function to see my sphere collider but even after making it bigger it does not detect.
The most strange thing about my issue is that im using the same code for my monster chest and my fantasy player, but for the chest it works but for the player it does not.
I created a class called PlayerDamage that is attached on an empty gameobject to the tip of my sword.
{
public class PlayerDamage : MonoBehaviour
public int damageAmount = 2;
public LayerMask enemyLayer;
void Update()
{
Collider[] hits = Physics.OverlapSphere(transform.position, 1.7f, enemyLayer);
if (hits.Length > 0)
{
if (hits[0].gameObject.tag == MyTags.ENEMY_TAG)
{
print("COLLIDED WITH ENEMY");
}
}
}
private void OnDrawGizmos()
{
Gizmos.DrawWireSphere(transform.position, 1.7f);
}
In another script called PlayerScript that is attached directly to the player I have a function called Attack:
void Attack()
{
if (Input.GetKeyDown(KeyCode.K))
{
if (!anim.GetCurrentAnimatorStateInfo(0).IsName(MyTags.ATTACK_ANIMATION) || !anim.GetCurrentAnimatorStateInfo(0).IsName(MyTags.RUN_ATTACK_ANIMATION))
{
anim.SetTrigger(MyTags.ATTACK_TRIGGER);
}
}
}
Also in the PlayerScript class there are two functions called ActivateDamagePoint and DeactivateDamagePoint, these are assigned to animation events for the attack animations.
void ActivateDamagePoint()
{
damagePoint.SetActive(true);
}
void DeactivateDamagePoint()
{
damagePoint.SetActive(false);
}
I double checked that everything is on his layer and that the tags are okay, but that did not solve my problem.
Like I said before for the chest I use the same code and it works, but unfortunately it does not work with my player. I also have the Activate and Deactivate DamagePoint functions in there and these are also called by the animation event for my chest attack animation.
Okay after 1hour of debugging I finnaly found the solution:
It was in the MyTags class (a helper class for all the string variables), the error was:
public static string ENEMY_TAG = "Enemey";
instead of:
public static string ENEMY_TAG = "Enemy";
I have looked around the web for answers but can't find a working one.
I have tried changing the code and I am pretty sure it's a very easy noob mistake as this is my first game.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class respawn : MonoBehaviour
{
[SerializeField] private Transform player;
[SerializeField] private Transform respawnPoint;
private Rigidbody Rigidbody;
void FixedUpdate()
{
if (player.position == respawnPoint.position);
{
GetComponent<Rigidbody>().velocity = 0;
Rigidbody.angularVelocity = 0;
}
}
private void OnTriggerEnter(Collider other)
{
player.transform.position = respawnPoint.transform.position;
}
}
The very first thing you want to do is to look at the Unity error console. Your code throws multiple errors, they will appear in red. Double-click on an error to be taken to its line in your code.
Also, try get a good editor, like VS Code, as it will help you find issues immediately by adding red wavy underlines. With above two approaches in hand, you will be able to find ~99% of your issues yourself the next time, and then can ask in forums for the remaining 1%.
Let's go through your code step by step:
private Rigidbody Rigidbody;
In Unity you normally want the type in upper case Rigidbody, but the variable name in lowercase rigidbody (even though the C# coding conventions suggest uppercase properties). Either way, don't use the same name as the type, so write:
private Rigidbody rigidbody;
or e.g. (I'm now omitting the default private, though you may also prefer to keep it, and I use a shorter variable name, and clarify its start value):
Rigidbody body = null;
In the following code:
GetComponent<Rigidbody>().velocity = 0;
... you first of all get the rigidbody component again. This isn't needed if you got it once in start (and for repeated usage, can lag), so do it like this:
void Start()
{
rigidbody = GetComponent<Rigidbody>();
}
And secondly, you assign a 0, but you want to assign new Vector3(0f, 0f, 0f), or just
rigidbody.velocity = Vector3.zero;
rigidbody.angularVelocity = Vector3.zero;
Lastly, you write
player.transform.position = respawnPoint.transform.position;
... but player and respawnPoint are already transforms, so you can use the simpler
player.position = respawnPoint.position;
Good luck!
When you enter the Trigger you will be teleported to the respawn position, but you cannot depend on FixedUpdate running on that exact pixel of the respawn position.
The most straigh forward answer is to, well, do the code as you would describe the issue: "When you enter a trigger, set the position to the respawn position and set velocity to 0":
I would change the entire script to:
public class respawn : MonoBehaviour
{
[SerializeField] private Transform player;
[SerializeField] private Transform respawnPoint;
private Rigidbody rigidbody;
void Start()
{
rigidbody = GetComponent<Rigidbody>()
}
private void OnTriggerEnter(Collider other)
{
player.position = respawnPoint.position;
rigidbody.velocity = Vector3.zero;
}
}
and don't forget to populate the player and respawnPoint values in the inspector.
Also, keep in mind that the current code is prone to errors, if you have other objects moving around. Right now, if ANY object enters the Trigger the PLAYER position will be reset. You could fix this with check for player
private void OnTriggerEnter(Collider other)
{
if (other.transform == player)
{
player.position = respawnPoint.position;
rigidbody.velocity = Vector3.zero;
}
}
I need to instantiate an object with a collider, check its collisions, then if its not touching anything, delete it.
is the following code always guaranteed to execute it the right order? (ie: collisions THEN lateUpdate?)
public class RemoveIfColliding : MonoBehaviour
{
bool touching = false;
private void OnCollisionStay(Collision collision)
{
print("I am touching " + collision.other.name);
touching = true;
}
private void LateUpdate()
{
if (!touching)
{
Destroy(gameObject);
}
}
}
Have a look at Order of Execution for Event Functions:
I would intepret it as all messages from the Physics block are called before the GameLogic. It states
The physics cycle might happen more than once per frame if the fixed time step is less than the actual frame update time.
but they should still be done before the Update and LateUpdate calls.
Even if LateUpdate is called first, the object will be destroyed in its next iteration. So basically at seemengly the same time.
But I don't think this is the best way to do it. You can simplify the code by not using the late update and the boolean at all. Just do it like this:
public class RemoveIfColliding : MonoBehaviour
{
private void OnCollisionStay(Collision collision)
{
print("I am touching " + collision.other.name);
Destroy(gameObject);
}
}
Hope this helps!
In World Scale AR, I want to move to an object I placed using SpawnOnMap. When I touch that object, I want that object to be erased. I made the Player have a script called PlayerController. I made a tag for the object so that when it touches, it should destroy or set it active. When I walk towards the object, nothing happens. I've tried OnTriggerEnter and OnCollisionEnter already. Is there some kind of method I'm missing that Mapbox provides?
public class PelletCollector : MonoBehaviour
{
public int count = 0;
// Start is called before the first frame update
void Start()
{
}
private void OnCollisionEnter(Collision other)
{
if (other.gameObject.tag == "Pellet")
{
count++;
Debug.Log("Collected Pellets: " + count);
other.gameObject.SetActive(false);
//Destroy(other.gameObject);
}
}
}