So I have this player (right now it is a sphere rolling around). This sphere has a game object called “weapon spawn point”. Attached to weapon spawn point is a script that instantiates and fires a bullet prefab when I left click my mouse.
Attached to the bullet prefab is the following script.
using UnityEngine;
using System.Collections;
public class BulletManager : MonoBehaviour
{
private float speed = 20f;
// Use this for initialization
void Awake ()
{
transform.rigidbody.velocity = Vector3.forward * speed;
Destroy (gameObject, 1f);
}
}
When I move my character around and left click my mouse, the instantiated bullet only moves forward along the z axis regardless on the direction the player is facing. Now my question is how do I get my player’s bullet to fire in the direction (x,z) last moved by my player (or the way my player is facing).
You’ll need to change Vector3.forward to transform.forward.
Vector3.forward is always 0, 0, 1 in world space, transform.forward is the local z direction.
That doesn’t quite work, because my character is a sphere, and as I roll around it shoots all over the place (including upwards).
Sorry, I missed that bit. You do want the bullet rigidbody velocity to be transform.forward otherwise it will always go in the same direction (World Z forward). The problem is with the object that is spawning the bullets - if it’s a child object that it’s rotating with the sphere and it’s forward direction is spinning all over the place.
I assume you want the bullet to fire in the direction the player is moving? In that case you should be able to use the player inputs (plugged into a Vector3) as the direction to fire in.
"
That won’t quite work either. Consider this scenario. I am moving forward really fast, and I hit the left arrow once. I wouldn’t want my player to fire left, as my players isn’t left. Also if my player stops moving, where will it fire. I was just wondering if there was a way to “lock” my firing to only hit in front of the player.
Will your camera always look towards the player? If so, that’s always a good starting point.
My camera is 10 units, back and up, from the player, regardless of the way it is facing, or the rotation of the player. Meaning if my player moves “World Z” Forward, it moves exactly as much in the same direction. Same for all directions. Right now this is temporary, but I want the weapon worked out first. Basically think of it only rotating around the x and z axis, not y, following the player where he moves.
CameraController Script
using UnityEngine;
using System.Collections;
public class CameraController : MonoBehaviour {
public GameObject player;
private Vector3 offset;
// Use this for initialization
void Start () {
offset = transform.position;
}
// LateUpdate is called once per frame after Update
void LateUpdate () {
transform.position = player.transform.position + offset;
}
}
Unparent WeaponSpawnPoint from the sphere, and set its location and Y rotation using a script?
I was going to suggest this, but it wouldn’t change the WeaponSpawnPoint Z axis at any point, so it would effectively be the same as using Vector3.forward.
Unless im missunderstanding the original question, what i suggested should work fine… If you clone the spheres World Y rotation and set it to the WeaponSpawnPoints Y rotation its Z would be facing foward relative to the sphere. And then use transform.forward on the WeaponSpawnPoint.
But again it may not work in practice - i am unable to test it at the moment.
public Rigidbody attachedObj;
void FixedUpdate()
{
transform.position = attachedObj.position;
transform.rotation = Quaternion.LookRotation(attachedObj.velocity);
}
Put together quickly to test, but this seems to work like I think you want it to work.
Add that to your separated Weapon Spawn object and it should point in the direction that the ball is rolling. You can spawn in transform.forwards direction then.
I may have massively over-thought this now, though!
It worked like I wanted, but brought up an additional issue. I have a PlayerController script. Inside this script is the ability for my character to jump. When I am jumping up, or falling down, the shots don’t shoot correctly and fire up and down.
For reference this is my script…
PlayerController
using UnityEngine;
using System.Collections;
public class PlayerController : MonoBehaviour
{
//Variables
public GameObject player;
public float speed;
private float value = 0;
private float moveHorizontal;
private float moveVertical;
bool spaceKeyDown = false;
bool isGrounded = false;
void OnCollisionEnter (Collision col)//Test if player is on the ground
{
if(col.gameObject.name == "Ground 1")
{
isGrounded = true;
}
}
void OnCollisionExit (Collision col)//Test if player is off the ground
{
if(col.gameObject.name == "Ground 1")
{
isGrounded = false;
}
}
void Update ()//For Input Data
{
moveHorizontal = Input.GetAxis ("Horizontal");
moveVertical = Input.GetAxis ("Vertical");
if(Input.GetButtonDown("Jump"))
{
spaceKeyDown = true;
//Debug.Log("Space Key Pressed. Frame: " + Time.frameCount);
}
}
void FixedUpdate ()//For Physics Data
{
JumpData ();
Vector3 movement = new Vector3 (moveHorizontal, value/speed , moveVertical);
rigidbody.AddForce(movement * speed * Time.deltaTime);//Value (jump height) is not effected by speed.
value = 0;//Make sure value is 0 after jump sequence.
}
void JumpData()
{
if (isGrounded == true)
{
if (spaceKeyDown == true)
{
spaceKeyDown = false;
value = 9.8f * 1500f;
}
else {value = 0;}
}
else {value = 0;}
spaceKeyDown = false;
}
}
It should work if you zero out the rigidbody’s y velocity when assigning it to the Weapon Spawn object.
I cant figure out how to do that, when I try it brings up an error saying
Assets/Scripts/shootBullet.cs(22,39): error CS1612: Cannot modify a value type return value of `UnityEngine.Rigidbody.velocity’. Consider storing the value in a temporary variable.
Also I found out that when I am running the code (before any edits), before I even move my player I get the following repeating error…
Look rotation viewing vector is zero
UnityEngine.Quaternion:LookRotation(Vector3)
shootBullet:FixedUpdate() (at Assets/Scripts/shootBullet.cs:23)
Try this in place of what I suggested before:
public Rigidbody attachedObj;
void FixedUpdate()
{
transform.position = attachedObj.position;
Vector3 newRot = new Vector3(attachedObj.velocity.x, 0f, attachedObj.velocity.z);
transform.rotation = Quaternion.LookRotation(newRot);
}
I’ve not tested it, but I think that will work. You’re basically telling it to use the rigidbody velocity, but rigging its vertical velocity to zero.
The ‘Look rotation viewing vector is zero’ message is just because Quaternion.LookRotation takes a direction and converts that direction to a rotation, which it obviously can’t do with Vector.zero. I’m not aware of it causing any issues, but you can put the LookRotation line in an if statement that checks if the rotation is equal to Vector.zero first if you want to remove it.
My bullet is shooting how it is supposed to. That error message is annoying though. How do I go about removing it. I’m new to the LookRotation.
You just need to add something like:
void FixedUpdate()
{
transform.position = attachedObj.position;
Vector3 newRot = new Vector3(attachedObj.velocity.x, 0f, attachedObj.velocity.z);
if (newRot != Vector.zero)
transform.rotation = Quaternion.LookRotation(newRot);
}
Thanks, everything is working perfectly now. Here is my final code.
using UnityEngine;
using System.Collections;
public class shootBullet : MonoBehaviour
{
public GameObject projectile;
public Rigidbody attachedObj;
void Update ()
{
if (Input.GetButtonDown("Fire1"))//left control and left mouse button
{
// instantiate a prefab, at the position of the object that has this script, with the default rotation (gameobject rotation ignored)
Instantiate(projectile, transform.position, transform.rotation);
}
}
void FixedUpdate()
{
transform.position = attachedObj.position;
Vector3 newRot = new Vector3(attachedObj.velocity.x, 0f, attachedObj.velocity.z);
if (newRot != Vector3.zero)
transform.rotation = Quaternion.LookRotation(newRot);
}
}