Why my code fires bullet at random positions? - unity3d

I see that the bullets are being fired at random positions and not actually in forward direction of the camera. What's wrong here and how should I fix it?
So I am using pooling and each time the bullet is enabled this code is run:
private void OnEnable()
{
transform.position = Camera.main.transform.position;
transform.rotation =Quaternion.identity;
GetComponent<Rigidbody>().AddForce((Camera.main.transform.forward + new Vector3(0, 0, 0)) * 5000);
Invoke("Destroy", 1.5f);
}
I have also changed it to the below code but even the second one doesn't work.
private void OnEnable()
{
Rigidbody rb = GetComponent<Rigidbody>();
rb.position = Camera.main.transform.position;
rb.rotation = Quaternion.identity;
rb.AddForce((Camera.main.transform.forward + new Vector3(0, 0, 0)) * 5000);
Invoke("Destroy", 1.5f);
}

First of all make sure the code works with out pooling. Secondly disable the collider component on the bullet (they might be colliding with themselves).
I've quickly tried this on my machine and this is the result I get.
using UnityEngine;
public class BulletController : MonoBehaviour
{
[SerializeField]
GameObject bulletPrefab;
void Update()
{
GameObject bullet = Object.Instantiate(bulletPrefab);
Rigidbody body = bullet.GetComponent<Rigidbody>();
body.position = Camera.main.transform.position;
body.AddForce(Camera.main.transform.forward * 75f, ForceMode.Impulse);
}
}

Here is the code I use with direction, position and velocity variables.
void Inception::shootGeode(std::string typeGeode, const btVector3& direction) {
logStderr(VERBOSE, "MESSAGE: Shooting geode(s)...\n");
std::shared_ptr<Geode> geode;
glm::vec3 cameraPosition = m_camera->getPosition();
btVector3 position = glm2bullet(cameraPosition + 3.0f * glm::normalize(m_camera->getTarget() - cameraPosition));
if (typeGeode == "cube")
geode = m_objectFactory->createCube("cube", new btBoxShape(btVector3(1.0f, 1.0f, 1.0f)), position, "dice");
if (typeGeode == "sphere")
geode = m_objectFactory->createSphere("sphere", new btBoxShape(btVector3(1.0f, 1.0f, 1.0f)), position);
btVector3 velocity = direction;
velocity.normalize();
velocity *= 25.0f;
geode->getRigidBody()->setLinearVelocity(velocity);
}

Related

Why is my Controller drifting with Slerp?

I've been working on this Controller, where I walk around a small planet. I'm using Quaternion.Slerp, and when I'm at certain points on the planet, the controller slowly drifts, rotating around the Y axis. My thought is that it is holding a value based on my starting position, and so when I move to different points, the Slerp function is trying to spin me toward that location? I've tried messing around with the script, moving different portions to their own custom methods to pinpoint the issue, but I'm a bit lost at this point. Any help would be appreciated!
I think the issue is going to be somewhere in the bottom two methods NewRotation, or RunWalkStand.
`
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerController : MonoBehaviour
{
[SerializeField] private LayerMask _groundMask;
[SerializeField] private Transform _groundCheck;
[SerializeField] private Transform cam;
public float jumpCooldown = 1f;
public float groundCheckRadius = 0.3f;
private float speed = 8;
private float runSpeed = 2;
private float turnSpeed = 800f;
private float jumpForce = 500f;
private Rigidbody rb;
private Vector3 direction;
private GravityBody _gravityBody;
private Animator playerAnimator;
private GameObject planetRecall;
void Start()
{
_gravityBody = transform.GetComponent<GravityBody>();
playerAnimator = GetComponent<Animator>();
planetRecall = GameObject.FindGameObjectWithTag("Planet Recall");
}
void Update()
{
bool isCloseToGround = Physics.CheckSphere(_groundCheck.position, groundCheckRadius, _groundMask);
NewRotation();
if (Input.GetKeyDown(KeyCode.Space) && isCloseToGround)
{
Jump();
}
}
void FixedUpdate()
{
RunWalkStand();
}
private void OnCollisionEnter(Collision collision)
{
if(collision.gameObject == planetRecall)
{
playerAnimator.SetBool("Grounded", true);
}
}
private void Jump()
{
rb.AddForce(-_gravityBody.GravityDirection * jumpForce, ForceMode.Impulse);
playerAnimator.SetTrigger("Fly_trig");
playerAnimator.SetBool("Grounded", false);
}
private void NewRotation()
{
rb = transform.GetComponent<Rigidbody>();
Vector3 mouseRotationY = new Vector3(0f, Input.GetAxisRaw("Mouse X"), 0f);
Quaternion rightDirection = Quaternion.Euler(0f, mouseRotationY.y * (turnSpeed * Time.deltaTime), 0f).normalized;
Quaternion newRotation = Quaternion.Slerp(rb.rotation, rb.rotation * rightDirection, Time.deltaTime * 1000f);
rb.MoveRotation(newRotation);
//Move Side to Side
Vector3 sideToSide = transform.right * Input.GetAxisRaw("Horizontal");
rb.MovePosition(rb.position + sideToSide * (speed * Time.deltaTime));
}
private void RunWalkStand()
{
direction = new Vector3(0f, 0f, Input.GetAxisRaw("Vertical")).normalized;
Vector3 forwardDirection = transform.forward * direction.z;
bool isRunning = direction.magnitude > 0.1f;
//Walking
if (isRunning && !Input.GetKey(KeyCode.LeftShift))
{
rb.MovePosition(rb.position + forwardDirection * (speed * Time.deltaTime));
playerAnimator.SetFloat("Speed_f", 0.5f);
}
//Running
else if(isRunning && Input.GetKey(KeyCode.LeftShift))
{
rb.MovePosition(rb.position + forwardDirection * (speed * runSpeed * Time.deltaTime));
playerAnimator.SetFloat("Speed_f", 1f);
}
//Standing
else if(isRunning == false)
{
playerAnimator.SetFloat("Speed_f", 0f);
}
}
}
`
it might be because a slerp is not a lineair line so its velocity is less when you are close to the endpoint maybe try Quaternion.RotateTowards.
I "Mostly" solved this issue, and it's an unexpected solution. The drift was solved by freezing rotation on the player in the inspector (Still don't know what was causing the player to spin though) However this caused extra jitter. I found two issues.
If I've selected ANY game object in the hierarchy, and play the game, the game is jittery, but if I click off of it onto nothing, the game runs smoother (Not completely better, but much smoother).
I'm using a Gravity script for the planet that applies gravity to the player's Rigidbody, and I believe with multiple things acting on the RB at the same time, it causes jitter. I'm thinkin of trying to greatly simplify the project, but putting the different methods from the scripts into different Update methods helps a good bit depending on the combination (Not as simple as Physics movement in FixedUpdate and camera in LateUpdate unfortunately).

Raycast 2D ricochet in Unity?

I'm new to Raycasting so I might be going about this in a bad way, but I would to send a raycast outward to direction a gameobject is facing, bounce off the first object it hits and go a short distance before disappearing.
As far as I can tell there is no built in function for reflecting raycasts in Unity, so I have been trying to generate a another raycast where the first one hits but my luck hasn't been going well. Here's what I have so far:
public Gameobject firePoint; // I have an object attached to my main object that I use as a point of origin
void DrawLazer()
{
Vector2 origin = new Vector2(firePoint.transform.position.x, firePoint.transform.position.y);
Vector2 direction = transform.TransformDirection(Vector2.up);
RaycastHit2D hit = Physics2D.Raycast(origin, direction, 10f);
Debug.DrawLine(origin, direction *10000, Color.black);
if (hit)
{
Debug.Log("Hit: " + hit.collider.name);
var whatWeHit = new Vector2(hit.transform.position.x, hit.transform.position.y);
var offset = whatWeHit + hit.point;
offset.y = 0;
RaycastHit2D hit2 = Physics2D.Raycast(offset, Vector3.Reflect(direction, hit.normal) * -10000);
if (hit2)
{
Debug.DrawLine(offset, -Vector3.Reflect(direction, hit.normal) * -10000);
}
}
}
I call DrawLaxer(); in update.
This current script is sort of able to generate a 2nd raycast, however as you can see, the first raycast still does not stop when it hits something, and more importantly while this solution works well when it hits a flat object on a horizontal plane. But if it hits on object on a vertical or diagonal plane it applys several calculations to the wrong axis:
Any help would be greatly appreciated.
Here is a complete example monobehavior that uses Vector2.Reflect and SphereCast.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ReflectionExample : MonoBehaviour
{
public GameObject firePoint;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
DrawPredictionDisplay();
}
private void DrawPredictionDisplay()
{
Vector2 origin = firePoint.transform.position; //unity has a built in type converter that converts vector3 to vector2 by dropping the z component
Vector2 direction = firePoint.transform.up;
float radius = 1.0f;
RaycastHit2D distanceCheck = Physics2D.Raycast(origin, direction);
RaycastHit2D hit = Physics2D.CircleCast(origin, radius, direction);
Debug.DrawLine(origin, direction * 10000, UnityEngine.Color.black);
DrawCircle(origin, 1.0f, UnityEngine.Color.black);
if (hit)
{
origin = hit.point + (hit.normal * radius);
direction = Vector2.Reflect(direction, hit.normal);
hit = Physics2D.CircleCast(origin, radius, direction);
Debug.DrawLine(origin, direction * 10000, UnityEngine.Color.blue);
DrawCircle(origin, 1.0f, UnityEngine.Color.blue);
}
}
private void DrawCircle(Vector2 center, float radius, UnityEngine.Color color)
{
Vector2 prevPoint = new Vector2(Mathf.Sin(0f), Mathf.Cos(0f));
for (float t = 0.1f; t < 2 * Mathf.PI; t = t + 0.1f)
{
var nextPoint = new Vector2(Mathf.Sin(t), Mathf.Cos(t));
Debug.DrawLine(center + prevPoint, center + nextPoint, color);
prevPoint = nextPoint;
}
}
}

Gun Script Creates Bullet But Bullet Travel in All Different Directions

I am trying to create a gun script however after the bullet prefab instantiates, it doesn't travel in the correct direction(Straight). The function used to create bullets in Shoot() which is called when the Update loop gets the input from GetMouseButton(0).
public class CharController : MonoBehaviour {
[SerializeField]
float moveSpeed = 4f;
public float aimSpeed;
Vector3 mousePos;
Vector3 forward, right;
public GameObject bulletSpawnPoint;
public GameObject bullet;
public float bullet_Speed;
public float fireRate;
void Start () {
forward = Camera.main.transform.forward;
forward.y = 0;
forward = Vector3.Normalize(forward);
right = Quaternion.Euler(new Vector3(0, 90, 0)) * forward;
}
void Update () {
if (Input.GetMouseButton(0))
{
transform.position += (-transform.position + mousePos).normalized * aimSpeed * Time.deltaTime;
transform.position = new Vector3(transform.position.x, 2.5f, transform.position.z);
Shoot();
}
}
void Shoot()
{
GameObject temp_Bullet_Handler;
temp_Bullet_Handler = Instantiate(bullet, bulletSpawnPoint.transform.position, bulletSpawnPoint.transform.rotation) as GameObject;
//temp_Bullet_Handler.transform.Rotate(Vector3.left * 90);
Rigidbody temp_Rigidbody;
temp_Rigidbody = temp_Bullet_Handler.GetComponent<Rigidbody>();
temp_Rigidbody.AddForce(Vector3.forward * Time.deltaTime * 10f);
Destroy(temp_Bullet_Handler, 10.0f);
}
}
If anyone has any information on what causes the bullets not to travel in a straight direction from the instantiation point, I would love to have your input.
Thanks in advance
Your Update moves the bullet in a direction which is based on it's position. Change that into a direction vector, like your "forward" instead of transform.position.

Unity: Diagonal movement issue

I have a test 2D game where my player moved from left to right and when he reached the end of the screen it would just transform on the other side. I had a change of heart and made my player move diagonally. It did work, but I have no idea how to make the player stop when it hits the end of the screen. I don't want it to transform on the other side, but rather just stop. So far all my results are either some glitching on the edges or not stopping at all. I have provided my PlayerController script. Right now my player moves diagonally and he will just continue after the edge of the screen. If anyone can assist me I would be very grateful. I never thought I will deal with diagonal movement, but I really want to learn how to do it.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class PlayerController : MonoBehaviour {
public float speed = 7;
public float speedy = 7;
public event System.Action OnPlayerDeath;
float screenHalfWidthInWorldUnits;
Rigidbody2D rb;
void Start () {
rb = GetComponent<Rigidbody2D>();
float halfPlayerWidth = transform.localScale.x / 2f;
screenHalfWidthInWorldUnits = Camera.main.aspect * Camera.main.orthographicSize;
}
void Update()
{
float inputX = Input.GetAxisRaw("Horizontal");
float velocity = inputX * speed;
transform.Translate(Vector2.right * velocity * Time.deltaTime);
}
public void MoveRight()
{
rb.velocity = new Vector2(speed, speedy);
}
public void MoveLeft()
{
rb.velocity = new Vector2(-speed, -speedy);
}
public void Stop()
{
rb.velocity = Vector2.zero;
}
void OnTriggerEnter2D(Collider2D triggerCollider)
{
if (triggerCollider.tag =="Box")
{
if (OnPlayerDeath != null)
{
OnPlayerDeath();
}
Destroy(gameObject);
}
}
}
You can check if the player is at what you define as the border of the map.
If you check this for the x and y axis respectively, you can then lock his x or y axis to the border and not further.
Here is an example of a script I made earlier that does that.
If I understand you correctly you would like to be able to move diagonally. In my sample script below you can move both straight and diagonally, you can also warp between the edges or stop at the edges as you spoke of wanting to.
This script is a bit more advanced than what you need probably, so let me know if something about it confuses you.
Please note that if you set the boolean _ShouldWarp to false he will stop at the border, otherwise he will warp from edge to edge of the map.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Player : MonoBehaviour
{
public float _Speed = 5f;
public WorldBounds _WorldBounds;
public bool _ShouldWarp; //If _ShouldWarp is false, will block players movement instead.
void Update()
{
Move();
WarpIfAtBoundary();
}
void Move()
{
float horizontal = Input.GetAxisRaw("Horizontal");
float vertical = Input.GetAxisRaw("Vertical");
transform.Translate(Vector3.right * Time.deltaTime * _Speed * horizontal);
transform.Translate(Vector3.up * Time.deltaTime * _Speed * vertical);
}
void WarpIfAtBoundary()
{
//X Axis
//If player is at positive X boundary
if (transform.position.x > (_WorldBounds.xPlus + _WorldBounds.xBuffer))
{
if (_ShouldWarp) //Teleport/warp player is set to enabled
{
transform.position = new Vector3(_WorldBounds.xMinus, transform.position.y, transform.position.z);
}
else //Otherwise keep player in border position
{
transform.position = new Vector3(_WorldBounds.xPlus + _WorldBounds.xBuffer, transform.position.y, transform.position.z);
}
}
//Else if player is at negative X boundary
else if (transform.position.x < (_WorldBounds.xMinus - _WorldBounds.xBuffer))
{
if (_ShouldWarp)//Teleport/warp player is set to enabled
{
transform.position = new Vector3(_WorldBounds.xPlus, transform.position.y, transform.position.z);
}
else //Otherwise keep player in border position
{
transform.position = new Vector3(_WorldBounds.xMinus - _WorldBounds.xBuffer, transform.position.y, transform.position.z);
}
}
//Y Axis
//If player is at positive Y boundary
if (transform.position.y > (_WorldBounds.yPlus + _WorldBounds.yBuffer))
{
if (_ShouldWarp)//Teleport/warp player is set to enabled
{
transform.position = new Vector3(transform.position.x, _WorldBounds.yMinus, transform.position.z);
}
else //Otherwise keep player in border position
{
transform.position = new Vector3(transform.position.x, _WorldBounds.yPlus + _WorldBounds.yBuffer, transform.position.z);
}
}
//Else if player is at negative Y boundary
else if (transform.position.y < (_WorldBounds.yMinus - _WorldBounds.yBuffer))
{
if (_ShouldWarp)//Teleport/warp player is set to enabled
{
transform.position = new Vector3(transform.position.x, _WorldBounds.yPlus, transform.position.z);
}
else //Otherwise keep player in border position
{
transform.position = new Vector3(transform.position.x, _WorldBounds.yMinus - _WorldBounds.yBuffer, transform.position.z);
}
}
}
}
//Set as serializable so it displays correctly in Unity's inspector window.
[System.Serializable]
public class WorldBounds
{
[Header("Bounds")]
public float xMinus = -9.4f;
public float xPlus = 9.4f;
public float yMinus = -9.4f;
public float yPlus = 9.4f;
[Header("BufferZone")]
public float xBuffer = 1f;
public float yBuffer = 1f;
}
EDIT:
With your additions will I be able to assign the movement to my two buttons. One is up and right and the other is down and left.
void Move()
{
float horizontal = Input.GetAxisRaw("Horizontal");
transform.Translate(Vector3.right * Time.deltaTime * _Speed * horizontal);
transform.Translate(Vector3.up * Time.deltaTime * _Speed * horizontal);
}
This should work to move diagonally left and down as well as up and right.
The change i made is to use the Horizontal input for both X and Y movement.
I don't need the warp. Just to step at the defined borders
You can set the Warp boolean to false or remove the warp parts from the code then :-), should work.

Unity networking mouse position

I was following this tutorial on the Unity docs, but wanted to change my version to fire towards the mouse position. The host works fine but when running the client the bullets fire towards the mouse position relative to the host client (usually just off to the side).
Here is my code as is:
public class PlayerMove : NetworkBehaviour {
public GameObject bulletPrefab;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
if (!isLocalPlayer)
return;
var x = Input.GetAxis("Horizontal") * 0.1f;
var z = Input.GetAxis("Vertical") * 0.1f;
transform.Translate(x, 0, z);
if (Input.GetMouseButtonDown(0))
{
CmdFire();
}
}
public override void OnStartLocalPlayer()
{
GetComponent<MeshRenderer>().material.color = Color.red;
}
[Command]
void CmdFire()
{
// create the bullet object from the bullet prefab
// make the bullet move away in front of the player
Vector2 target = Camera.main.ScreenToWorldPoint(new Vector2(Input.mousePosition.x, Input.mousePosition.y));
Vector2 myPos = new Vector2(transform.position.x, transform.position.y + 1);
Vector2 direction = target - myPos;
GameObject projectile = (GameObject)Instantiate(bulletPrefab, myPos, transform.rotation);
projectile.GetComponent<Rigidbody2D>().velocity = direction * 4f;
// spawn the bullet on the clients
NetworkServer.Spawn(projectile);
// make bullet disappear after 2 seconds
Destroy(projectile, 2.0f);
}
}
I have also tried to move the "velocity = direction" to a new bullet script but it always performs the same.
How can I use a 'local' mouse position, if that's the solution here?
You need to synchronize the direction, rotation and position from your client on all the other clients if you want them to see what client sees.
Also - [Command] only runs on the server, you probably want to spawn the bullet on all the clients connected to the server so you should run [ClientRpc] from your [Command]
public class PlayerMove : NetworkBehaviour {
public GameObject bulletPrefab;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
if (!isLocalPlayer)
return;
var x = Input.GetAxis("Horizontal") * 0.1f;
var z = Input.GetAxis("Vertical") * 0.1f;
transform.Translate(x, 0, z);
if (Input.GetMouseButtonDown(0))
{
Fire();
}
}
public override void OnStartLocalPlayer()
{
GetComponent<MeshRenderer>().material.color = Color.red;
}
void Fire()
{
Vector2 _target = Camera.main.ScreenToWorldPoint(new Vector2(Input.mousePosition.x, Input.mousePosition.y));
Vector2 _myPos = new Vector2(transform.position.x, transform.position.y + 1);
Vector2 _direction = _target - _myPos;
Vector3 _rot = transform.rotation.eulerAngles;
CmdFire(_myPos, _myDir, _rot);
}
[Command]
void CmdFire(Vector2 _myPos, Vector2 _myDir, Vector3 _rot)
{
RpcFire(_myPos, _myDir, _rot);
}
[ClientRpc]
void RpcFire(Vector2 _myPos, Vector2 _myDir, Vector3 _rot)
{
// create the bullet object from the bullet prefab
// make the bullet move away in front of the player
GameObject _projectile = (GameObject)Instantiate(bulletPrefab, _myPos, Quaternion.Euler(_rot);
_projectile.GetComponent<Rigidbody2D>().velocity = direction * 4f;
// spawn the bullet on the clients
NetworkServer.Spawn(_projectile);
// make bullet disappear after 2 seconds
Destroy(_projectile, 2.0f);
}
}