So I'm making a simple 3D RPG game in Unity with a player and a bunch of enemies. What is the standard way to keep track of the damage taken in combat? I think the easiest way is to count damage everytime the attack animation is triggered, but how? How do I know whether an animation is triggered or not? Or is there any other way to do it? Please help, thanks in advance!
So you want to detect if the enemy hits you with a projectile/melee. The way to do that is attaching a collider to their weapon, you can do this by setting empty game objects as children of the weapon and attach individual collider components to them (Don’t do this unless you know how to make it not take multiple damages at once. Just for extra precision). Then what you want to do is for each/the collider hit the isTrigger check box so it has a check in it. Add a tag to the collider(s) that has a name like “damage” or “weapon”. Then open a script to attach to your player. Use OnTriggerEnter() to detect the weapon hitting your player:
...//the rest of your code before this.
public float health = 10f; //health value.
public float damageTick = 1f; //damage taken per hit
void OnTriggerEnter(Collider obj)
{
//for same damage per different weapon hit.
if (obj.GameObject.Tag == “damage”) //remember this is what the tag of the weapon was.
{
health -= damageTick;
//play the animation. You can do that.
}
//*optional* for different damage per weapon type.
if (obj.GameObject.Tag == “sword1”)
{
health -= sword1Damage; //make sure you have a variable for sword1Damage.
}
else if (obj.GameObject.Tag == “bow8”)
{
health -= bow8Damage; //make sure you have a variable for bow8Damage.
}
// add on to this if else, to make more weapons take different damage.
}
It's too expensive. If you have 10 enemies, then the calculations through the colliders will overload the system.
It's easier to calculate, when the user clicks on the attack button, create a primitive and see what objects are included in this primitive around it. Push them onto the stack. Further, if your attack is at a distance, you can count through the vectors of the nearest enemy, if the damage is massive, then you can set the hitting radius and inflict damage on all enemies in this zone using the observer pattern
Related
I am making a 2D game and have a basic weapon which I decided to call a pistol. I want to make a shotgun next and I have all of the work done except for the fact that they are all spawned in the same place and they all collide with each other.
I've had a few ideas like trying to turn off collisions for the rigidbodies (Didn't work), applying force without a rigidbody (Didn't work). I've done one game before this which was through a tutorial so this is my first real game and I just need help. If you need more details I can always send more. Thank you.
Jump into the Physics2D settings and make sure that the layer you’ve set for your “bullets” is not colliding with itself.
The one you’ll want to turn off for self collision is usually the one on the end, that intersects with itself on the row and column:
The script you need is the following line. In this line, Unity physics renders one collider ineffective against another.
Physics2D.IgnoreCollision(collider, ignoreCollider);
Also, with the algorithm below, you can neutralize all colliders at the moment of the bullet shot.
[SerializeField] private GameObject bulletType;
private List<Collider2D> _tempCollides;
void ShotBullets()
{
_tempCollides.Clear();
for (int i = 0; i < 4; i++)
{
// Instantiate and catch all colliders in a List
var collider = Instantiate(bulletType, AnyPlace, AnyRotation).GetComponent<Collider2D>();
_tempCollides.Add(collider);
}
foreach (var _collider in _tempCollides) // For Every Bullet Collider...
{
foreach (var _subCollider in _tempCollides) // .. Define to Ignore other Colliders..
{
if (_collider != _subCollider) Physics2D.IgnoreCollision(_collider, _subCollider);
}
}
}
I'm trying to use the EventManager and according Events to calculate the distance between objects, and to do something when enough objects are close to the target.
I watched video's on YouTube and searched for examples on Google, but I couldn't find something that looks like what I want. Of course I also watched the explanation videos of Events in general, but I just don't get it. They are all English, which is not my native language, this makes it difficult to understand. So, also sorry for any grammar mistakes. They often talk so fast. So please don't think I'm lazy, I have searched for hours but I just don't get it.
I have one target object, and several enemy objects. This enemy objects have the tag 'Enemy'. The target object can move. I made a coroutine, so when the target moves, the enemies follow, until a distance of 0.5. But from the moment that they reached the distance of 0.5, the enemies won't move anymore. Instead they should also follow the target when they already reached their target position. So to prevent this, I changed the while(Vector3.Distance(transform.position, target.position) > 0.5f) in while 1 > 0, (so just always) and I deleted the part of the code that was about 'after the while loop'. But this is probably not the right way.
So, in short, I want to make an Event that keeps track of when enemies reaches or loses their target position. When three enemies are on their target position, I want to make them blue.
Could anyone show me how I can do this? I don't get it now, but when I see how it works I can use this for more events in the game.
I think You can use trigger collider, just make it bigger then your target object, then do all you want about enemies in methods OnTriggetEnter, OnTriggerStay
As an another technique you can use raycasts. Raycasts will provide you more performance than colliders.
You can locate your raycasts in your target position, in case your raycast hit the enemy then make them blue. For Example;
public LayerMask enemyLayer;
bool isTouch = false;
public bool isTouched(){
if (Physics.Raycast(transform.position,-Vector3.up,1f,enemyLayer)) {
isTouch = true;
return isTouch ;
}
return !isTouch ;
}
I am using the navmesh/agent on the player as an assistance autopathing function where the agent is disabled at all times unless the user clicks a point on the floor to walk towards. Then the agent will be disabled again once the destination is reached.
I need a way to check if the player is currently on the navmesh, within a tolerable threshold without the navmeshagent being enabled. Or, if there is a way to remove the player-binding 'effect' of the navmeshagent without disabling it, as I could use that to solve my problem too.
I guess in pseudocode, this is what i'm trying to accomplish with navmeshagent disabled:
if (!agent.isOnNavMesh){ DisableClickSelection();}
I was thinking of the possibility of comparing the Y transform of the player and the navmesh to get a height difference and using that to determine if the player is on the navmesh but i don't know how to go about getting the Y transform of the navmesh at a specific X and Z point. Maybe i can use a raycast? I'm not sure the best way. Like i said, if there is a way to remove the player-binding 'effect' of the agent on the player but keep the agent enabled I would be able to work with that too.
You should be able to do this through use of NavMesh.SamplePosition(). This method basically searches in a spherical radius around a given position for the nearest point on the navmesh. All you need to do is verify that the returned position is vertically in line with the player position, and is on/above it.
Here's an idea on how you might apply this in code:
// Don't set this too high, or NavMesh.SamplePosition() may slow down
float onMeshThreshold = 3;
public bool IsAgentOnNavMesh(GameObject agentObject)
{
Vector3 agentPosition = agentObject.transform.position;
NavMeshHit hit;
// Check for nearest point on navmesh to agent, within onMeshThreshold
if (NavMesh.SamplePosition(agentPosition, out hit, onMeshThreshold, NavMesh.AllAreas))
{
// Check if the positions are vertically aligned
if (Mathf.Approximately(agentPosition.x, hit.position.x)
&& Mathf.Approximately(agentPosition.z, hit.position.z))
{
// Lastly, check if object is below navmesh
return agentPosition.y >= hit.position.y;
}
}
return false;
}
So for using it with your example, you'd write:
if (!IsAgentOnNavMesh(agent.gameObject))
{
DisableClickSelection();
}
Hope this helps! Let me know if you have any questions.
I have two scripts, one attached to a gameobject and the other attached to an enemy prefab that is instantiated over time. The script attached to the gameobject uses OnTriggerEnter2D to detect when the enemy has entered, then the health bar for the object goes down by one. Iit works, the only problem is now is that because of the fact that the enemy comes up then walks back down, the enemy is colliding with the objects more than once which is not what I want.
I have tried things like using booleans to stop it colliding more than once but other prefabs enemies isn't able to collide with the gameobject because of the boolean is being set to true and not being set back to false. I don't want to use yield wait for seconds because enemies do spawn often and so it won't really look normal; I also tried onTriggerExit2D but you get the idea if I try that method. Is there any other way of detecting if an enemy has entered the objects collider damaging the object once but then when the enemy comes back down he ignores the collision (without turning off the enemies or the gameobject's collider) aka all instantiated enemies is able to collide with the gameobject when they are going up but not when they are coming back down.
Your best bet is to simply do a bool check on the monsters if they're going north or not. There are several ways to go about this. If you know where they are going you can simply compare where they are going to where they are and compare the y vector values. so something like this:
public bool monsterNorthChecker(){
if(monsterDestination.y > currentLocation.y){
return true;
}
else{
return false;
}
}
Then you can simply call that function OnTriggerEnter and verify if the monster is going north or not, if he is, take away his health. If you don't know his destination, you'll probably have to resort to more tedious means of determining destination direction. Something like comparing the y values of last frame's vector2 to this one and see which way he's moved.
I am trying to build a 2D space shooter game where the player will remain constant at the bottom of the screen and will move left and right. When the player fires a bullet(projectile), the bullet is going up just fine, but it is coming back again. Also if two bullets collide, they react to the collision.
I have two questions here:
How can I ensure that the bullet does not come back? (One way is to destroy it after a few seconds, but not sure if this is the right way)
How do I avoid collision between the bullets.
Here is my code snippet:
void Update () {
if (Input.GetButtonDown("Fire1"))
{
Rigidbody2D clone = (Rigidbody2D)Instantiate(bullet, transform.position + transform.up, transform.rotation);
clone.velocity = transform.TransformDirection(Vector3.up * 20);
}
}
I am very new to Unity and somehow wrote this code by looking into Unity Forums.Any help will be very much appreciated.
Thanks
More details:
I have created the bullet and added Rigidbody2D and a BoxCollider2D for this object. Made the bullet object a prefab and I dragged it under the Player object. Now bullet is a child of the Player object. Attached the script above to the Player object.
To answer your immediate questions:
1) I am not too sure about how you have the scene setup or about using the Unity 2D tools but usually if your bullets are coming back down then I would assume that you still have gravity applied to the rigidbody -- so make sure that you have that unchecked.
2) With Unity3D for objects to interact with each other they need rigidbodies attached. This is vital, say, if you want your lasers to destroy Monster #1. However, you only need one rigidbody attached to an object to have a desired effect. I would suggest removing the rigidbody from your laser and attach rigidbodies to objects ( Monster #1 ) that you want to be affected by the laser fire. ( That should work, if not there are other options -- one using layers and ignoring particular objects on those layers ).
Tips:
Here are some extra things. When you are creating objects and they fly off screen over time they will build up. Imagine you are in a large battle and you instantiated hundreds of lasers -- it will eventually be an issue for performance. So always consider Destroying objects after a certain amount of time.
Also, after looking at your code, I can't tell whether the velocity of the object is based upon its current position and nothing is being added. What I think is happening is when you instantiate an object it may be moving up, but because there is no incrementer, the object ( as it gets higher ) slows until it is at a rate which it is falling. For example this
clone.velocity = transform.TransformDirection(Vector3.up * 20);
should probably do this:
clone.velocity += transform.TransformDirection(Vector3.up * 20);
Heres http://docs.unity3d.com/Documentation/ScriptReference/Vector3-up.html, to read up on velocity. The problem is is that you need to continuously apply a constant forward motion so things in motion will tend to stay in motion. If not gravity will pull it down.
Also, heres a bit of code that I've used in the past that's created a pretty cool shooting laser effect thing:
public class Laser : MonoBehaviour {
public int fireRate = 70;
void Start(){
InvokeRepeating("FireLaser", 0.01f, 0.009f);
Destroy( gameObject, 2.0f );
}
void FireLaser(){
transform.Translate( Vector3.up * fireRate * Time.deltaTime );
}
}
edit: it's 3 a.m. and I hate proofreading.