Trajectory of projectile slightly off Unity2D - unity3d

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.

Related

How do I make my 2D character's legs snap to non flat terrain?

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:

Unity: How to find a empty hole in a wall for player?

I'm trying to figure out simple custom 2D physics for platformer. At the moment I'm using ray casts to figure out collision between the player and map. However using ray cast has some problems. For example, if the player is falling (has somewhat high downwards velocity) its unable to pick up holes in the wall because it moves past them due to going too far down to be detected as empty space.
One solution is to move to tile based system instead of using ray casts but I would preferably not to do so.
So I'm wondering is there some kinda solution to figure out empty holes in wall, even small edge ones without huge performance impact.
High quality drawn illustration, assume leftwards velocity:
Physics2D.BoxCast is how I would tackle this. It does what you expect, instead of a ray it calculates as if a full box was traversing the distance.
Usage is very similar to raycasting. Example:
public Collider2D mainCollider;
public Vector2 velocity;
void Update() {
Vector2 origin = new Vector2(transform.position.x, transform.position.y);
Vector2 size = mainCollider.bounds.size;
Vector2 direction = velocity * Time.deltaTime;
float maxDist = velocity.magnitude;
var hit = Physics2D.BoxCast(origin, size, 0, direction, maxDepth);
if (hit == null) {
transform.position += direction;
} else {
transform.position += direction.normalized * hit.distance;
}
}
If boxes are not your taste, there's also a Physics2D.CapsuleCast and Physics2D.CircleCast.

transform.LookAt() causes Y angle to increase by 180

I am trying to create a third person spaceship movement.
The spaceship rotates about all axes at its position, and has a throttle control to move in forward direction. There is a camera which is always behind it. I am not making the camera a child because I want the camera to NOT follow the rotation about z axes.
The camera has a script, which keeps its position a fixed distance behind the spaceship, and then calls transform.LookAt(spaceShipTarget).
The problem is that as I rotate the ship around global x axes 90 degrees, the y axis of camera suddenly does a 180 degree rotation. The camera control script is below:
using UnityEngine;
namespace UnityStandardAssets.Utility
{
public class FollowBehind : MonoBehaviour
{
public Transform target;
public float distance;
public float delay;
private Vector3 velocity = Vector3.zero;
private void LateUpdate()
{
Vector3 offset = target.transform.TransformVector(0, 0, distance);
Vector3 currentPosition = transform.position;
Vector3 finalPosition = target.position + offset;
transform.position = Vector3.SmoothDamp(currentPosition,
finalPosition, ref velocity, delay);
transform.LookAt(target);
}
}
}
Why would that happen and how can I fix it?
The problem you have with the rotation of the camera is probably caused by the script you use to make the camera follow the spaceship, probably because when you rotate the spaceship the rotation (and probably the position) of the camera are affected.
What you could do instead is make both the spaceship and camera child of another object, and then add a script to this parent object. Now you can put some code in the script of the parent to move the parent itself (this way both camera and spaceship will move together, and you don't need to keep them together manually) and also in the script of the parent you can put some code to rotate the spaceship and camera individually or together based on specific inputs.

assigning velocity to rigidbody doesn't do anything

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.

2D bouncing formula doesn't work properly

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.