Ok, for this task I need to coordinate physics hitting a game object at a certain point and animation, to create the illusion of punching a character and he stumbles back as if propelled by that contact point.
I have rigid bodies on both the hitting object and character being hit, and can tell when the hitting object enters the character's box collider. What I thought to do first was create an impulse at the contact point then trigger my pre made character animation -
Vector3 direction = (this.transform.position - collider.transform.position) / (this.transform.position - collider.transform.position).magnitude;
this.transform.GetComponent<Rigidbody>().AddForce(direction, ForceMode.Impulse);
Problem is this just makes the character float slowly off opposite the hitting object (Rigidbody has gravity checked on character), and depending on where the character is facing, the animation looks not coordinated with the punch.
I wanted to see whether there's a streamlined way of doing this - how can I create a realistic punch/moving backward situation in Unity?
There's no easy way to get this behavior out-of-the-box with Unity. You will need to script a blending of ragdoll physics with animations.
One approach you might want to try is a system that "pins" your ragdoll to the bones of an animation, and if a collision occurs, the ragdoll unpins itself (partially or completely) from the bones, temporarily. When/if it completes being affected by physics, you would probably want to animate from a keyframe dynamically created based on the position of the ragdoll to a target keyframe.
There are also tools like PuppetMaster on the asset store that are meant to do things like this, but they are often not free, because they are difficult to make well.
Related
I recently started having a look at game development with Unity and was trying to make a simple 2D character with basic movement abilities. This character is supposed to jump and move from side to side, but only if it is standing on something.
Now my question is: How do you check if a player is standing on something? / Get the distance to the next game object / collider beneath the player game object?
Would greatly apreciate any helpful answers and especially explanations on how exactly it works. Thanks!
To do this, you need to send a ray to detect the point of impact on the ground and then calculate the distance. The code below sends a ray from the center of your object down to the maximum height (3) and gives the size.
public LayerMask groundLayer;
public float maxRayLength = 3;
public void Update()
{
var hit = Physics2D.Raycast(transform.position, Vector3.down, maxRayLength, groundLayer.value);
if (hit) Debug.Log(hit.distance); // it will print current distance from pivot
}
If you want to calculate the height of the ray from the character's foot, there are two methods, one is subtracting half the height of the character from it.
Physics2D.Raycast(transform.position-transform.up*height, ....)
Next one is to use an empty object at the base of the character, which we refer to instead of the center.
public Transform pivot;
Then..
Physics2D.Raycast(pivot, ....)
There are a few ways of actually doing this.
The most usual although a bit complicated way of doing it for a beginner is using Raycasts. A Raycast is basically a small invisible line that starts and ends where you tell it to. If anything of a specific tag or layer is caught in it's crossfire you can basically pull that object from your code. Raycasts are used for a lot of things, most notably in Shooter games to shoot or in games like Skyrim to pickup objects and interact with them.
Another way to do this, which is a bit more popular in 2D games is to create a "feet" GameObject and make it the child of the player in the hierarchy. You can add a box collider on that GameObject and check the "IsTrigger". You can add a Tag to your ground objects and through your code using the OnTriggerEnter() and OnTriggerExit() Methods you can basically tell when your character is floating on air and when he is on ground.
Another popular method is to use the Physics.OverlapBox() Method which is pretty much the same as the Trigger Method but you are creating an invisible box (much like a raycast) and instead of only getting notified when Triggered (something enters or exits) you check if the invisible box is colliding with another object/tag/collider (which could be your ground).
There are also a few different things you can do with a Nav Mesh (mostly in 3D) but I think that for now these 3 should suffice!
I want to add knockback to my entire player when it shoots, so it can impulse itself.
I'm new to making games, I don't know much about c# and I haven't found any tutorials for the thing I need
Difficult to know what you need help on here. But try to I'll answer the question.
When your player fires their gun, you would typically create a new object and apply a force to it for slow move projectiles or alternatively, you'll do a ray trace to see if the target is hit for laser beam style shots.
To make the player move, use AddForce on their Rigid Body to apply a force in the opposite direction. That direction is simply the negative direction of the projectile's direction (or the ray that was traced)
I want to make a complex system of character movement, with such features as wall crawling, double jumps, etc. and with the further possibility of adding complex elements. I have a choice: 1) I tried to do the movement through rigidbody.velocity changing. But I ran into the following problem: I don’t know how to perform the exact BoxAllCast because I don’t know the exact distance that the body will travel with the changed velocity per frame 2) and using rigidbody.MovePosition is bad because, as I understand it, it does not pass in one frame, but I want have full control over the player, and if you make the controller through rigidbody.velocity changing, then you get a lot of stuck in textures, shaking in textures etc.
Please help me decide, maybe someone can share the sources of a complex movement system so that I can see how they implement it, and generally suggest about the best method for changing the position of a rigidbody
Often complex character controllers won't use the Rigidbody component but instead use a Character Controller component as it provides more control over character movement. Physics accurate controllers are difficult to control as they are controlled by physics. Character controllers allow you to define how physics will work on the controller while also being able to 'force' the player to take certain actions (instead of letting the physics engine do so)
As Tony Li says "An accurate physics-based model will feel muddy. Players are used to pressing a direction input and seeing their character move immediately without waiting for forces to propagate through the physics simulation. That's why CharacterController exists."
https://forum.unity.com/threads/how-to-approach-designing-a-complex-character-controller.345923/#post-2238687
I've create a movement script that moves a character (ship) in a topdown view.
Gravity is disabled, but the rest of the settings i left mostly alone.
I'm applying a constant force in the forward or backward direction (local, so relative to the character NOT the world). This however causes some movement in other directions if the character is rotated for some reason.
Debug.Log(nameof(force) + force);
rigidBody2D.AddRelativeForce(force);
Lets me explain with pictures.
Starting point:
Moving forward somewhat (works okay):
Back to starting point (stopping game, starting anew)
And then i manually change the rotation to -90 in the inspector.
I then move forward somewhat.
As we can see since the rotation is -90, moving forward in relative to the character (AddRelativeForce(..)) causes it to move to the right on the screen.
The X position increments accordingly.
However, also the Y component changes, the character gets velocity in this direction, even though i apply no force in that direction - which we can see in the output.
How can I move my character with force without this issue?
Edit:
Here are the project files. Runs under the latest unity 2020.1.14f1. The logic mentioned here is located in MoveExecuteSystem. I use a small ECS framework: https://github.com/Leopotam/ecs
https://wetransfer.com/downloads/b86dfb27b4388b85ac4fef285d87b39520201124193329/00af66
Take into account that AddRealtiveForce adds the force in the local coords system. If the force vector has got always the same value, the outcome is going to be different depending on the rotational position of the entity.
To solve this, you need to apply the force such as: Vector3 force = myShip.forward * forceValue where force value can be an int or a float.
It can be myShip.up or myShip.right depending on what you want. My point is that with the .forward, .up or .right you always will apply the force according to the instant local coordinate system rotational position.
EDIT:
This question seems deeper than I thought, I made the trial in a project myself, and actually there are variations in the position when you apply force only when the object is rotated. Had a quick look and don't know why this is. Seem to be a precisión thinh regarding the rotations of the physics the rigidbody uses under the hood.
I tried to remove the friction which I thought might be also cause of the problem but seems not possible. +1 to this question and lookig forward to know the answer.
EDIT2:
Bounciness and friction can be set to 0 if a new physics material 2d is created, but the issue persists.
You can freeze position in determined axis as a solution, but this does not explain the position variation problem.
I am working on a Unity game in a 2D environment. The player GameObject has a Rigidbody2D attached. It moves horizontally when swiping. When swipe is too fast, it does not collide with the Colliders. Maybe it changes its transform position before detecting collision? It does not happen when the swipe is slow.
Based upon your problem I am assuming you are moving your object in the Update() function (please correct me if not). This means you are moving the object a certain amount every frame. However, Unity checks colliders and does physics calculations on a different time interval (Fixed Timestep, https://docs.unity3d.com/Manual/class-TimeManager.html).
Just before the objects collide, the colliders are checked. Unity calculates colliders every Fixed Timestep (default 0.02 times a second). If unity does not detect a collision it means your objects intersect for less time than the Fixed Timestep, or in other words, they are moving very fast (like you describe your situation). One (bad) way to fix this would be to decrease the amount of time in between physics calculations. However, this would greatly decrease your programs efficiency.
Instead, consider moving your object in the function FixedUpdate() so that the object only moves every time the physics checks for a collision. This should fix your problem.
Take a look at the 3rd answer (by Garth-Smith):
https://forum.unity3d.com/threads/rigidbody-2d-wont-collide-with-another-object-when-its-moving-really-fast.248786/
I particularly want to highlight the part:
If you have a Rigidbody2D, you should be moving it in FixedUpdate()
using rigidbody2D.MovePosition(Vector2). This will move the
Rigidbody2D through space, instead of teleporting it from point A to
point B.
The second part about Raycasts should not be necessary for your problem, but if you continue to experience problems your can use them to check a range as jdweng stated in his comment.
Here are a couple places to learn about Raycasts if you are unfamiliar with them:
https://docs.unity3d.com/ScriptReference/Physics2D.Raycast.html
https://unity3d.com/learn/tutorials/topics/physics/raycasting
If the movement of your object is too fast it will simply ignore the collision since it never touches the actual collider - it just skips it.
In order to fix this you need to predict when that collision will happen and trigger it at correct moment.
Setting collision detection to Continuous as pixlark said might help if the swipe is not too fast.
Make sure that the collision detection mode for your Rigidbody2D is set to Continuous or Continuous Dynamic.
simple
go to the rigidbody of the object and change the c