- Home /
Fire projectile, tracing a Raycast, enemy AI, 2D
'Aight, here's the situation:
Enemy patrols, depending on direction, speed and whether it's hit a wall or not.
If the player walks inside its range, it stops and STARES O_O...
It also does some damage and knocks the player back on collision - standard stuff...
What I want it to do: - Instead of STARING at the player ... I want it to trace a raycast, instantiate my laser object and apply force in the direction ( or using the angle ) of the raycast. - Alternatively ... I could make it shorter than the player and make it a dull enemy firing in a straight line ... but that wouldn't be fun now would it.
Here's my script so far with the note that I already have some working enemies and a boss fight, it's just this that I'm having an issue with, I don't want to be spoon fed and would much rather theoretical responses with short examples THANKS!
public class Enemy1 : MonoBehaviour
{
//Public variables
public float moveDistance; //Distance the enemy will move on both sides/aka Patrol distance
public float moveSpeed; //Speed at which the enemy will move
//Private variables
private bool playerInside; //Used to check if the player is inside
private float orgPos; //The enemy's original position
private float useSpeed; //Some more speed variables
private bool wallInTheWay; //Indicates if a wall has been hit
private Animator _anim1; //Used for animation, specifically the shooting one
//Some general logic
void LateUpdate()
{
Debug.DrawRay (transform.position,GameObject.Find ("nyan").transform.position - transform.position , Color.green);
}
//Setting up CoUpdate() and variables
private IEnumerator Start()
{
//Grab the component so that we can animate stuff
//_anim1.gameObject.GetComponent<Animator> ();
//Patrol speed and initial position
useSpeed = -moveSpeed;
orgPos = this.gameObject.transform.position.x;
//Assign bools to false, avoiding any stupid scenarios
wallInTheWay = false;
playerInside = false;
//And finaly start CoUpdate()
yield return StartCoroutine (CoUpdate ());
}
//CoUpdate - Update() with the block functionality
private IEnumerator CoUpdate()
{
//Stuff here happens once
//Update
while (true)
{
//Screem, aim and fire
if(playerInside)
{
yield return StartCoroutine(ScrAimFire());
}
//Or... wait for it... waaaaait for it...
else if(!playerInside)
{
//If there is no wall in the way patrol in regular intervals
if(!wallInTheWay)
{
//Based on position, assign direction
if(orgPos - this.transform.position.x > moveDistance)
useSpeed = moveSpeed;
else if(orgPos - this.transform.position.x < -moveDistance)
useSpeed = -moveSpeed;
//And move...
this.transform.Translate (useSpeed * Time.deltaTime, 0, 0);
}
//If there is a wall there however...
else if(wallInTheWay)
{
//Translate the object accordingly
yield return StartCoroutine(WallMovement());
}
}
//Always - to avoid infinit loops and crashes
yield return null;
}
}
//Check if the player is in range
private void OnTriggerEnter2D(Collider2D plr)
{
if (plr.gameObject.tag == "Player")
playerInside = true;
}
//Make sure to disable the trigger if the player is no longer in range
private void OnTriggerExit2D(Collider2D plr)
{
if (plr.gameObject.tag == "Player")
playerInside = false;
}
//Various collision checks
private void OnCollisionEnter2D(Collision2D obj)
{
//If it's a player...
if (obj.gameObject.tag == "Player")
{
//Knockback and stop the player ... kinda messy due to all the component fetching
if(obj.gameObject.GetComponent<Rigidbody2D>().velocity.x < 0)
{
obj.gameObject.GetComponent<Rigidbody2D>().velocity = new Vector2(0,0);
obj.gameObject.GetComponent<Rigidbody2D>().AddForce(new Vector3(2000.0f,0.0f,0.0f));
}
else if(obj.gameObject.GetComponent<Rigidbody2D>().velocity.x > 0)
{
obj.gameObject.GetComponent<Rigidbody2D>().velocity = new Vector2(0,0);
obj.gameObject.GetComponent<Rigidbody2D>().AddForce(new Vector3(-2000.0f,0.0f,0.0f));
}
//Also remember to do some damage
_Player.curHealth -= 50;
}
//If it's a wall, make sure the rest of the script knows this
if (obj.gameObject.tag == "Wall")
wallInTheWay = true;
if (obj.gameObject.tag == "Lava")
Destroy (this.gameObject);
}
//Make sure you know when you're no longer touching the wall
private void OnCollisionExit2D(Collision2D obj)
{
if (obj.gameObject.tag == "Wall")
wallInTheWay = false;
}
//Wall Logic - simple
private IEnumerator WallMovement()
{
//This should do for now ... Plan on making it float back up later on
RaycastHit2D rightWall = Physics2D.Raycast(this.gameObject.transform.position, Vector2.right, 5.0f);
//If you hit a wall on the right
if (rightWall)
this.transform.Translate (-moveDistance, 0.0f, 0.0f);
//Otherwise...
else
this.transform.Translate (moveDistance, 0.0f, 0.0f);
//And make sure you dont teleport/run back to the wall
orgPos = this.transform.position.x;
//ALWAYS!!
yield return null;
}
//The actual scream, aim and fire logic
private IEnumerator ScrAimFire()
{
yield return null;
}
}
I'm a little fuzzy about what you are asking. Typically a class like this one will have a reference to the player. And will initialize it in Start():
private Transform player;
void Start() {
player = GameObject.FindWithTag("Player").transform;
}
Then to apply force, you can do:
Vector3 dir = player.position - transform.position
player.rigidbody2D.AddForce(dir * someForce);
You may want to vary the force based on the distance to the player. You can get the distance with 'dir.magnitude' to make the calculation.
Ugh ... I'll try making it as simple as possible, sorry for any controversy over my initial explanation. Here goes -
I have an enemy, that's twice taller compared to my player. That enemy has to fire a projectile at the player when the player is in range. But the player can jump ... and move, so firing a projectile in the same direction would make it bad and easy to kill.
I want a ray to be cast at the player, originating from the enemy. Using that ray I want the enemy to fire a better aimed projectile that takes care of jumping and any movement in general, while posing a challenge.
You can see what I mean with the:
Debug.DrawRay (transform.position,GameObject.Find ("nyan").transform.position - transform.position , Color.green);
Line. I basically want the projectile to follow this ray.
EDIT: OR alternatively I just realised, I can assign a variable to equal the player's transform while the player is in range, and fire a projectile in that direction.
EDIT2: Testing something...
Answer by robertbu · Apr 21, 2014 at 06:25 PM
I'm assuming "nyan" is your player. As with my previous comment, typically you would find it once in Start() rather than call it in the bowels of your code. Assuming the projectile is coming from 'transform.position', then all you need to do is:
Transform player = GameObject.Find ("nyan").transform;
Vector3 dir = player.position - transform.position;
projectile.rigidbody2D.AddForce(dir.normalzied * someForceFactor);
Often a projectile is Instantiated and moved on it forward. So you would have something like:
Transform player = GameObject.Find ("nyan").transform;
Vector3 dir = player.position - transform.position;
Vector3 look = Quaternion.LookRotation(dir);
GameObject go = Instantiate(projectilePrefab, transform.position, look) as GameObject;
go.rigidbody2D.AddForce(go.transform.forward * someForceFactor);
Right ... for some reason this is giving me an "object reference not set to an instance of an object" when trying to apply force...
I'm using the exact same thing over in my player script ... (kind of)
Vector3 direction = playerPos.position - transform.position;
Rigidbody2D clone;
clone = Instantiate (laser, this.transform.position, Quaternion.identity) as Rigidbody2D;
clone.rigidbody2D.AddForce (direction * 5000.0f);
The reason why I'm not using Vector3 look is because "You can't convert a vector3 to a Quaternion" and if I use a quaternion they go all funky so... this should do
AW$$anonymous$$AY! Fixed it ... thanks a bunch (I had the wrong prefab assigned to laser doh!)
PS: I'd upvote you... but since I don't have 15 $$anonymous$$arma it's Unity's policy not to trust me sorry :<
Question answered feel free to close it... lasers look a bit awkward but I'll make them rotate sooner or later (they don't rotate according to the direction they're going in ugh...)
Unfortunately I believe that requires 50 $$anonymous$$arma ... so ugh
I converted my comment to an answer. You can close the question out by clicking on the checkmark next to the answer.
Your answer
Follow this Question
Related Questions
WayPoints mixed with Raycast 1 Answer
Have falling object exit from a collider after collision? 2 Answers
AI Evasion help 1 Answer
How can I get a character to patrol and follow terrain? 1 Answer
Jitter on Slerp - Raycast 0 Answers