I am new to unity, and i am trying to create a bouncing ball, so i've did many researches about bouncing realted physics and i found a formula :
Formula:
-2*(V dot N)*N + V
Where V is the velocity vector and N is the normal of the surface on which the ball will bounce
Here is my script :
using UnityEngine;
using System.Collections;
public class BallPhysics : MonoBehaviour {
void Start () {
rigidbody2D.velocity =new Vector2 (-1,-3);
}
// Update is called once per frame
void Update () {
}
void OnTriggerEnter2D(Collider2D col) {
if (col.gameObject.name == "Pong") {
tBounce ();
}
}
void tBounce(){
RaycastHit2D hit = Physics2D.Raycast (new Vector2 (transform.position.x,transform.position.y), new Vector2(-1f,-1f));
Vector2 n = hit.normal;
Vector2 v = rigidbody2D.velocity;
Vector2 R = -2 * (Vector2.Dot (v, n)) * n + v;
rigidbody2D.velocity = R;
}
}
I am giving the ball a velocity vector in the start function, i am using OnTriggerEnter2D for collision handling and raycast2D to get the normal of a surface.
The problem is that the script doesn't reflect the velocity vector called R, i think the probleme is in the normal vector.
For example let's say V is a Vector2(-1,-1) so basically R should be (-1,1), but it's not. R is (3,1) !
i've successfuly been able to make a ball bouncing on Horizontal/vertical surface by reversing the ball velocity but this won't work properly with arbitary angles,that's why i am using this formula.
So what's the problem ?
Your raycast is likely hitting the wrong collider. You start it at transform.position. That is the center point of your ball object.
Imagine a ray coming out of a circle's center. What's the first line it hits? It hits the circle itself first. So your Raycast reports the surface normal of the ball, not the pong paddle.
There are many ways to get around this. You can apply a Physics Layer that ignores raycasts. I think there is one pre-defined like that. You can create custom ones as well and supply a layer mask to your raycast.
There are other ways to solve it like originating the raycast from somewhere else, but since you're doing this as the objects collide, a layer mask is probably the simplest.
Related
I am creating a 2D platformer type game, and it has non flat terrain. How do I make it so that my character's legs always smoothly transition from a flat surface to a slope surface?
For reference you can check out [Alto's Adventure] (http://altosadventure.com/) (mobile). In that, the skateboard snaps to the curvy terrain.
Feel free to ask for more details.
To make such a possibility, you have to send a ray to the ground and then set the direction of up transform according to the Normal vector point of impact. The following code solves the basic problem.
public LayerMask groundLayer;
public float maxRayLength = 3;
public float offset = .5f; // set it to half of your character height
public void Update()
{
var ground = Physics2D.Raycast(transform.position, -transform.up, maxRayLength, groundLayer.value);
if (ground)
{
transform.up = ground.normal;
transform.position = new Vector3(ground.point.x, ground.point.y) + transform.up*offset;
}
}
In addition to the script, you must specify a suitable 2D collider as well as its layer. For layers, make sure that both the script inspector and the layer are set to the hypothetical ground layer.
Example Result:
I have a simple cannon I am trying to program to shoot a projectile. I have 4 game objects:
The tank object
A Pivot Object (child of tank)
A Cannon Object (child of pivot)
An empty GameObject called Tip which sits just above the cannon (child of cannon)
My code for the cannon object is below:
public class cannon: MonoBehaviour
{
public float power = 1.0f;
public Transform projectile;
void Update()
{
if (Input.GetButtonDown("Fire1"))
{
Transform bullet;
Vector2 pos = transform.GetChild(0).position;
bullet = Instantiate(projectile, pos, Quaternion.identity);
Rigidbody2D bullet_rb = bullet.GetComponent<Rigidbody2D>();
bullet_rb.AddForce(pos * power);
}
}
}
Everything seems to work okay, until I looked at the trajectory of the projectiles when the cannon is aimed directly along the x-axis. There is still a small y component to the applied force, which I didn't expect and do not desire.
Here's a gif:
What could be causing this behavior?
The force you're adding is pos (times a scalar power)... The position of your cannon is above zero on the y axis, so that's why it launches with a y offset. I'm assuming it has an x offset too, just less noticeable, because the base (tank) is centered at x while it's above center in the y. Try moving the whole tank setup off away from the scene root; you'll probably see a huge spike in the force of the projectile, because of this error of using pos.
What you want is a vector representing a pure direction instead. One that is also normalized (magnitude of one). In this case, either right (forward in 2d) or up, from the perspective of the rotating tip or cannon.
I have a 2D scene that consists of 4 sprites, each with a box collider.
I then have a prefab that is simply a sprite of a circle with a 2D circle collider.
Finally I have a script named Atmosphere attached to my main camera that will fill the box with lots of instances of the prefab and give them a velocity in a random direction.
using UnityEngine;
public class Atmosphere : MonoBehaviour
{
public GameObject Molecule;
void Start()
{
float x = -4.5f;
while (x < 4.5f)
{
float y = -4.5f;
while (y < 4.5f)
{
var inst = GameObject.Instantiate(Molecule);
inst.transform.position = new Vector3(x, y, 0);
var rb = inst.GetComponent<Rigidbody2D>();
float xForce = Random.value * 2f - 1f;
float yForce = Random.value * 2f - 1f;
rb.AddForce(new Vector2(xForce, yForce) * 100f);
y += 0.5f;
}
x += 0.5f;
}
}
}
For a while the dots bounce around against each other and the edges of the box.
But after a while they eventually get stuck to the edges of the box.
Both the box and balls and the box walls have the same physics material
Which has zero friction and a bounciness of 1.
Why do they stick to the walls, and how can I stop it from happening?
Download Unity 3D demo
UPDATE
If I drop a single molecule into the box with the following script attached it gets stuck to the wall immediately.
[RequireComponent(typeof(Rigidbody2D))]
public class Molecule : MonoBehaviour
{
Rigidbody2D RigidBody2D;
void Start()
{
transform.position = new Vector3(0, 1, 0);
RigidBody2D = GetComponent<Rigidbody2D>();
float xForce = Random.value * 2f - 1f;
float yForce = Random.value * 2f - 1f;
RigidBody2D.AddForce(new Vector2(-.25f, -0.25f) * 100f);
}
}
Unity3D has a velocity threshold. Objects with a velocity below this threshold won't bounce etc.
The solution is to go to Edit > Project Settings > Physics 2D and to set the Velocity Threshold lower.
EDIT - The real solution:
So I was doing some reading on integration techniques and it hit me: The energy you're losing is quite likely coming from numerical inaccuracies stemming from several approximation techniques compounded.
I'm guessing the continuous collision detection algorithm is mostly to blame, floating-point error accumulation, but probably also from numerical integration techniques.
What you're trying to achieve is elastic collision, which means that it satisfies conservation of energy as well as momentum. The trick is going to be for you to add a script to every object that preserves the energy of the system by adding error-correcting velocity over time. Whether you actually use the energy route or not is up to you, there are a number of ways to track and modify the energy resulting in a change of velocity. Momentum would be the would be the easiest to track in my opinion. What you're trying to achieve is elastic collision, which means that it satisfies conservation
i.e.
Make a component that preserves the scalar quantity of kinetic energy or momentum (it'll probably produce the same results)
When you initialize all the particles with a velocity, make sure to save the starting momentum in the particle's script. I would save the scalar quantity for simplicity, so just use the length of velocity
Every frame, in the update event check the velocity of the rigid body. Find the change in momentum or change in energy and add the -difference and apply it to the object.
I doubt you'll have to work on collision events as well, especially if you use the exact same mass for every object. Here's a link with an example where someone corrected unity's friction-less physics using conservation of energy https://answers.unity.com/questions/168393/frictionless-physics.html
colliders may be stuck in each other for the reason of low contact offset, go to edit-project settings-physics2d and increase the default contact offset a little bit, 0.12 for example, it was work for me.
cheers
I have a script attached to a mesh with a kinematic, rigid body with a convex mesh collider that I'd like to move around. Here's what I call in my update function:
if (Input.GetKey(forwards)) {
Debug.Log("forwards!!");
//get current velocity in local space
Vector3 localVel = transform.InverseTransformDirection(body.velocity);
//alter so that forward component = speed
localVel = new Vector3(localVel.x, localVel.y, linearSpeed);
//convert back into world space and set to body
Vector3 worldVel = transform.TransformDirection(localVel);
body.velocity = worldVel;
}
Other Info:
body is a Rigidbody variable that I assign in Start() using GetComponent<Rigidbody>();
linearSpeed is a float with value 1
I'm getting the Debug.Log output, but my mesh is not moving. Is there anything obvious I'm missing here? This is my first script for a 3D, as opposed to a 2D game.
public float speed = 20;
Rigidbody r;
void Start(){
r = gameObject.GetComponent<Rigidbody> (); //Put's reference to local rigidbody into variable "r"
}
void FixedUpdate () {
Vector3 direction = Vector3.zero; //set's current direction to none
//Adds vectors in case that user is pressing the button
if(Input.GetKey(KeyCode.W)) direction += Vector3.forward;
if(Input.GetKey(KeyCode.S)) direction -= Vector3.forward;
if(Input.GetKey(KeyCode.D)) direction += Vector3.right;
if(Input.GetKey(KeyCode.A)) direction -= Vector3.right;
//Normalizez direction (put's it's magnitude to 1) so object moves at same speeds in all directions
r.AddForce (direction.normalized * speed); //Adds direction with magnitude of "speed" to rigidbody
}
Rigidbody MUST be attached to same GO as this script. This script uses world directions, because working with local directions is much harder (the object is rotating and changes directions rapidly, you can use it if you want just by replacing reference to Vector3 to transform like this:
if(Input.GetKey(KeyCode.W)) direction += transform.forward;
Of course for all direction.
This is very basic way to move the object along it's local axises, to do it more better you need to write specific scripts for specific sets of objects, it all depends what kind of object are you moving and how you want to move it. (is it sphere, cube..., will it ever fly up, should it rotate....).
If the RigidBody is Kinematic it is meant to be moved by means other than the physics system; animations, transform.position, etc. Make your rigid body non-kinematic and it should move when you set velocity.
I want to move a rigid body in an elliptical movement like the player movement "whale trail" game.What I did is:
Created a Cube called "Player" with scale(1.5,0.5,0.1)
Created another small cube called Point with scale(0.1,0.1,0.1) and positioned same as Player but 0.5 more in x (So that now the player looks like a 2D rectangle and a point on it little right to the centre of the rectangle).
Then I created a fixed joint between both bodies
Now I applied for on the player at the position of the Point as follows ,
float mfAngle = 0.0f;
void update()
{
mfAngle=transform.eulerAngles.z;
mfAngle=mfAngle%360;
if(mfAngle>=0 && mfAngle<90)
{
mfXforce=-0.1f;
mfYforce=0.1f;
}
if(mfAngle>=90 && mfAngle<180)
{
mfXforce=-0.1f;
mfYforce=0.1f;
}
if(mfAngle>=180 && mfAngle<270)
{
mfXforce=-0.1f;
mfYforce=-0.1f;
}
if(mfAngle>=270 && mfAngle<360)
{
mfXforce=0.1f;
mfYforce=-0.1f;
}
Debug.Log("Angle ="+mfAngle+"X = "+mfXforce+"Y = "+mfYforce);
Vector3 pointPos=_goPointObject.transform.position;
transform.rigidbody.AddForceAtPosition(new Vector3(mfXforce,mfYforce,0),pointPos);
}
But it doesn't works fine.I just moves upwards and the turns and moves in different direction.If anyone know how to move the rigid body in elliptical motion by applying force give me a solution.(I want to use it as like whale trail game u can see the video of the "loop movement" in this http://www.youtube.com/watch?v=wwr6c2Ws1yI video).Thanks in advance.
I had found the solution by myself.To achieve that elliptical movement u have to create two bodies and connect them with joint by placing it horizontally next to each other.Then u have to apply force in x direction constantly and in Y direction only when the Screen is be touched on the first body.
And its important to reduce the X speed when moving up then u will get that elliptical rotation.
It works fine for me.
Thanks,
Ashokkumar M