- Home /
making an enemy detect if the player is behind it, and turn around.
Hello everyone ! I am making a 2D platformer, and I currently am working on an enemy script. The enemy walks on a platform, and uses a linecast to detect the player. The said linecast goes a bit behind the monster, to simulate the earing (so if the players is too close behind, the monster turns around, and gets the player).
The problem is, that with the following script, the monster can only detect the player if the player behind the monster, on it's right (the case in which the rotation y of the monster is 0). I really don't get why the "else if" condition right after, very similar but for the other side, won't work. As told just where the problem is in the script (I tried to make it explicit so that it would be easier to find), the one thind that doesn't work is the condition in the "else if" to detect wether or not the player is behind the monster.
Here is the script
using UnityEngine;
using System.Collections;
public class enemy_type_mannequin : MonoBehaviour {
public LayerMask enemyMask;
public LayerMask PreyMask;
public bool findyou = false;
public Transform GroundCheck;
public GameObject Target;
Rigidbody2D myBody;
Transform myTrans;
float myWidth;
public float speed;
public float idleTimer;
float idleDuration = 8;
Animator freakAnimator;
public Transform lookDirection;
public Transform lookOrigin;
public float HuntTimer;
public SpriteRenderer preyRenderer;
bool hunting;
bool hasKilled;
public Laureline_movement preymovement;
public float distance;
public bool isBehind;
// Use this for initialization
void Start () {
myTrans = this.transform;
myBody = this.GetComponent<Rigidbody2D>();
freakAnimator = this.GetComponent<Animator>();
HuntTimer = 0;
preyRenderer = GameObject.FindGameObjectWithTag("Player").GetComponent<SpriteRenderer>();
hunting = false;
hasKilled = false;
preymovement = GameObject.FindGameObjectWithTag("Player").GetComponent<Laureline_movement>();
isBehind = false;
Target = GameObject.FindGameObjectWithTag("Player");
}
void FixedUpdate()
{
// eyesight line to detect the player
Debug.DrawLine(lookOrigin.position, lookDirection.position);
RaycastHit2D SeeYou = Physics2D.Linecast(lookOrigin.position, lookDirection.position, PreyMask);
distance = transform.position.x - Target.transform.position.x;
// if the monster "sees" the player, hunt him down
if (SeeYou.collider != null && SeeYou.collider.tag == "Player" && HuntTimer == 0 && hasKilled == false) {
Hunt();
}else if ( HuntTimer != 0 && HuntTimer < 4 && hasKilled == false)
{
Hunt();
// if the monster does not see the player, idle/patrol
}
else if(hasKilled == false){
Idle();
}
}
void Hunt() {
hunting = true;
HuntTimer += Time.deltaTime;
// here's the " if the player is behind, turn around"
//the first one works well
if(distance < 0 && transform.rotation.y == 0)
{
Vector3 currRot = myTrans.eulerAngles;
currRot.y += 180;
myTrans.eulerAngles = currRot;
}
// this is the one that does not work, the boolean is there to confirm that the problem does not come form the code to make the monster turn around, but from the condition in the "else if" statement.
else if(distance > 0 && myTrans.rotation.y == 180)
{
Vector3 currRot = myTrans.eulerAngles;
currRot.y += 180;
myTrans.eulerAngles = currRot;
isBehind = true;
}
// change speed and anim according to hunting the player
freakAnimator.SetBool( "isHunting" , true);
Vector2 myVel = myBody.velocity;
myVel.x = -myTrans.right.x * speed;
myBody.velocity = myVel;
speed = 10;
}
// detects if the player is in the trigger used to determined if the monster is close enough to kill the player, and acts accordingly
void OnTriggerStay2D(Collider2D Col) {
if (Col.CompareTag("Player") && hunting && Col.isTrigger == false)
{
hasKilled = true;
freakAnimator.SetBool("HaveKilled", true);
speed = 0;
myBody.isKinematic = true;
preymovement.enabled = false;
preyRenderer.enabled = false;
}
}
// when idling, the monster stays on one platform, unlike when hunting, and when at the end of the platform, it turns around after an idling time.
void Idle () {
hunting = false;
HuntTimer = 0;
freakAnimator.SetBool("isHunting", false);
speed = 1;
// check to see if there's ground in front before moving forward.
Vector2 lineCastPos = GroundCheck.position - GroundCheck.right;
Vector2 lineCastFront = myTrans.position - myTrans.right;
Debug.DrawLine(lineCastPos, lineCastPos + Vector2.down);
Debug.DrawLine(lineCastFront, lineCastFront + Vector2.left);
bool isGrounded = Physics2D.Linecast(lineCastPos, lineCastPos +Vector2.down, enemyMask);
bool isBlocked = Physics2D.Linecast(lineCastFront, lineCastFront + Vector2.left, enemyMask);
//if there's no ground, turn around.
if (!isGrounded || isBlocked)
{
speed = 0;
freakAnimator.SetBool("isIdling", true);
idleTimer += Time.deltaTime;
if (idleTimer >= idleDuration)
{
idleTimer = 0;
freakAnimator.SetBool("isIdling", false);
speed = 1;
Vector3 currRot = myTrans.eulerAngles;
currRot.y += 180;
myTrans.eulerAngles = currRot;
}
}
//Always move forward
Vector2 myVel = myBody.velocity;
myVel.x = - myTrans.right.x * speed;
myBody.velocity = myVel;
}
}
and here's an image showing the case in which the scripts fails to notice the player is behind the monster :
I know that this question came back a few times, and I apologize for asking it once more, but I've searched and didn't find any solution yet, I wouldn't be asking otherwise. é u è
(also quite the number of edits but the script failed to display correctly several times in a row).
Answer by juicyz · Sep 20, 2016 at 11:49 PM
No clue if this fixes anything but... Just out of curiousity:
if(distance < 0 && transform.rotation.y == 0)
{
Vector3 currRot = myTrans.eulerAngles;
currRot.y += 180;
myTrans.eulerAngles = currRot;
}
else if(distance > 0 && myTrans.rotation.y == 180)
{
You are using transform.rotation and myTrans.rotation. Why are you using two transforms that mean the same thing?.... Maybe the second one should be transform.rotation too.
Another type of solution instead of checking the rotation is to have another boolean like isFacingRight or something like that. You would check that instead of the rotation. You would change isFacingRight whenever the enemy changes direction.
To debug this...have print statements before the if and else if, print out the distance variable and the rotation.y value and see if they are what you are expecting. OR pause the game and look at the public variables. distance and rotation are both public so you can look at them using the GUI.
It Worked ! Well, in a weird way, but it does !
Changing the "myTrans" into a "transform" didn't, BUT using a boolean "isFacingRight" did.
The strange thing about it is that at first, the script was supposed to turn the boolean true or false according to the y rotation of the monster ( 0 or 180) but it seems that for some reason, the script is unable to tell when the rotation of the monster is 180 (I checked in game, it really was). But making the boolean change every time the monster changes direction, and making it manualy true or false according to the start rotation of the creature did work. It's odd, but hey, as long as it works...and now the players can fear for their lives è u é
Thanks !
Yeah, I'm guessing it's a little bug somewhere that isn't working right but it's hard to debug when I don't have it in front of me. Guessing it's math related or not checking the right variable and maybe right value but I'm happy that I could provide some sort of solution that it works.
Graphics look cool too!
Run little people run
Well yeah, just having the script doesn't make it easy to solve, maybe it's just some tiny mistake somewhere that compromises the whole thing.
Thank you ^v^ , I'm more of a visual-making guy than a programmer so this is more my element (even through the backround and platforms here are just quick sketch to test ingame)
Answer by AntGoober · Sep 20, 2016 at 08:30 AM
So if the distance is 0 (regardless of direction) the monster flips to face the player? Is it because you've got distance > (GREATER) 0 in the else if statement?
Answer by Freak4Fun · Sep 21, 2016 at 06:22 PM
well, no, since the monster detects the character before, and none of these conditions gets the "if the distance is 0" (it's always inferior or superior to 0) , and I am not sure it is possible for the monster to face the player if the distance is 0 since they would be at the exact same location. (I tried it and to get this distance =0 I had to jump on the monster's head) ( so I changed it so if we do that the monster kills the character.)
also I don't really understand your second question, the distance is greater than zero in the "else if" statement because in this situation (the one depicted in the screenshot) the distance is always greater than zero (I've looked ingame).
This is why I don't get the problem : the angle is indeed 180, and the distance is indeed greater than zero, but the "else if" doesn't notice.
Your answer
Follow this Question
Related Questions
Mirroring Animation with Object Move 2 Answers
A Quick Question About 2D Enemy AI 0 Answers
2d enemy ai 0 Answers
Avoid enemy sprite overlapping 1 Answer
How can i do? (enemy don't refind player game object) 2 Answers