Video showing the host and client side perspectives
I am using rigidbodies on the balls, which are not instantiated, and they are picked up via script¹, the host can access everything, but the client cannot access the rigidbodies, but supposedly can access the script (video explains the process). I am relatively new to Netcode, so if it's something obvious, talk to me as if I am a 2 year old, and, preferably, point me in the right direction, or unity doc.
¹
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GetBall : MonoBehaviour
{
[SerializeField] private Camera cam;
[SerializeField] private float distanceGrab;
[SerializeField] private Transform ballHold;
[SerializeField] private Transform ballThrow;
[SerializeField] private GameObject ballGet;
[SerializeField] private GameObject _ball;
[SerializeField] private bool isHoldingBall;
[SerializeField] private float charge;
[SerializeField] private Rigidbody rb;
[SerializeField] private RectTransform slider;
[SerializeField] private GameObject pickUpDot;
[SerializeField] private GameObject reticle;
void Update()
{
if(_ball != null)
{
_ball.transform.position = ballHold.position;
_ball.transform.rotation = new Quaternion(transform.rotation.x, transform.rotation.y, transform.rotation.z, transform.rotation.w);
}
if(isHoldingBall == false)
{
GrabBall();
}
if(isHoldingBall == true)
{
ThrowBall();
}
}
void OnTriggerEnter(Collider ball)
{
}
void GrabBall()
{
ballGet.SetActive(true);
reticle.SetActive(false);
if(ballGet.transform.GetComponent<BallInSphere>().canPickUp == true)
{
pickUpDot.SetActive(true);
if(Input.GetButtonDown("Fire1"))
{
_ball = ballGet.transform.GetComponent<BallInSphere>().theBall;
rb = _ball.GetComponent<Rigidbody>();
rb.useGravity = false;
rb.isKinematic = true;
}
}
else if(ballGet.transform.GetComponent<BallInSphere>().canPickUp == false)
{
pickUpDot.SetActive(false);
}
if(_ball != null)
{
isHoldingBall = true;
}
}
void ThrowBall()
{
ballGet.SetActive(false);
pickUpDot.SetActive(false);
reticle.SetActive(true);
slider.sizeDelta = new Vector2(slider.transform.localScale.x * charge * 100f, 100f);
if(_ball != null)
{
if(Input.GetButton("Fire2"))
{
charge += 20f * Time.deltaTime;
if(charge >=10)
{
charge = 10;
}
}
if(!Input.GetButton("Fire2"))
{
charge -= 20f * Time.deltaTime;
if(charge <= 0)
{
charge = 0;
}
}
if(Input.GetButtonDown("Fire1") && charge > 0)
{
_ball.transform.GetComponent<I_Am_Ball>().canHit = true;
_ball.transform.position = ballThrow.position;
rb = _ball.GetComponent<Rigidbody>();
rb.useGravity = true;
rb.isKinematic = false;
rb.AddForce(cam.transform.forward * charge * 300);
isHoldingBall = false;
_ball = null;
rb = null;
charge = 0f;
slider.sizeDelta = new Vector2(0f, 100f);
}
}
}
}
I've tried adding the Network Rigidbody with Network Transform (All of my objects (players and balls) have the Network Object component attached to them), which didn't work. I have tried using my PlayerNetwork script, which makes the actual players move, but my players don't use rigidbodies and the balls do, so it didn't really help. I have tried my hand at RPC's, but really dont understand it. If that's what I need to use, then I'll gladly read through the doc on it, but if I can avoid it, that would be great too.
Thanks in advance.
Edit: After trying my hand at Rpc's I've realized that an Rpc is not the answer to my question. Although I cam across something called Client Side Predictions, which I am currently looking into. If I'm on the right track, or the wrong track, I'd be thankful for someone to let me know.
Related
I'm trying to create projection of the ship trajectory, but I think it is too resource expensive to be usable since the editor freezes after a couple of seconds.
The trajectory has to take into account a couple of things:
Player's velocity (and input)
Player being attracted by other planets. (I THINK this is included in the velocity vector).
I've tried moving expensive operations outside the function that is called at FixedUpdate, link GetComponent or move to scene, but it still freezes, a little less but freezes.
My best guess is that the physics simulation is too expensive to run on FixedUpdate, but I don't know if there is a better method to call it on.
Here is my current code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.SceneManagement;
public class Player : MonoBehaviour
{
...
[SerializeField] public Rigidbody playerRigidBody;
// Projection
private Scene _simulationScene;
private PhysicsScene _physicsScene;
[SerializeField]
private int _maxPhysicsFrameIterations = 10;
private GameObject _ghostObj;
[SerializeField]
private GameObject _markerPrefab;
private List<GameObject> _markersPool;
// Input Values
...
private Rigidbody _ghostRigidBody;
...
// Start is called before the first frame update
void Start()
{
playerRigidBody = GetComponent<Rigidbody>();
currentBoostAmount = maxBoostAmount;
// Projection
_markersPool = new List<GameObject>();
for (int i = 0; i < _maxPhysicsFrameIterations; i++)
{
GameObject marker = Instantiate(_markerPrefab);
_markersPool.Add(marker);
}
CreatePhysicsScene();
}
private void OnDisable()
{
Attractor.players.Remove(this);
Destroy(_ghostObj);
}
// Update is called once per frame
void FixedUpdate()
{
HandleBoosting();
HandleMovement();
if (thrust1D != 0 || upDown1D != 0 || strafe1D != 0 || roll1D != 0 || pitchYaw != Vector2.zero)
{
SimulateTrajectory();
}
}
void CreatePhysicsScene()
{
var scene = SceneManager.GetSceneByName("SimulationScene");
var isSimulatioSceneValid = scene.IsValid();
if (isSimulatioSceneValid)
{
_simulationScene = scene;
}
else
{
_simulationScene = SceneManager.CreateScene("SimulationScene", new CreateSceneParameters(LocalPhysicsMode.Physics3D));
}
_physicsScene = _simulationScene.GetPhysicsScene();
_ghostObj = Instantiate(this.gameObject, transform.position, transform.rotation);
_ghostObj.GetComponent<PlayerInput>().enabled = false;
_ghostObj.GetComponent<Renderer>().enabled = false;
_ghostRigidBody = _ghostObj.GetComponent<Rigidbody>();
SceneManager.MoveGameObjectToScene(_ghostObj, _simulationScene);
}
public void SimulateTrajectory()
{
Physics.autoSimulation = false;
_ghostObj.transform.position = transform.position;
_ghostRigidBody.velocity = playerRigidBody.velocity;
for (int i = 0; i < _maxPhysicsFrameIterations; i++)
{
_physicsScene.Simulate(i + 1 / _maxPhysicsFrameIterations);
_markersPool[i].transform.position = _ghostObj.transform.position;
}
Physics.autoSimulation = true;
}
}
I made a Gun Script (using YT videos) and a Bullethole GameObject should Instantiate at the Position the RayCast hits an Object. But it is always at 0 0 0. I tried many thing but non work.
GameObject bulletHoleClone = Instantiate(bulletHole, rayHit.point, Quaternion.Euler(0, 180, 0));
Destroy(bulletHoleClone, bulletHoleTime);
Whole Code:
using TMPro;
using UnityEngine;
public class GunScript : MonoBehaviour
{
//Gun Stats
public int damage;
public float timeBetweenShooting, spread, range, reloadTime, timeBetweenShots;
public int magazineSize, bulletsPerTap;
public bool allowHoldButton;
int bulletsLeft, bulletsShot;
private float normalSpread;
//bools
bool shooting, readyToShoot, reloading;
//Graphics
public CameraShake camShake;
public float camShakeStrengh, camShakeDuration;
public GameObject muzzleFlash, bulletHole;
public TextMeshProUGUI text;
public float muzzleFlashTime = 0.1f; //Will be deleted after there is an actual Effect and not a Box
public float bulletHoleTime = 3f;
//Refrences
public Camera fpsCam;
public Transform attackPoint;
private RaycastHit rayHit;
public LayerMask dafuqIsEnemey;
private Rigidbody rb;
private void Awake()
{
rb = GetComponent<Rigidbody>();
bulletsLeft = magazineSize;
readyToShoot = true;
normalSpread = spread;
}
private void Update()
{
MyInput();
//Set Text to BulletAmount
text.SetText(bulletsLeft + " / " + magazineSize);
}
private void MyInput()
{
if (allowHoldButton) shooting = Input.GetKey(KeyCode.Mouse0);
else shooting = Input.GetKeyDown(KeyCode.Mouse0);
if (Input.GetKeyDown(KeyCode.R) && bulletsLeft < magazineSize && !reloading) Reload();
//PewPew
if (readyToShoot && shooting && !reloading && bulletsLeft > 0)
{
bulletsShot = bulletsPerTap;
Shoot();
}
if (rb.velocity.magnitude > 0)
spread = normalSpread * 1.5f;
else spread = normalSpread;
if (Input.GetKey(KeyCode.LeftControl))
spread = normalSpread * 2f;
else spread = normalSpread;
}
private void Shoot()
{
readyToShoot = false;
//Bullets go BRRRRRRRRRR
float x = Random.Range(-spread, spread);
float y = Random.Range(-spread, spread);
//Calculate Direction with Spread
Vector3 direction = fpsCam.transform.forward + new Vector3(x, y, 0);
//Maybe Add that the Ray Isnt coming out of your Head. Instead make it apear on the GunTip
if (Physics.Raycast(fpsCam.transform.position, direction, out rayHit, range, dafuqIsEnemey))
{
Debug.Log(rayHit.collider.name);
if (rayHit.collider.CompareTag("Enemy"))
{
Debug.Log("Hit An Enemy");
//rayHit.collider.GetComponent<ShootingAi>().TakeDamage(damage);
}
}
//Shake Camera
camShake.Shake(camShakeDuration, camShakeStrengh);
//Graphics
GameObject bulletHoleClone = Instantiate(bulletHole, rayHit.point, Quaternion.Euler(0, 180, 0));
GameObject muzzleClone = Instantiate(muzzleFlash, attackPoint.position, Quaternion.identity);
Destroy(muzzleClone, muzzleFlashTime);
Destroy(bulletHoleClone, bulletHoleTime);
Debug.Log(rayHit.point);
bulletsLeft--;
bulletsShot--;
Invoke("ResetShot", timeBetweenShooting);
if (bulletsShot > 0 && bulletsLeft > 0)
Invoke("Shoot", timeBetweenShooting);
}
private void ResetShot()
{
readyToShoot = true;
}
private void Reload()
{
reloading = true;
Invoke("ReloadFinished", reloadTime);
}
private void ReloadFinished()
{
bulletsLeft = magazineSize;
reloading = false;
}
}
You're not hitting anything. You check to see if you hit something, and then spawn a bullet hole even if you didn't hit anything.
If you didn't hit anything, there isn't anywhere to put a bullet hole.
The problem is that you're using the raycast hit as a local variable, which allows you to use it outside of the scope where it's actually valid.
Delete rayHit from your class and define it in the raycast instead, like
out RaycastHit rayHit
then it should only be scoped for the if statement and you'll get a compiler error anywhere it's not valid.
This brings up a larger question about what do you do if it misses an enemy, or which layers you should be raycasting against. Personally I think you'd want to raycast against everything, then you can try to determine what you hit and what that means later. Only other really good alternative would be to raycast against enemies, then repeat that against objects if that misses, but it's a lot of overhead to keep spinning up the raycasting engine. You'd be better off firing against multiple layers and getting the layer off the collider.
PS too your spread is probably way, way too big. For values of spread, 0.01 is half a degree, 0.1 is five degrees, 1 is 45 degrees.
I found the Problem. Just tell the Gun that the Layer "Ground" is also an Enemy. Now it works. Thanks
Basically you need to Transform Direction e.g camTrans.TransformDirection. You can try this way
public class Raytest : MonoBehaviour
{
public Camera fpsCam;
public float maxDistance = 200f;
public bool update = true;
public GameObject objectToSpawn;
private void Update()
{
if(!update) return;
var camTrans = fpsCam.transform;
if (Physics.Raycast(camTrans.position, camTrans.TransformDirection(Vector3.forward), out var hit, maxDistance))
{
Debug.DrawRay(camTrans.position, camTrans.TransformDirection(Vector3.forward) * hit.distance, Color.red);
Debug.Log("Did Hit");
var clone = Instantiate(objectToSpawn, hit.point, Quaternion.Euler(0, 180, 0));
update = false;
}
else
{
Debug.DrawRay(camTrans.position, camTrans.TransformDirection(Vector3.forward) * 1000, Color.white);
Debug.Log("Did not Hit");
}
}
}
After hitting raycast
I'm working on an RTS game using mirror and ran into an issue.
I'm working on auto-attack function for the units.
Everything works for the host but not on clients.
Any help would be very much appreciated, I've been at it for a few days already.. Help!
Or at least point me in right direction here.
I will optimize this a bit better later on I just need to understand why it's not working on client. I've also noticed that Client will add itself to enemies list, it seems to be ignoring "hasAuthority" check
It's a bit of a write up so I'll try to make it as understandable as possible.
Unit gets instantiated and this is the script attached to it:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Mirror;
using System.Linq;
public class UnitFiring : NetworkBehaviour
{
[SerializeField] private Targeter targeter = null;
[SerializeField] private GameObject projectilePrefab = null;
[SerializeField] private Transform projectileSpawnPoint = null;
[SerializeField] private float fireRange = 10f;
[SerializeField] private float fireRate = 1f;
[SerializeField] private float rotationSpeed = 20f;
private float lastFireTime;
//auto attack
[SerializeField] private Transform ownAimAtPoint = null;
[SerializeField] private LayerMask layerMask;
[SerializeField] private int updateFunctionFrequency = 60; //in frames
[ServerCallback]
private void Update()
{
if (Time.frameCount % this.updateFunctionFrequency != 0) return;
//runs update every 60 frames
enemyColliders.RemoveAll(Collider => Collider == null);
//if enemyCollider List has GameObject that was destroyed or null, it removes it from the list.
Targetable target = targeter.GetTarget();
if(target == null)
{
ArrayDetect();
AttackUnit();
return;
}
if (!CanFireAtTarget()) { return; }
//look at target
Quaternion targetRotation =
Quaternion.LookRotation(target.transform.position - transform.position);
//Rotate
transform.rotation = Quaternion.RotateTowards
(transform.rotation, targetRotation, rotationSpeed * Time.deltaTime);
if(Time.time > (1 / fireRate) +lastFireTime)
{
Quaternion projectileRotation = Quaternion.LookRotation(
target.GetAimAtPoint().position - projectileSpawnPoint.position);
GameObject projectileInstance = Instantiate(
projectilePrefab, projectileSpawnPoint.position, projectileRotation);
NetworkServer.Spawn(projectileInstance, connectionToClient);
lastFireTime = Time.time;
}
}
[Client]
private bool CanFireAtTarget()
{
return (targeter.GetTarget().transform.position - transform.position).sqrMagnitude
<= fireRange * fireRange;
}
[SerializeField] private Collider[] colliderArray;
[SerializeField] private List<GameObject> enemyColliders;
Next is the ArrayDetect Function
Detect unit with Physics.OverlapSphere, make sure it has the authority and add it to enemyCollider List, I also added layerMask to make sure it's only checking for Units.
[Server]
private void ArrayDetect()
{
colliderArray = Physics.OverlapSphere(ownAimAtPoint.position, fireRange, layerMask);
foreach (Collider collider in colliderArray)
{
Debug.Log("we hit a", collider);
if (!collider.TryGetComponent<Targetable>(out Targetable potentialTarget))
{
return;
}
if (potentialTarget.hasAuthority)
{
return; //if the hit target is the players, do nothing
}
else
{
enemyColliders = enemyColliders.Distinct().ToList();
enemyColliders.Add(collider.gameObject);
Debug.Log("Found an enemy", potentialTarget);
}
}
}
Now AttackUnit Function, it will go thought enemyColliders List and set them as target to attack
[ServerCallback]
private void AttackUnit()
{
foreach (GameObject enemy in enemyColliders)
{
Debug.Log("We got confirmed enemy", enemy);
//GetComponent<Targeter>().CmdSetTarget(enemy);
targeter.CmdSetTarget(enemy);
//attack the enemy
}
}
This is Targetable Script, it simply returns AimAtPoint:
public class Targetable : NetworkBehaviour
{
[SerializeField] private Transform aimAtPoint = null;
public Transform GetAimAtPoint()
{
return aimAtPoint;
}
}
This is the CmdSetTarget Command in Targeter Script:
[Command]
public void CmdSetTarget(GameObject targetGameObject)
{
if(!targetGameObject.TryGetComponent<Targetable>(out Targetable newTarget)) { return; }
//if game object does not have a target, return
target = newTarget;
}
This is the error I get in the console, but only on the client Units, the host runs as it should:
Trying to send command for object without authority. Targeter.CmdSetTarget
Thanks for taking time to read this
I followed a tutorial on Youtube and it was from a man named Dani. I also followed another one from someone called Dave / GameDevelopment on how to pick up objects in Unity 3D. I have ran into a problem where if I pick up a weapon that was on the ground by default it does not work. My gun floats in the air. I believe the main reason for this (don't quote me on this) is that the Gun is some how not becoming a child of the camera, which is what supposed to happen. Please fix and thanks.
This is my pick up script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PickUpScript : MonoBehaviour
{
public GrappleGun gunScript;
public Rigidbody rb;
public BoxCollider coll;
public Transform player, gunContainer, fpsCam;
public float pickUpRange;
public float dropForwardForce, dropUpwardForce;
public bool equipped;
public static bool slotFull;
private void Start()
{
if(!equipped)
{
gunScript.enabled = false;
rb.isKinematic = false;
coll.isTrigger = false;
}
if (equipped)
{
gunScript.enabled = true;
rb.isKinematic = true;
coll.isTrigger = true;
slotFull = true;
}
}
private void Update()
{
//equipped and e is pressed
Vector3 distanceToPlayer = player.position - transform.position;
if (!equipped && distanceToPlayer.magnitude <= pickUpRange && Input.GetKeyDown(KeyCode.E) && !slotFull) PickUp();
//Drop if equipped and q is pressed
if (equipped && Input.GetKeyDown(KeyCode.Q)) Drop();
}
private void PickUp()
{
equipped = true;
slotFull = true;
transform.SetParent(gunContainer);
transform.localPosition = Vector3.zero;
transform.localRotation = Quaternion.Euler(Vector3.zero);
transform.localScale = Vector3.one;
//Enable rb and km and coll = trigger
rb.isKinematic = true;
coll.isTrigger = true;
//Enable Script
gunScript.enabled = true;
}
private void Drop()
{
equipped = false;
slotFull = false;
transform.SetParent(null);
//Enable rb and km and coll = trigger
rb.isKinematic = false;
coll.isTrigger = false;
//GunCarries momentum of player
rb.velocity = player.GetComponent<Rigidbody>().velocity;
//AddForce
rb.AddForce(fpsCam.forward * dropForwardForce, ForceMode.Impulse);
rb.AddForce(fpsCam.up * dropUpwardForce, ForceMode.Impulse);
//Enable Script
gunScript.enabled = false;
}
}
This is grapple hook script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GrappleGun : MonoBehaviour
{
private LineRenderer lr;
private Vector3 grapplePoint;
public LayerMask whatIsGrappable;
public Transform gunTip, camera, player;
private float maxDistance = 50f;
private SpringJoint joint;
void Awake()
{
lr = GetComponent<LineRenderer>();
}
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
if (Input.GetMouseButtonDown(0))
{
StartGrapple();
}
if (Input.GetMouseButtonUp(0))
{
StopGrapple();
}
}
void LateUpdate()
{
DrawRope();
}
void StartGrapple()
{
RaycastHit hit;
if (Physics.Raycast(camera.position, camera.forward, out hit, maxDistance, whatIsGrappable))
{
grapplePoint = hit.point;
joint = player.gameObject.AddComponent<SpringJoint>();
joint.autoConfigureConnectedAnchor = false;
joint.connectedAnchor = grapplePoint;
float distanceFromPoint = Vector3.Distance(player.position, grapplePoint);
//the distance
joint.maxDistance = distanceFromPoint * 0.8f;
joint.minDistance = distanceFromPoint * 0.25f;
joint.spring = 5f;
joint.damper = 0;
joint.massScale = 1f;
lr.positionCount = 2;
}
}
void DrawRope()
{
//if not grappling
if (!joint) return;
lr.SetPosition(0, gunTip.position);
lr.SetPosition(1, grapplePoint);
}
void StopGrapple()
{
lr.positionCount = 0;
Destroy(joint);
}
public bool IsGrappling()
{
return joint != null;
}
public Vector3 GetGrapplePoint()
{
return grapplePoint;
}
}
I think a better way for your situation would be to create an empty game object where you want the grappling gun to be held when it's picked up, and the empty game object parented to the camera from the scene. Then from the script, you can write these lines of code.
To reference the empty game object:
public transform gunHoldPosition;
And you can attach that from the scene view in Unity.
Then to make the gun snap to the position when it's held:
private void PickUp()
{
equipped = true;
slotFull = true;
transform.localPosition = Vector3.zero;
transform.localScale = Vector3.one;
//Enable rb and km and coll = trigger
rb.isKinematic = true;
coll.isTrigger = true;
//Enable Script
gunScript.enabled = true;
}
Now In the Update function, you have to write a little more:
private void Update()
{
//equipped and e is pressed
Vector3 distanceToPlayer = player.position - transform.position;
if (!equipped && distanceToPlayer.magnitude <= pickUpRange && Input.GetKeyDown(KeyCode.E) && !slotFull) PickUp();
//Drop if equipped and q is pressed
if (equipped && Input.GetKeyDown(KeyCode.Q)) Drop();
if (equipeed){
/* If this script is on the gun itself, then you just have to do transform.position, but if it's on some other object then you have to reference the gun that's being picked with the variable of 'public gameObject gun;' up and say gun.transform.position*/
transform.position = gunHoldPosition.position;
}
}
I'm not exactly sure why you have to do this in the Update function, but once I made a pickup script and the same thing happened to me, so I had to put the transform.postition in the Update Function. Hopefully this works for you if it doesn't reply to me and I will try something else.
Also sorry that I am late to answer my question even though I fixed it really fast. I was making the object with the script, aka a child of the model without actually making the model a child of thing.
Im working on a first person shooter. I have an aim function, which puts the pistol right in front of the camera, to make it look like your holding it in front of you. Im trying to make it so the pistol will also rotate with the camera on the Z axis, so that way the pistol wont stay still, because that looks odd and gets in the way. To do this, I tried this:
GPR.gun.transform.rotation = Quaternion.Euler(0, 0, plrCam.transform.rotation.z);, however this ends up rotating the gun very slightly around the z axis, and mainly rotating it around the y axis whenever I move my camera. I am a beginner programmer in Unity so please try to make answers more digestible to beginners so I can understand it. Here is my full script:
using System.Collections.Generic;
using UnityEngine;
public class PistolFire : MonoBehaviour
{
//Gun Properties
public float range = 50f;
public float damage = 10f;
//Sensitivity decrease for looking down the sights
public float downSights = 5f;
//Other vars
private playerGunControls playerGun;
private GameObject plrCam;
private Camera fpsCam;
private ParticleSystem muzzleFlash;
private GameObject impactEffect;
private bool aimed = false;
private GameObject aimPos;
private GunPickupRaycast GPR;
private GameObject handPos;
private GameObject Player;
// Start is called before the first frame update
void Start()
{
//Getting objects because gun is instantiated, so this is necessary
plrCam = GameObject.Find("Player Camera");
playerGun = plrCam.GetComponent<playerGunControls>();
fpsCam = plrCam.GetComponent<Camera>();
muzzleFlash = GetComponentInChildren<ParticleSystem>();
impactEffect = GameObject.Find("Impact Effect");
aimPos = GameObject.Find("aimPos");
GPR = plrCam.GetComponent<GunPickupRaycast>();
handPos = GameObject.Find("Hand Pos");
Player = GameObject.Find("Player");
}
// Update is called once per frame
void Update()
{
//Check for shoot button down
if (Input.GetButtonDown("Fire1"))
{
if (playerGun.holding == "Pistol")
{
Shoot();
}
}
//Check if aim button down
if (Input.GetButton("Fire2"))
{
if (playerGun.holding == "Pistol")
{
Aim();
}
}
//Check if no longer aiming to reset to normal
if (aimed == true && !(Input.GetButton("Fire2")))
{
Unaim();
}
}
void Shoot()
{
muzzleFlash.Play();
RaycastHit hit;
if(Physics.Raycast(plrCam.transform.position, plrCam.transform.forward, out hit, range))
{
Debug.Log(hit.transform.name);
Health health = hit.transform.GetComponent<Health>();
if (health != null)
{
health.TakeDamage(damage);
}
//Instantiate the Impact Effect
GameObject IE = Instantiate(impactEffect, hit.point, Quaternion.identity);
Destroy(IE, 1.5f);
}
}
void Aim()
{
aimed = true;
Debug.Log("Aiming");
GPR.gun.transform.position = aimPos.transform.position;
GPR.gun.transform.rotation = Quaternion.Euler(0, 0, plrCam.transform.rotation.z);
}
void Unaim()
{
GPR.gun.transform.position = handPos.transform.position;
Debug.Log("No longer aiming");
aimed = false;
}
}
I fixed my problem by making the gun a child of my camera instead of a child of my player.