I've just started making a 2d physics based game but when I tried to set up a catapult thing to check some features I noticed the projectile started to slide off but when I turned up the friction it also turned up the air resistance, how do I increase friction without increasing air resistance?
In Unity, there are only two values that describe friction. Linear drag, and Angular drag.
Linear drag - describes how fast the object velocity is slowing down per tick
Angular drag - describes how fast the object rotation is slowing down per tick
I think you would need a little script to achieve different drags in different enviroments, pseudo-code would look like this
if(in_the_catapult)
{
// Set the rigidbody to high value to not slide off
rigidbody.drag = 100;
}
else if(touching_the_ground)
{
// Set the rigidbody to what the friction should be on the ground
rigidbody.drag = 2;
}
else if(in_the_air)
{
// Set the rigidbody to what the air resistant should be
rigidbody.drag = 0.1;
}
This code should run in Update to check every frame if the state has changed or it should be run on the event if the condition has changed because it's probable that your bullet will bounce off the ground multiple times.
Related
I'm currently working on a simple 2d jump and run game. I want to move my player with physics (using addforce).
In the editor, my player jumps at a normal height. But when i build the game it suddenly jumps way higher. I put everything in fixedUpdate() and don't know where the problem is?
//Movement
rb.velocity = new Vector2(horizontalMove, rb.velocity.y);
//Jump
if (jumpPressed)
{
if (isGrounded)
{
rb.AddForce(new Vector2(0f, jumpForce), ForceMode2D.Impulse);
anim.SetTrigger("takeOf");
}
}
Dan
If jumpPressed is true for every frame when the jump key is held, this could be the issue. This would mean that the code could act several times, reapplying the upwards force several times (before it goes far away enough from the ground that the ground check does not detect it). If this is the case, it can be fixed by:
rather than using AddForce, set the vertical velocity to the velocity of the jump.
changing the jumpPressed to only return true if jump was pressed this frame
Imposing a limit to how often you can jump (if you cannot jump twice within 0.1 seconds, that could fix the issue)
I have a ball in my demo game that has a bounce rate of 0.6. If the ball lands on a platform, of course it bounces. But the thing is, I actually tried to stick the ball to the platform.
When the ball collides with the surface of the platform, the speed of rigid body 2D becomes 0. But I guess because of the bounce rate, ball jumps a little bit and lands again in 0.02 seconds. Because of this, OnCollisionEnter2D runs for 2 times, which is something I don't want. Here is my code;
private void OnCollisionEnter2D(GameObject other) {
if(other.GameObject.tag == "platform") {
//Sets the rigidbody2D velocity as zero vector, angular drag and linear drag as 10f
game.SetBallVelocity(Vector2.zero, 10f, 10f)
}
}
How can I make OncollisionEnter2D only runs for single time? In another word, let the Ball really stick at the first time?
I don't have enough information to give you the exact answer but one of those should fix the problem:
1: Changing collision mode on the ball's rigidbody (test both Discrete and Continuous)
2: OnCollisionEnter2D is called before the physics calculations that change the ball's velocity, so use OnCollisionExit2D()
Quick side note, your IDE should have warned you of this but other.gameobject.CompareTag("platform") is faster than directly comparing the strings (other.GameObject.tag == "platform")
I have a labyrinth in my unity game, this game also has a red ball that is passing through the labyrinth, both have colliders (The ball circle colliders and the labyrinth edge colliders), it seems to work fine, but, when you drag the ball and push it into the labyrinth, passing some seconds, you can get through the colliders and pass, and, if you get enough speed, you can pass all the labyrinth like nothing!, I put in my script a speed limit (10) but it isn't working that well.
Your problem is FixedUpdate and using CollisionDetectionMode.Discrete.
It is called N counts per second, where N is a fixed value. Physics is calculated on FixedUpdate. Now imagine situation:
FixedUpdate is called 60 times per second. Time between FixedUpdate
calls is 1 second / 60 times = 17 ms (approx.)
Collider A size is
1x1x1, Collider B size is 1x1x1
Collider A attached to still object, Collider B attached to object moving towards Collider B with speed 90 units per second.
Physics engine is comparing position of A and
position of B on FixedUpdate It thinks that Collider B just
teleported through Collider A, because it's speed per one
FixedUpdate tick is larger, then collider's size.
If you are going to use very high speed, you have three options:
Try to follow Foggzie's advice
Increase count of FixedUpdates per second, and avoid overloading it with scripts.
Implement your own physics for high-speed objects
Unity deals with this problem through its Collision Detection Modes. Make sure your Rigidbody components have their collisionDetectionMode properties configured accordingly (they default to Discrete). It seems like you'll want the ball to use ContinuousDynamic and the labyrinth to be Continuous but note, as stated in the link:
Continuous Collision Detection is only supported for Rigidbodies with
Sphere-, Capsule- or BoxColliders.
You'll probably need to change the labyrinth colliders.
I am on my third day of learning Unity and are currently doing the roll-a-ball tutorial. I am trying to add a restart button, that teleports the ball back to the start-position/origin. It all works good, but the ball will keep moving after I restart, but I want it to stay in a spot and not move by itself.
What I mean is that if I'm moving left at max speed and press 'R' to restart, then it will keep moving left fast for some time, but what I want to achieve is that the ball would not keep moving by itself after I restart it's position (perhaps it's speed is just decreasing so slow that it's unnoticeable, in which case I'd want it to slow down faster).
Here's my code that I just tried out and "hoped" would work, but doesn't. I think that the problem I have here is that a new axisHorizontal/axisVertical variable value is assigned again the next frame, the value being taken from Input.GetAxis, which from what I have heard is not possible to change.
That means that a movementForce bigger than 0/0/0 and AddForce will be activated again the next frame.
using UnityEngine;
using System.Collections;
public class PlayerScript : MonoBehaviour {
public float movementSpeed = 7f;
private Rigidbody rigidSphere;
void Start() {
rigidSphere = GetComponent<Rigidbody>();
}
void FixedUpdate() {
float axisHorizontal = Input.GetAxis("Horizontal");
float axisVertical = Input.GetAxis("Vertical");
Vector3 movementForce = new Vector3(axisHorizontal, 0.0f, axisVertical);
rigidSphere.AddForce(movementForce * movementSpeed);
if (Input.GetKeyDown(KeyCode.R)) {
transform.position = new Vector3(0, 0, 0);
rigidSphere.AddForce(0, 0, 0);
axisHorizontal = 0;
axisVertical = 0;
}
}
}
I tried googling on how to change the value that is taken from GetAxis, but others claim it's impossible to do so. So I have really no idea how to make it not keep moving forever...
And I also got a 'bonus' question that has arised during those two days that I have been learning Unity, but they are not worth a seperate question, perhaps if they have been already answered before (I've been unable to find any documentation that'd help me on it), then just give me a link on where I could find the answer to my problem.
The question is that how do I make the ball stop moving after some time after I press a button (W/A/S/D, the default values for positive/negative buttons in Input Manager)? For example, I press 'W' just for a second, but the ball will keep moving forward forever and will never stop.
What I want to achieve is after I for example press 'W' for a second, after a few seconds the ball will completely stop, it just seems that the value from GetAxis never goes back to 0. I tried to google about it, and I think it's something to do with Gravity in the Input Manager - I tried changing it, but the ball will still keep moving forever, the only thing I noticed did change was the speed of the ball.
I'd be really grateful if someone could help me with these problems.
I am trying to add a restart button, that teleports the ball back to
the start-position/origin. It all works good, but the ball will keep
moving after I restart, but I want it to stay in a spot and not move
by itself.
I see that you tried to solve this by using rigidSphere.AddForce(0, 0, 0);. This will only add 0,0,0 to the existing force the ball is moving at. The solution to this is to set the Rigidbody velocity to 0.
Replace rigidSphere.AddForce(0, 0, 0); with rigidSphere.velocity = Vector3.zero;
Even when you do this, Input.GetAxis value increases and decreases over time before reaching 0. So, on the next frame, the ball might still be moving due to this.
To stop this, also replace Input.GetAxis with Input.GetAxisRaw.
Input.GetAxisRaw will immidiately return to 0 when the key is released.
What I want to achieve is after I for example press 'W' for a second,
after a few seconds the ball will completely stop, it just seems that
the value from GetAxis never goes back to 0.
Since the ball is rolling, you need to increase the angular drag of the ball. This will make the ball stop rolling after releasing the key. The angular drag is on the Rigidbody attached to the ball. Also increase the drag if that's not enough.
I've got a coin RigidBody and walls around it with box colliders. For trial purpose I've applied the following code to the coin.
private void OnMouseDown()
{
rigidbody.AddForce(30.0f, 0f, 5.0f, ForceMode.Impulse);
}
But, sometimes the coin passes through the walls, but when I increase the speed from 30 to 50 points it passes through the walls on the first click. I've googled a lot and still got nothing except for the DontGoThroughThings Script which doesn't work for me or I don't really know how to use it.
I've always added a continuous dynamic on the coin and continuous collision detection on the walls but still doesn't work.
the problem with physics collision detection is that sometimes when the speed of an object is too high (in this case as a result of a force added to the rigid body) the collision wont be detected. The reason is that the code you are executing is running at x ammount of steps per seconds so sometimes the rigidbody will go through the collider between one step to another. Lets say you have a ball at 100 miles per hour and a wall that is 1 feet wide, the code will move the ball a determined ammount of feets everytime the code is runned according the physics of it, so the movement of the ball is virtualized but its not a real physical movement so it can happen that from one step to another the ball can move from point a to b and the wall is between those points and as a result the collision will not be detected.
Possible Solutions.
You have a simple solution that wont be as accurate as it should be and a harder one that will be perfectly accurate.
The solution number one will be increasing the colliders size, according to the max speed your coin can get, that way the collider will be big enough so that the collision wont be missed between one frame to another.
The second and harder solution will be adding an auxiliar to your collision detection, some kind of a security check. For example using physical raycast. You can set a raycast to forward direction and determine if that object is an inminent collision, if it does and once the object isnt being collided by the raycast anymore then your collision detection had failed that way you have your auxiliar to confirm that and call the collision state.
I hope it helped and sorry about my english. If you didnt understound it very much i could help you with code but i will need some code from your project.
See if the colliders have their 'Is Trigger' unchecked.
Also, check if the gameObjects have colliders.
I have faced this problem many times..
Make sure Your coin's Rigidbody has "Is Kinamatic" False, Is Triggger:false,
And also "Is Trigger" of walls is False.
You could save the velocity and position on each update and then test for out of bounds, if the coin leaves the valid area you can restore it at the last valid position or plot the collision yourself if you want to