I'm a new unity's user, and I'm trying to make a little 2D plateformer.
I can controle my player but I have a little problem with my jump.
I made it with a trigger in animator, it works, but I want to stop the animation when player touching the ground.
The best will be to keep the last jump's frame prep until the player touch the ground, and after stop it.
I have a collider2D on a gameObjet who's attached to the player with this code:
void Start()
{
Audio = GetComponent<AudioSource>();
Anim = transform.parent.GetComponent<Animator>();
}
void OnTriggerEnter2D (Collider2D col)
{
if (col.gameObject.tag == "Sol" || col.gameObject.tag == "Plateforme")
{
Anim.SetTrigger("stopJump");
transform.parent.GetComponent<playerController>().isGrounded = true;
Audio.pitch = 0.7f;
Audio.volume = 0.7f;
Audio.PlayOneShot(soundGround);
}
}
My animator have a transition 'stopJump' between 'jump' 'idle' and run. Is it the right thing to do?
see my animator here
The animation Jump doesn't want to stop before the ending frame. If i disable 'has exit time', the jump stop too early...
The trigger 'stopJump' does not have priority...
Thanks!
In your state machine of the animator,
just add an idle state and a trigger which will transfer from JUMP state to that IDLE(which will loop when the player is standing on the ground and do nothing) state, then from the OnTriggerEnter2D you could use Animator.setTrigger("triggerName") to transfer the state to idle.
As in our project player should become idle in lots of condition, so we just made an AnyStat transfer to the idle state by trigging backIdel here is the example:
Related
So, i have a Player and a End object. The End has no Mesh renderer, but it has a Box Collider with a Slippary. So its invisible in the game, i tagged it with "End" and write this Script (in the Player).
private void OnCollisionEnter(Collision collision)
{
if (collision.collider.tag == "End")
{
Time.timeScale = 0f;
}
}
But when i hit the invisible object called End, the Player goes ahead. I want to fix this problem because my Player moves on when i finish the game and the coordinates influence the reached points. So it has really to stop (the Playermovement is anytime activated)
My animations enters a state and it's collision with enemy projectiles either defends himself or gets hurt depending on what animation he is currently in. I'm trying to detect collisions with the ONTRIGGERENTER function and boxcollider2D's but it's not having any affect. I want to figure out how to correctly facilitate trigger enters and collisions between these animations.
I've already tried giving my sprite a tag and calling that tag when the ONTRIGGERENTER function is called but it didn't work. I also tried a more complicated way of calling the tag of the collider but that didn't work either. How do you access the trigger when it's an animation?
string DefenceAnimTag = "Defending";
string DestroyEnemTag = "Eliminated";
//This code is connected to the enemy projectile and trying to
//sense when it's collided with the player
void OnTriggerEnter(Collider2D col)
{
if (col.tag == Defending)
{
GetComponent<Animator>().SetBool("Elim", true);
}
else { //deal damage to the player }
}
//The first method didn't work so I tried a second method.
//Here is an alternative attempt at detecting triggers in
//animations.
void OnCollisionStay2D(Collider2D col)
{
if (col.gameobject.CompareString("Defending"))
{
GetComponent<Animator>().SetBool("Elim", true);
}
}
//This method didn't work either even though the Animation
//WOULD be Defending
I expected enemy projectiles to collide with my player when he was defending himself and get defeated. I knew that it was working when the Enemy projectiles transition into their Elim state, where they get defeated by enemy defenses, however they made collisions and then continued unaffected.
Okay, okay, I figured it out. Because a Gameobject can have many animations to it, you cannot go by the tag that the GameObject in the inspector has. You have to go by the title of the Animations that is currently playing. In order to access the animation currently playing we must use the following code:
AnimatorClipInfo[] m_AnimClipInf;
string m_ClipName;
void Start()
{
//Set up our projectile for possible Elimination
//upon Collision
Getcomponent<Animator>().SetBool("Elim", false);
}
void OnTriggerEnter2D(Collider2D col)
{
m_AnimClipInf = col.GetComponent<Animator>
().GetCurrentAnimatorClipInfo(0);
m_ClipName = m_AnimClipInf[0].clip.name;
if (m_ClipName == "Defending")
{
GetComonent<Animator>().SetBool("Elim", true);
//Projectile gets eliminated
}
}
The player is a magican who can attack enemys with fireballs when pressing the left mouse button.
The code i use is pretty simple (inside the Update function):
if (Input.GetMouseButton(0) && canShoot)
{
canShoot = false;
Invoke("AllowCanShoot", fireBreak);
Attack();
}
canShoot is a bool which stops the player from attacking once per frame.
AllowCanShoot is a function that sets canShoot to true.
Attack() is the function that handles the attack, not relevant for this question.
I also have a UI Button that appears on screen when the player is near the trader. When the player presses the UI Button he attacks the trader.
What i want is, that he could press the button without attacking him.
I can't disable attacking for the player, because enemys can get to the trader, too, and the player may have to fight then.
What i tried is:
setting the canShoot bool to false, when the UI Button is pressed, but this isn't working, the player is still attacking, maybe the Update function gets executed before the UI Button function?!
You can use the EventSystem.IsPointerOverGameObject() function to make sure that the mouse is not over a UI object before attacking:
if (Input.GetMouseButton(0) && canShoot && !EventSystem.current.IsPointerOverGameObject())
{
canShoot = false;
Invoke("AllowCanShoot", fireBreak);
Attack();
}
If you can't disable attacking for the player, can you make it that when aiming at the trader, the player can't attack him?
Use a Raycast when near the trader.
Something like this maybe?
void NearTrader()
{
if (Vector3.Distance(trader.position, player.position) < myDistance)
{
RaycastHit hit;
if (Physics.Raycast(player.position, PlayerCamera.transform.forward, out hit, myRange))
canShoot = false;
else
canShoot = true;
}
}
Is there a way to detect if the collider on the player (with a rigidbody) object is not colliding with any other collider in a 2D environment?
Not per se, but there are two ways you can get the information. It's easiest to keep an int counter, and increment it in OnCollisionEnter and decrement in OnCollisionExit. When the counter is 0, there are no collisions.
Another way, which will tell you which colliders are overlapping but not necessarily if they are touching, is to use a physics function. Note which type of collider you have--sphere, capsule, box. Knowing the size/shape/position of the collider, you can call Physics.OverlapBox, Physics.OverlapCapsule, or Physics.OverlapSphere. Give the function the same shape as your collider, and it will return the colliders that overlap that space. (For 2D colliders, you can use the Physics2D.Overlap* functions.)
/edit - actually piojo's idea with counters is better, just use int instead of bool.
One way would be to add an int to your script called collisions and set it to 0. Then if at any point the collider fires OnCollisionEnter just increment it, and in OnCollisionExit decrement it.
Something like this should work for 3D:
public int collisions = 0;
void OnCollisionEnter(Collision collision)
{
collisions++;
}
void OnCollisionExit(Collision collision)
{
collisions--;
}
https://docs.unity3d.com/ScriptReference/Collider.OnCollisionEnter.html
https://docs.unity3d.com/ScriptReference/Collider.OnCollisionExit.html
I don't understand what's with all the number keeping. I just did this for when my character jumps or falls off the edge and it works great.
Both my player and terrain have colliders. I tagged my terrain with a "Ground" tag.
Then check if I am currently in contact with the collider with OnCollisionStay()
void OnCollisionStay(Collision collision)
{
if (collision.collider.tag == "Ground")
{
if(animator.GetBool("falling") == true)
{
//If I am colliding with the Ground, and if falling is set to true
//set falling to false.
//In my Animator, I have a transition back to walking when falling = false.
animator.SetBool("falling", false);
falling = false;
}
}
}
void OnCollisionExit(Collision collision)
{
if (collision.collider.tag == "Ground")
{
//If I exit the Ground Collider, set falling to True.
//In my animator, I have a transition that changes the animation
//to Falling if falling is true.
animator.SetBool("falling", true);
falling = true;
}
}
void OnCollisionEnter(Collision collision)
{
if (collision.collider.tag == "Obstacle")
{
//If I collide with a wall, I want to fall backwards.
//In my animator controller, if ranIntoWall = true it plays a fall-
//backwards animation and has an exit time.
animator.SetBool("ranIntoWall", true);
falling = true;
//All player movement is inside of an if(!falling){} block
}
}
Setting : Creating my first multiplayer game and running into an odd issue. it's a tank game where players can shoot bullets and kill each other
Problem : When the client shoots while moving, the bullet seems to spawn with a little delay which causes the the player to collide with the bullet.
The issue seems to be that the player itself is local and the bullet
is being spawned on the network ( which is causing the delay)
Note: The host player does not have this problem, therefore it's somehow related to networking.
How can I sync the bullet with the client player?
private void Fire(){
// Set the fired flag so only Fire is only called once.
m_Fired = true;
CmdCreateBullets ();
// Change the clip to the firing clip and play it.
m_ShootingAudio.clip = m_FireClip;
m_ShootingAudio.Play ();
// Reset the launch force. This is a precaution in case of missing button events.
m_CurrentLaunchForce = m_MinLaunchForce;
}
[Command]
private void CmdCreateBullets()
{
GameObject shellInstance = (GameObject)
Instantiate (m_Shell, m_FireTransform.position, m_FireTransform.rotation) ;
// Set the shell's velocity to the launch force in the fire position's forward direction.
shellInstance.GetComponent<Rigidbody>().velocity = m_CurrentLaunchForce * m_FireTransform.forward;
NetworkServer.Spawn (shellInstance);
}
Do your game rules need to cater for a player's tank being able to shoot itself?
If not, a simple solution is to have the projectile's collider ignore it's owner's collider when it's being activated:
Transform bullet = Instantiate(bulletPrefab) as Transform;
Physics.IgnoreCollision(bullet.GetComponent<Collider>(), GetComponent<Collider>());
I solved it the following way. if someone can look over to confirm my answer, it would be nice.
private void Fire(){
// Set the fired flag so only Fire is only called once.
m_Fired = true;
CmdCreateBullets ();
// Change the clip to the firing clip and play it.
m_ShootingAudio.clip = m_FireClip;
m_ShootingAudio.Play ();
// Reset the launch force. This is a precaution in case of missing button events.
m_CurrentLaunchForce = m_MinLaunchForce;
}
[Command]
private void CmdCreateBullets()
{
RpclocalBullet ();
}
[ClientRpc]
private void RpclocalBullet(){
GameObject shellInstance = (GameObject)
Instantiate (m_Shell, m_FireTransform.position, m_FireTransform.rotation) ;
// Set the shell's velocity to the launch force in the fire position's forward direction.
shellInstance.GetComponent<Rigidbody>().velocity = 25f * m_FireTransform.forward;
}