- Home /
My enemies merge when they come towards me
public Transform target; public int moveSpeed; public int rotationSpeed; public int maxDistance;
private Transform myTransform;
// Use this for initialization
void Start ()
{
GameObject go = GameObject.FindGameObjectWithTag("Player");
target = go.transform;
}
void Awake ()
{
myTransform = transform;
}
// Update is called once per frame
void Update ()
{
float distance = Vector3.Distance(target.transform.position, transform.position);
myTransform.rotation = Quaternion.Slerp(myTransform.rotation, Quaternion.LookRotation(target.position - myTransform.position),rotationSpeed * Time.deltaTime);
if(distance < 15f && Vector3.Distance(target.position, myTransform.position) > maxDistance)
{
myTransform.position += myTransform.forward * moveSpeed * Time.deltaTime;
}
}
this is the code I have On my enemy the allows them to come towards me, but when multiple enemies is coming towards me the just merge into one, any suggestions on how I can fix this. "Comment" if the code looks messy I can re-post it :)
Answer by AlucardJay · Feb 27, 2013 at 04:09 PM
I cannot offer a solution to your script, only provide an alternative. The behaviour you're looking for is based on physics (things recognize and bump into things), and if you want to use colliders as colliders or triggers then you need a rigidbody for that. So a basic rule could be 'for anything that moves, add a rigidbody'.
There is a neat little pattern I noticed with transform.position and rigidbody.velocity :
transform.position += transform.forward * speed * Time.deltaTime;
rigidbody.velocity = transform.forward * speed;
With this pattern it is easy to recode transform.position to work for rigidbody.velocity. But sometimes it seems rigidbodies have a mind of their own. To help prevent this, there are the Constraint settings. Check/tick (enable) all the Freeze Rotation boxes.
SO first to explain the setup of my script. On your enemies, attach a rigidbody component, freeze all rotations in the constraints portion, leave gravity enabled. Replace your script with this one (make sure the name of the class is the name of your script, in my example it is called RecognizeColliders ).
using UnityEngine;
using System.Collections;
public class RecognizeColliders : MonoBehaviour
{
public float moveSpeed = 8.0f;
public float rotationSpeed = 2.0f;
public float minDist = 4.0f;
public float maxDist = 45.0f;
private float minSqrDist;
private float maxSqrDist;
private Transform myTransform;
private Transform target;
private Rigidbody myRigidbody;
private Vector3 desiredVelocity;
void Start()
{
minSqrDist = minDist * minDist;
maxSqrDist = maxDist * maxDist;
myTransform = transform;
myRigidbody = rigidbody;
GameObject go = GameObject.FindGameObjectWithTag( "Player" );
target = go.transform;
// moveSpeed += Random.value * someMultiplier; // add randomness to each enemy moveSpeed, same can be done for rotationSpeed
}
void Update()
{
float sqrDist = ( target.position - myTransform.position ).sqrMagnitude;
Quaternion calcRot = Quaternion.LookRotation( target.position - myTransform.position );
desiredVelocity = new Vector3( 0, myRigidbody.velocity.y, 0 );
// apply rotation
myTransform.rotation = Quaternion.Slerp( myTransform.rotation, calcRot, rotationSpeed * Time.deltaTime );
// modify desiredVelocity if within range
if ( sqrDist > minSqrDist && sqrDist < maxSqrDist )
{
desiredVelocity = myTransform.forward * moveSpeed;
desiredVelocity.y = myRigidbody.velocity.y;
}
}
void FixedUpdate()
{
myRigidbody.velocity = desiredVelocity;
}
}
Bear in mind C# is not my native tongue, so this may be inelegant but is tested and working.
A couple of things you may notice different to your script :
Distance has been replaced by square distance. Square distance is much easier for Unity to calculate, and with this running every update on every enemy, using square distance helps performance. If you know your desired distance, then it is more efficient to use
if ( (tgt.position - tx.position).sqrMagnitude < ( minDistance * minDistance ) )
than
if ( Vector3.Distance(tgt.position - tx.position) < minDistance )
and it is so easy to get the square of your desired distance (minDistance * minDistance ) ! So theres a consideration.
Next one is instead of directly applying a move calculation to the transform, that calculation is stored in a variable. In this case it's called desiredVelocity, mainly for using this value to apply to the rigidbody in a FixedUpdate. Sometimes it is better to write another line of code instead of cramming all the calculations into a command, mainly to make things easier to read (especially when starting out). Sure an extra variable takes a little memory, but really for a Vector3 is insignificant. There is no such problem for writing one extra line of code to break things up a bit, there is really no efficiency difference here apart from what pros consider neat and tidy. I have a longhand way of writing with spaces and comments.
Point in case is the conditional check for if the target is within range :
if ( sqrDist > minSqrDist && sqrDist < maxSqrDist )
very easy to read and see what is going on there =]
I think that's about it apart from where the velocity.y is reapplied to desiredVelocity, for the purpose of gravity. If the object is falling, we want it to keep falling.
Which brings me to my big consideration with using this method - you can use this on uneven terrain =]
Here is a package I have built for you, to demonstrate my example script in 2 environments : flat and uneven. Create a new Project (to avoid confusion with your scripts and assets), then import the package. Run both scenes, controls for player are WASD and LMB to shoot. Then check the components on the enemy, and the rigidbody settings. The other scripts are in uJS (from another of my answers), I don't have the time or need to convert them sorry.
Now this isn't perfect as it is a basic script, but hopefully it demonstrates a way to be able to recognize collisions with your characters. You need to include considerations as mentioned by robertblu (adding randomness to the enemy move and rotation speed). Another thing to look into is the suggestion by MickM which is to employ character controllers as they look after collisions. The player script is actually my modified version of the Rigidbody FPS walker script on the Unity Wiki. All you can do is experiment and have fun.
oops, nearly forgot, here's the link to the example package : http://www.alucardj.net16.net/unityanswers/RecognizeColliders.unitypackage
The upload seemed a little slow, so if there are any problems I shall upload it again.
Thank you so much, it works great and know I can finally go on, The example package is great didnt take long at all.
That's great, glad you liked it. I was waiting first before expanding. Now you can see the enemies still like to stack with rigidbodies and gravity, without sliding off. Why? because every fixed update the velocity is hard coded, even when off the ground. In the Character Controller there is a variable called isGrounded. With this you can quickly check and decide to only do things based on if this is true or not.
Without a character controller you have to do this manually. In my script (RecognizeColliders) add a variaable :
public bool isGrounded = false;
now modify the FixedUpdate and add the new 3 functions as shown below :
void FixedUpdate()
{
if ( isGrounded )
{
myRigidbody.velocity = desiredVelocity;
}
}
// ----
void OnCollisionEnter( Collision other )
{
//Debug.Log( "Enter : " + other.collider.gameObject.name );
if ( other.collider.gameObject.name == "Terrain" )
{
isGrounded = true;
}
}
void OnCollisionStay( Collision other )
{
//Debug.Log( "Stay : " + other.collider.gameObject.name );
if ( other.collider.gameObject.name == "Terrain" )
{
isGrounded = true;
}
}
void OnCollisionExit( Collision other )
{
//Debug.Log( "Exit : " + other.collider.gameObject.name );
if ( other.collider.gameObject.name == "Terrain" )
{
isGrounded = false;
}
}
see how much more smoother and natural they behave. You can see in FixedUpdate just a check for ifGrounded apply desiredVelocity, or else the rigidbody just does it's thing. (especially when you shoot them back while they are in the air).
It works, great. the enemies move smoother and before sometimes the enemies goes on top of one another but it doesnt do that anymore
This is just the start of making your own character controller. you can use Unitys character controllers, and there are some written by other people on the Unity Wiki : http://wiki.unity3d.com/index.php?title=Scripts/General
PS : you can accept the answer that worked for you by clicking on the grey tick. This rewards the poster and answerer with karma, and marks the question as answered and accepted. Thanks.
I tried clicking on the grey tick button but it wouldn't let me for some reason? Just to let u know :)
Answer by AfricanMoney · Feb 26, 2013 at 11:38 AM
I think you shouldnt try to fix people's comments and try to help them because they want to learn programming rather than having to read your stupid comments on how to use the website correctly, I think if you are not going to post an answer don't post anything at all. Stop posting those stupid comments and stop wasting my time and other people's time who has to read the comments.
Next time think twice before posting that comment again, because you are just wasting your time and annoying me and other users
Goodbye and don't post on this question again!!!!!
@African$$anonymous$$oney - Alucardj is one of the more active members of this community, and I am personally delighted that he encourages community members to use this site correctly. There are many sites where people can learn program$$anonymous$$g. This site is intended to help people with specific problems using Unity.
@Graham Dunnett
it is great that He is a more active member, but don't you think that if He is a more active member, He should use His knowledge and wisdom of program$$anonymous$$g to help people become better programers ins$$anonymous$$d of telling people how to use this website.
I know there is other sites, but I like the unity website because I get answers from the community and from people that has had this problem before and they a eager to share their knowledge, and what they have done to fix that problem.
I only started program$$anonymous$$g a year and a half ago, I dont get a lot of time to do program$$anonymous$$g because I am still at school. Then I ask a question and I get a reply from @alucardj telling me how to use this website, its not helping me. I would rather that He help me become better at program$$anonymous$$g.
just when I get out, they drag me back in ....
Dude, seriously, why are you on this crusade to flame and/or silence me?
"He should use His knowledge and wisdom of program$$anonymous$$g to help people become better programers" : is this not reflected in my 417 (and rising) answers in 12 months? Not including my countless technical comments that are out there.
So mellow out and have a look at the comment that started this rant :
Hi There. (friendly intro)
Please don't post comments as answers. (rules)
Post comments by clicking the [add new comment] button, a window then open for you to type in. (helpful instruction)
Answer fields are for answers only, as this is a knowledge base. Here at Unity Answers, Answer means Solution, not Response. (fact)
You can convert this answer to a comment (or just edit your original question), (helpful instruction)
you'll also get a better chance of getting an actual answer if the main list shows none or one answer in blue =] (helpful information to get more traffic to your question, and my smileyface)
Under the answer where it says edit | delete | more , click on more , then convert to comment (helpful instruction)
Also you don't have to wait for a moderator to approve a comment. (helpful information to understand the process)
Do you realize how many times I have been actually thanked for this info, and how many people have suffered from negative votes for not doing so? Can you not see this is aimed at educating and avoiding negative karma for a better experience? For both those asking questions and those searching for answers without asking duplicate questions?
"I would rather that He help me become better at program$$anonymous$$g" : Well I was watching this question before your flame war and actually had some suggestions if the other answers didn't work out.
Pull your head in, get humble and appreciative, learn to take advice from your peers, and try to devote all this wasted energy into productivity for your project. If you feel the need to perpetuate your crusade, go ahead, it's your life, but my suggestion is Get Over It. The votes to comments on this page should speak for themselves.
Graham, thankyou for your kind words. I know I shouldn't bite but this is the first time I have been really flamed and it was the last thing I ever expected on this 'site. 99.9999% of the people here are very friendly.
@robertbu : I cannot believe I flagged you with that generic notepad post! Am in awe of your C# skills and you have a great understanding of rotations too. Wow, sorry, of course your judgement would be better than $$anonymous$$e for what you consider your replies to be (answer or comment).
I never meant to and had no intention of trying to police users activity, it just turned out that way when I got to moderator status. After a few days of typing the same thing to new users, my generic notepad of posts was born, simply to save me finding the previous version to copy pasta.
After all this I am now thinking it is a wasted effort as you stated. It's such a regular occurrence in the moderation que sometimes I just cannot be bothered and approve the obvious good questions/answers, then just leave the rest for another mod to decide. Thanks for posting to me with your thoughts.
I hope my answer doesn't offend, just thought I'd try to help as it was asked for rather than my comments. All the best.
Answer by robertbu · Feb 26, 2013 at 06:24 AM
It is a significant task to add logic to keep your enemies apart based on distance, but you can randomize there movements somewhat. Instead of specifying absolute values for rotationSpeed and moveSpeed, specify a range for these values, then every couple of seconds, each enemy can recalculate his own values. If the player stands in one place, the enemies will still come together (eventually), but while the player is moving they have a greater chance at the enemies spreading out a bit...some will lag, some will take longer to make turns.
Note that your moveSpeed, rotationSpeed should be float values, not int values.
Hi There.
Please don't post comments as answers. Post comments by clicking the [add new comment] button, a window then open for you to type in. Answer fields are for answers only, as this is a knowledge base.
Here at Unity Answers, Answer means Solution, not Response.
You can convert this answer to a comment (or just edit your original question), you'll also get a better chance of getting an actual answer if the main list shows none or one answer in blue =]
Under the answer where it says edit | delete | more , click on more , then convert to comment
Also you don't have to wait for a moderator to approve a comment.
O$$anonymous$$ I know what to do, but I'm not really sure how to do it. Do I just add a Random.Range at the beginning of my update function?
eg. var n$$anonymous$$oveSpeed = Random.Range (2, 8);
var nRotationSpeed = Random.Range (2, 6);
Or is there something else I have to do.
Thank you for all the help
hi there #alucardj
Every time you add one of those comments it gets peoples hopes up because they get and answer to there question, just to find that you posted that message, this is a Q & A website stop posting those messages because it is really annoying and not helpful!!!! >:(
I wouldn't do it each frame, and you have to recalc the class variables, I try do it ever second or two. Something like (untested):
function Start () {
InvokeRepeating("RecalcSpeeds", 0.0, 1.5);
}
function RecalcSpeeds(){
rotationSpeed = Random.Range (2.0, 8.0);
moveSpeed = Random.Range (2.0, 6.0);
}
This recalculates the class variables for moveSpeed and rotationSpeed very 1.5 seconds. Play with the ti$$anonymous$$g and the values. You want to create variation among your enemies while still having them move towards the player.
Hey @African$$anonymous$$oney : well it's simple then, isn't it, follow the rules. Do you think I like going through the moderation que to see a 20:1 ratio of answers that should be comments. Don't you think I would rather be enjoying myself reading and helping with actual technical questions ins$$anonymous$$d of trying to get people to just use this website as it was intended.
ftr this is a knowledge base where people come to read answers, and not have to filter through a ton of useless comments ins$$anonymous$$d of actual answers ....
how about you watch : http://video.unity3d.com/video/7720450/tutorials-using-unity-answers
and read : http://answers.unity3d.com/page/faq.html
so I can spend my time more productively
Answer by MickM · Feb 26, 2013 at 07:15 AM
The reason they are merging is you are modifying the transform directly (which will ignore physics collisions) Try add a character controller to them and use the simple move function, while they will still run into each other it will be a collision so they won't merge (you will find they will probably end up circling you or be spread in a frontage near you)
For implementation look here : http://docs.unity3d.com/Documentation/ScriptReference/CharacterController.SimpleMove.html
I will check back here when I get home in case you need code... You should be able.to make it work from there though!
Your answer
Follow this Question
Related Questions
Multiple Cars not working 1 Answer
Distribute terrain in zones 3 Answers
How to spawn enemy? (Enemies) 1 Answer
Issues rotating around transform.up 2 Answers
Fixing screen resolution 1 Answer