- Home /
Gun rotation and bullet trajectory mismatch
Hi,
Ok, I really need some help please, this has been bugging me for ages and I can't figure it out. I'm trying to prototype a simple 2D sidescrolling platformer for a touch screen device. I want to use the left thumbstick to control the direction the player character shoots, as soon as the user presses the thumbstick, it starts to shoot in the same direction as the thumbstick.
The problem is that the bullets that I instantiate to not travel in quite the same direction as the arm/gun rotates which makes it look like there is a kink in the stream of bullets. I've also tried RaycastHit2D and Debug.DrawLine to help me visualise everything but I really want a projectile that the user can see rather than a ray. Check out the picture below for clarity ...
Obviously the Raycast is blue, and the white bullets are my instantiated projectile. The way everything is setup is that the arm/gun called playerArm is a child of the main character (which I have temporarily removed for clarity) and then the point of instantiation is a child of playerArm, it's called shotSpawnPoint.
The only thing that I have identified is that I made a public variable in shotSpawnPoint and made it equal to its rotation on the z axis to monitor it and compare it with my playerArm z rotation. It is very very different. Please see below ...
If you can't see the picture clearly, the z rotation of playerArm here is 26.1422 yet the z rotation of shotSpawnPoint is 0.2261603. Also, the transform handles of the GameObject playerArm are pointing in the same direction of the bullets, but the sprite of the GameObject is rotated further around. Also, the z rotation of shotSpawnPoint is only between -1 and 1, yet playerArm is between 0 and 360.
For clarity, I have another GameObject called firePoint as a child of shotSpawnPoint +200 on the x. I use this as the 'to' point in my Raycast.
Please see below my code for the playerArm, weaponFire (attached to shotSpawnPoint) and finally bulletMove (attached to my bullet prefab) respectively.
playerArm script
using UnityEngine;
using System.Collections;
public class armController : MonoBehaviour {
public float xAxis = 0.0f;
public float yAxis = 0.0f;
public float theAngle = -18.0f;
public Vector3 angleVector;
public float armFallSpeed = 5.0f;
// Update is called once per frame
void FixedUpdate () {
//Get the positions of the x and y axis
xAxis = CFInput.GetAxisRaw ("Vertical");
yAxis = CFInput.GetAxisRaw ("Horizontal");
//If the user is pressing on the D-pad calculate 'theAngle' to be the sum, in rads of the x and y axis of the D-pad
if( xAxis != 0 || yAxis != 0 )
theAngle = Mathf.Atan2 (xAxis, yAxis) * Mathf.Rad2Deg;
//Clamp the arm
if ( theAngle > 125.0f )
theAngle = 125f;
else if (theAngle < -120.0f)
theAngle = -120.0f;
//Return the arm to resting position
if (theAngle > -18.0f && xAxis == 0.0f && yAxis == 0.0f)
{
theAngle -= armFallSpeed;
if (theAngle < -18.0f + armFallSpeed)
theAngle = -18.0f;
}
if (theAngle < -18.0f && xAxis == 0.0f && yAxis == 0.0f)
theAngle += armFallSpeed;
transform.rotation = Quaternion.Euler(0.0f,0.0f, theAngle);
//I've also tried the following and it exhibits the same behaviour.
//transform.rotation = Quaternion.AngleAxis( theAngle, Vector3.forward );
}
}
weaponFire script
using UnityEngine; using System.Collections;
public class weaponFire : MonoBehaviour {
public float fireDamage = 10;
public LayerMask whatToHit;
Transform shotSpawnPoint;
private float shotDistance = 100f;
Transform firePoint;
public Transform bulletTrailPrefab;
public float thisRotationZ;
// Use this for initialization
void Awake ()
{
shotSpawnPoint = transform;
if( shotSpawnPoint == null )
{
Debug.LogError ("No shotSpawnPoint! WHAT!?!");
}
firePoint = GameObject.Find ("firePoint").transform;
if( firePoint == null )
{
Debug.LogError ("No firePoint! WHAT!?!");
}
}
// Update is called once per frame
void FixedUpdate ()
{
//When user presses the thumbstick, shoot.
if( CFInput.GetAxis ("Horizontal") != 0 || CFInput.GetAxis ("Vertical") != 0 )
{
Shoot();
}
//Monitor the z rotation.
thisRotationZ = transform.rotation.z;
}
void Shoot()
{
//Confirm Fire.
Debug.Log ("FIRE!");
Vector2 shotSpawnPointPosition = new Vector2( shotSpawnPoint.position.x, shotSpawnPoint.position.y );
Vector2 firePosition = new Vector2( firePoint.position.x, firePoint.position.y );
RaycastHit2D hit = Physics2D.Raycast ( shotSpawnPointPosition, firePosition - shotSpawnPointPosition, shotDistance, whatToHit );
Debug.DrawLine ( shotSpawnPointPosition, firePosition, Color.cyan );
if (hit.collider != null)
{
Debug.Log ("We hit " + hit.collider.name + " and did " + fireDamage + " damage." );
Debug.DrawLine ( shotSpawnPointPosition, hit.point, Color.red );
}
Bullet();
}
void Bullet()
{
Instantiate ( bulletTrailPrefab, shotSpawnPoint.position, shotSpawnPoint.rotation );
}
}
bulletMove script
using UnityEngine;
using System.Collections;
public class bulletMove : MonoBehaviour {
public float moveSpeed = 230.0f;
// Update is called once per frame
void Update ()
{
transform.Translate ( Vector3.right * Time.deltaTime * moveSpeed );
Destroy ( gameObject, 1 );
}
}
Any help anyone might be able to give would be greatly appreciated. Thank you in advance!
Answer by FortisVenaliter · May 14, 2015 at 05:34 PM
The only thing I notice is that your are handling the direction differently between the raycast and the shot. The raycast has a forward vector of (firePosition - shotSpawnPointPosition) whereas the bullet has a forward vector of weaponFire.transform.forward.
Maybe when you instantiate the bullet, have the rotation be Quaternion.LookAt(firePosition - shotSpawnPointPosition, Vector3.up) and then have the bullet move along it's forward z-axis.
Nice one!!!!!! Yes, that did it. Thank you sooooooo much! That has been hampering me for so long, thank you thank you thank you.
Although I couldn't use Quaternion.LookAt I had to use Quaternion.LookRotation. I don't know if thats what you meant? I had to Google LookAt, and found LookRotation in the Unity documents.
This is what I ended up with inside the void Bullet() function ...
void Bullet()
{
Vector3 shotTarget = firePoint.position - shotSpawnPoint.position;
Quaternion shotRotZ = Quaternion.LookRotation (shotTarget);
Instantiate ( bulletTrailPrefab, shotSpawnPoint.position, shotRotZ );
}
And now it shoots directly along the Raycast.
I'm so happy right now! Cheers FortisVenaliter!
Glad that worked for you. Please mark it as the correct answer, if you would, to close the question and allow others to reference it.