I'm trying to get an input from the "space" button, but it looks like it doesn't take the input when I click. Here's my code:
void OnTriggerEnter2D (Collider2D other)
{
if (other.gameObject.tag == "GreenKey") {
print ("Green Key taken");
Destroy (other.gameObject);
greenKey_canvas.enabled = true;
} else if (other.gameObject.tag == "RedKey") {
print ("Red Key taken");
Destroy (other.gameObject);
redKey_canvas.enabled = true;
} else if (other.gameObject.tag == "YellowKey") {
print ("Yellow Key taken");
Destroy (other.gameObject);
yellowKey_canvas.enabled = true;
} else if (other.gameObject.tag == "Gem") {
print ("Gem taken");
gems = gems + 5;
gemsText.text = gems.ToString ();
Destroy (other.gameObject);
} else if (other.gameObject.tag == "RedGem") {
print ("Gem taken");
gems++;
gemsText.text = gems.ToString ();
Destroy (other.gameObject);
} else if (other.gameObject.tag == "LiveTaker") {
lives--;
} else if (other.gameObject.tag == "RedDoor") {
if (redKey_canvas.enabled) {
if (Input.GetKeyDown(KeyCode.Space)) {
//OPEN DOOR
other.gameObject.GetComponent<SpriteRenderer>().sprite = enterDoor;
redKey_canvas.enabled = false;
}
}
} else if (other.gameObject.tag=="YellowDoor") {
if (yellowKey_canvas.enabled) {
//OPEN DOOR
}
} else if (other.gameObject.tag=="GreenDoor") {
if (greenKey_canvas.enabled) {
//OPEN DOOR
}
}
}
In the console, I get the "entered door with key" message, but when I press Space, nothing happens.
I've also tried to add an Axis to the Input Manager named "DoorEnter", but it doesn't work either...
The reason this dosent work, is that the OnCollisionEnter function only activates the frame that the collision first happens, and that the GetKeyDown only lauches the single frame the button gets pushed.
One quite ugly fix, would be to Replace GetKeyDown with GetKey, then already hold space when walking into the door.
A better solution would be to add a variable, for an if statement in the Update loop. Make it activate when the user enters, and deactivate when the user leaves collision area.
Then make an if statement like this:
if(inCollider && Input.GetKeyDown(KeyCode.Space)){
//Open door here
}
Also, can anyone format this correctly? (Am on phone)
EDIT: Collision means trigger! Sorry!
Related
I'm trying to detect collision in some cases, headshot, not headshot, missing the target.
Here is how I tried to achieve it:
private void OnCollisionEnter(Collision collision)
{
if (interations.won && interations.currentlyPickedUpObject == null)
{
if (collision.collider == head)
{
Debug.Log("HeadShot");
}
if (collision.collider == body || collision.collider == feet)
{
Debug.Log("Not a HeadShot");
}
else
{
Debug.Log("You've missed the target");
}
}
}
The issue I'm facing is that the if and the else both get executed! shouldn't the else block get executed only if the if conditions are not met? why is this happening? I want to execute the else part only if the two conditions are false!
enter image description here
Try this:
private bool hasCollided = false;
private void OnCollisionEnter(Collision collision)
{
if (interations.won && interations.currentlyPickedUpObject == null && !hasCollided)
{
hasCollided = true;
if (collision.collider == head)
{
Debug.Log("HeadShot");
}
if (collision.collider == body || collision.collider == feet)
{
Debug.Log("Not a HeadShot");
}
else
{
Debug.Log("You've missed the target");
}
}
}
Try to change the second if with else if, like this
else if (collision.collider == body || collision.collider == feet)
In your code, the else condition is linked only with the second if condition, and not the first if.
They are both executed, because you got two if statements. Your first if statement is separate from the else, which in turn is tied to the second if.
Imagine collider is a head: your first if will be true. Then you go to the second if - the collider is neither body nor feet, and you go to the else, hence your code logs both HeadShot, and You've missed the target
To prevent that, you can use else if:
if (collision.collider == head)
{
Debug.Log("HeadShot");
}
else if (collision.collider == body || collision.collider == feet)
{
Debug.Log("Not a HeadShot");
}
else
{
Debug.Log("You've missed the target");
}
as it will prevent the code from choosing multiple options.
So I'm trying to implement shooting in a multiplayer game. I want to spawn a bullet out of a weapon. On the server side it works, but as I shoot as a client it says [Netcode] Behaviour index was out of bounds. Did you mess up the order of your NetworkBehaviours?.
The bullet is a prefab which I included in NetworPrefabs. The prefab also has a Network Object component.
This is where I call shoot()
if(shot == false && transform.GetChild(0).GetComponent<Weapon>().bulletInMag > 0 && reloading == false)
{
shot = true;
StartCoroutine(shoot());
}
This is what shoot() does
IEnumerator shoot()
{
firePoint = transform.GetChild(0).GetChild(0).transform;
weapon = transform.GetChild(0).gameObject.GetComponent<Weapon>();
if (weapon.threeShot)
{
for(int i=0; i<3; i++)
{
if(NetworkManager.Singleton.IsServer)
{
spawnBullet();
} else
{
spawnBulletServerRpc();
}
weapon.bulletInMag -= 1;
SharedFunctions.Instance.updateAmmoCount();
yield return new WaitForSeconds(0.2f);
}
yield return new WaitForSeconds(weapon.shootingIntervall);
shot = false;
}
else
{
if (NetworkManager.Singleton.IsServer)
{
spawnBullet();
}
else
{
spawnBulletServerRpc();
}
weapon.bulletInMag -= 1;
SharedFunctions.Instance.updateAmmoCount();
yield return new WaitForSeconds(weapon.shootingIntervall);
shot = false;
}
}
void spawnBullet()
{
GameObject bullet = Instantiate(prefabBullet, firePoint.position, transform.rotation);
bullet.GetComponent<Rigidbody2D>().AddForce(firePoint.up * weapon.bulletSpeed, ForceMode2D.Impulse);
bullet.GetComponent<NetworkObject>().Spawn();
}
[ServerRpc]
void spawnBulletServerRpc()
{
spawnBullet();
}
I'm thankful for any help.
I finally fixed the issue. The error [Netcode] Behaviour index was out of bounds. Did you mess up the order of your NetworkBehaviours? basically means that there is a mismatch between server and client representation of a network object.
At the beginning of my Player script I wrote:
public override void OnNetworkSpawn()
{
if (!IsOwner) Destroy(this);
}
which deletes the component if your not the owner.
So when I joined I had the script on client side but it wasn't there on server side. So when I tried to make an ServerRpc it didn't know where to send it. The same goes for ClientRpc.
A very helpful source was the Unity Mulitplayer Networking Discord: https://discord.gg/buMxnnPvTb
I am looking to show a line in my app from where the model is placed so that the user knows position where the model is kept in real world. When user changes device camera away from model the line gets turned on to show where the model is. Similarly it turns off when model is detected. I have attached images to show from a similar app white dotted lines show the path. Notice how the lines disappear when the model is detected.
LineRenderer lins;
public GameObject Lineprefab;
private GameObject newline;
public Transform startpoint;
public Renderer m_rend1;
bool HitTestWithResultType (ARPoint point, ARHitTestResultType resultTypes)
{
List<ARHitTestResult> hitResults = UnityARSessionNativeInterface.GetARSessionNativeInterface ().HitTest (point, resultTypes);
if (hitResults.Count > 0 && check==true)
{
foreach (var hitResult in hitResults)
{
Debug.Log ("Got hit!");
//obj.Hideplane();
Genplanes.SetActive(false);
if (Select == 0) {
Debug.Log("hit-zero!");
Instantiate(Instaobj[0], ForSelect);
check = false;
}
if (Select == 1) {
Debug.Log("hit-one!");
Instantiate(Instaobj[1], ForSelect);
check = false;
}
if (Select == 2) {
Debug.Log("hit-two!");
Instantiate(Instaobj[2], ForSelect);
check = false;
}
m_HitTransform.position = UnityARMatrixOps.GetPosition (hitResult.worldTransform);
m_HitTransform.rotation = UnityARMatrixOps.GetRotation (hitResult.worldTransform);
Debug.Log (string.Format ("x:{0:0.######} y:{1:0.######} z:{2:0.######}", m_HitTransform.position.x, m_HitTransform.position.y, m_HitTransform.position.z));
obj.StopPlaneTracking();
}
}
return false;
}
private void Start()
{
spawngenerator();
newline.SetActive(false);
m_rend1 = GetComponent<MeshRenderer>();
}
void spawngenerator()
{
GameObject newline = Instantiate(Lineprefab);
lins = newline.GetComponent<LineRenderer>();
}
private void LateUpdate()
{
lins.SetPosition(0, startpoint.position);
lins.SetPosition(1, m_HitTransform.position);
if( m_rend1.isVisible==true)
{
Debug.Log("Render is Visible");
newline.SetActive(false);
}
else if( m_rend1.isVisible==false)
{
newline.SetActive(true);
Debug.Log("It is InVisible");
Debug.Log("Render is InVisible");
}
}
void Update () {
#if UNITY_EDITOR //we will only use this script on the editor side, though there is nothing that would prevent it from working on device
if (Input.GetMouseButtonDown (0)) {
Ray ray = Camera.main.ScreenPointToRay (Input.mousePosition);
RaycastHit hit;
//we'll try to hit one of the plane collider gameobjects that were generated by the plugin
//effectively similar to calling HitTest with ARHitTestResultType.ARHitTestResultTypeExistingPlaneUsingExtent
if (Physics.Raycast (ray, out hit, maxRayDistance, collisionLayer)) {
//we're going to get the position from the contact point
m_HitTransform.position = hit.point;
Debug.Log (string.Format ("x:{0:0.######} y:{1:0.######} z:{2:0.######}", m_HitTransform.position.x, m_HitTransform.position.y, m_HitTransform.position.z));
//and the rotation from the transform of the plane collider
m_HitTransform.rotation = hit.transform.rotation;
}
}
#else
if (Input.touchCount > 0 && m_HitTransform != null )
{
var touch = Input.GetTouch(0);
if ((touch.phase == TouchPhase.Began || touch.phase == TouchPhase.Moved) && !EventSystem.current.IsPointerOverGameObject(touch.fingerId))
{
var screenPosition = Camera.main.ScreenToViewportPoint(touch.position);
ARPoint point = new ARPoint {
x = screenPosition.x,
y = screenPosition.y
};
// prioritize reults types
ARHitTestResultType[] resultTypes = {
//ARHitTestResultType.ARHitTestResultTypeExistingPlaneUsingGeometry,
ARHitTestResultType.ARHitTestResultTypeExistingPlaneUsingExtent,
// if you want to use infinite planes use this:
//ARHitTestResultType.ARHitTestResultTypeExistingPlane,
//ARHitTestResultType.ARHitTestResultTypeEstimatedHorizontalPlane,
//ARHitTestResultType.ARHitTestResultTypeEstimatedVerticalPlane,
//ARHitTestResultType.ARHitTestResultTypeFeaturePoint
};
foreach (ARHitTestResultType resultType in resultTypes)
{
if (HitTestWithResultType (point, resultType))
{
return;
}
}
}
}
#endif
}
.
First, I 'd start with checking if the model is within the bounding box of the camera https://docs.unity3d.com/ScriptReference/Renderer-isVisible.html
if the object is not visible (isVisible == false), create a line renderer from object position to wherever it should end.
The end point could be a camera child place just in front of it, so it looks like it starts from the user to the object.
I'm making my very first game in unity. In this game my player is a ball which touches some question marks. When a question mark is triggered it has to display a question and the answers. Till here every thing is fine. Now i need to press a or b according to the question. If the answer is right it will add points. But here is the problem. Unity doesn't wait for me to press the keys. Unity passes through the code before i press the buttons and the game crashes.
void OnTriggerEnter(Collider collider)
{
if (collider.gameObject.CompareTag("QuestionCube1"))
{
Question.text = "Which Number is bigger?";
Answer.text = "A.5 B.10";
if (Input.GetKeyDown(KeyCode.A))
{
gameController.minusQuestionScore();
}
else if (Input.GeyKeyDown(KeyCode.B))
{
gameController.addQuestionScore();
}
Question.text = "";
Answer.text = "";
}
}
//Sorry if the code is kinda all over the place I dont know how to pass the code here exactly. The gameController and the UI texts are declared and working
Okay let's shift away from the comment section and let's try to improvise, on my current understandings of your problem.
First thing you must consider is the following.
void OnTriggerEnter(Collider collider)
Triggers ONLY once, when the other collider enters. The solution?
Use OnTriggerStay.
void OnTriggerStay(Collider collider)
This will always check for the input when the objects are colliding.
The next thing to consider is the reset of the text. As far as I understand you should remove it when they are not colliding anymore, so you could have additional method. OnTriggerExit, which will run additional code when they are not colliding anymore.
void OnTriggerExit(Collider collider)
{
if (collider.gameObject.CompareTag("QuestionCube1"))
{
Question.text = "";
Answer.text="";
}
}
So overall
void OnTriggerEnter(Collider collider)
{
if (collider.gameObject.CompareTag("QuestionCube1"))
{
Question.text = "Which Number is bigger?";
Answer.text = "A.5 B.10";
if(Input.GetKeyDown(KeyCode.A))
{
gameController.minusQuestionScore();
}
else if(Input.GeyKeyDown(KeyCode.B))
{
gameController.addQuestionScore();
}
}
}
You can use Coroutine to wait for the input after it is triggered.
void OnTriggerEnter(Collider collider)
{
if (collider.gameObject.CompareTag("QuestionCube1"))
{
Question.text = "Which Number is bigger?";
Answer.text = "A.5 B.10";
StartCoroutine(WaitForAnswer());
}
}
IEnumerator WaitForAnswer()
{
for (;;)
{
if (Input.GetKeyDown(KeyCode.A))
{
gameController.minusQuestionScore();
break;
}
else if (Input.GetKeyDown(KeyCode.B))
{
gameController.addQuestionScore();
break;
}
yield return null;
}
Question.text = "";
Answer.text = "";
yield return null;
}
I have created a random generator for a prefab called "Tunnel". Whenever i collide with a tunnel prefab, i wish to keep the game running. If i am no longer colliding with a tunnel i wish the game to stop.
The game works fine for the first tunnel, but when i reach the end of the first tunnel (start of the second - they overlap), my "OnTriggerExit2D" function stops the game.
Is there a way to tell my "OnTriggerExit2D" to check if i'm colliding with a different tunnel?
Here's my code:
void OnTriggerEnter2D(Collider2D other)
{
Debug.Log (other.gameObject.tag);
if (other.gameObject.CompareTag ("LeftTunnel")) {
touchRef.onTunnelL = true;
}
if (other.gameObject.CompareTag ("RightTunnel")) {
touchRef.onTunnelR = true;
}
}
void OnTriggerExit2D(Collider2D other)
{
if(other.gameObject.CompareTag("LeftTunnel"))
{
touchRef.OnTriggerExit2Dchild();
touchRef.onTunnelL = false;
}
if(other.gameObject.CompareTag("RightTunnel"))
{
touchRef.OnTriggerExit2Dchild();
touchRef.onTunnelR = false;
}
}
thanks!
So, after consulting with some people I decided to change the whole mechanism to work with ray casting and it works great now.
Here's the code for anyone in the future (I call cast function on Update):
void Cast()
{
for (int i = 0; i < Input.touchCount; ++i)
{
Vector2 test = Camera.main.ScreenToWorldPoint(Input.GetTouch(i).position);
RaycastHit2D hit = Physics2D.Raycast(test, (Input.GetTouch(i).position));
Vector2 touchPos = new Vector2(test.x, test.y);
onLeft(touchPos);
onRight(touchPos);
}
}
void onLeft(Vector2 touchPos){
Collider2D tempL;
if (tempL = Physics2D.OverlapPoint (touchPos)) {
if(tempL.CompareTag("LeftTunnel")){
Debug.Log ("Hit Left tunnel");
onTunnelL = true;
}
}
else{
onTunnelL = false;
}
}
void onRight(Vector2 touchPos){
Collider2D tempR;
if (tempR = Physics2D.OverlapPoint (touchPos)) {
if(tempR.CompareTag("RightTunnel")){
Debug.Log ("Hit Right tunnel");
onTunnelR = true;
}
}
else{
onTunnelR = false;
}
}