1555 lines
51 KiB
C#
1555 lines
51 KiB
C#
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
using TMPro;
|
|
using UnityEngine.Networking;
|
|
using UnityEngine.PlayerLoop;
|
|
using UnityEngine.Rendering;
|
|
using UnityEngine.VFX;
|
|
|
|
public class Player : MonoBehaviour
|
|
{
|
|
public static Player Instance { get; private set; }
|
|
public float lastJumpTime;
|
|
public bool InSoloInstance = false;
|
|
public PlayerEntity PlayerEntity;
|
|
private int excludeLayers;
|
|
|
|
#region Player Score
|
|
|
|
[System.NonSerialized] public int score;
|
|
|
|
#endregion
|
|
|
|
#region Consts and Hashes
|
|
|
|
private const string ESCAPE_MENU = "EscapeMenu";
|
|
private const string INVENTORY = "Inventory";
|
|
private const string TALL_GRASS = "Tall_Grass";
|
|
private const string FOOTSTEP = "footstep";
|
|
private const string HEAD = "Head";
|
|
private const string BULLSEYE = "Bullseye";
|
|
private const string BODY = "Body";
|
|
private const string ARM = "Arm";
|
|
private const string LEG = "Leg";
|
|
private const string FOOT = "Foot";
|
|
private const string SHIELD = "Shield";
|
|
private const string SPARKS = "HitEffect_Sparks";
|
|
private const string BLOOD = "vfx_Blood";
|
|
private static readonly int animatorXAxis = Animator.StringToHash("xAxis");
|
|
private static readonly int animatorZAxis = Animator.StringToHash("zAxis");
|
|
private static readonly int animatorIsDead = Animator.StringToHash("Dead");
|
|
private static readonly int animatorVelocityMag = Animator.StringToHash("VelocityMagnitude");
|
|
private static readonly int animatorKnockback = Animator.StringToHash("Knockback");
|
|
private static readonly int animator3D_Shoot = Animator.StringToHash("3D_Shoot");
|
|
private static readonly int animator3D_Reload = Animator.StringToHash("3D_Reload");
|
|
private static readonly int animator3D_HeadHit = Animator.StringToHash("HeadHit");
|
|
private static readonly int animator3D_BodyHit = Animator.StringToHash("BodyHit");
|
|
private static readonly int visualEffect_Rate = Shader.PropertyToID("Rate");
|
|
|
|
#endregion
|
|
|
|
#region Player Controller Assignments
|
|
|
|
public FirstPersonController playerController;
|
|
internal InputHandler inputHandler;
|
|
public CameraController cameraController;
|
|
public bool canRun = true;
|
|
|
|
#endregion
|
|
|
|
#region Player Variables
|
|
|
|
private float distanceTravelled = 0f;
|
|
private readonly float maxFootstepDistance = 2.5f;
|
|
public Camera thirdPersonCamera;
|
|
[System.NonSerialized] public bool isFirstPerson = true;
|
|
private Vector3 oldPosition;
|
|
public bool IsMoving = false;
|
|
public bool isBeingKnockedBack;
|
|
private Vector2 knockbackRef;
|
|
public bool CanJump = true;
|
|
public float runEnergy = 10.0f;
|
|
|
|
public float speedMultiplier = 1.0f;
|
|
|
|
#endregion
|
|
|
|
#region Weapon Controller Variables
|
|
|
|
private Weapon weaponData;
|
|
public WeaponController CurrentWeapon;
|
|
private Animator weaponAnim;
|
|
[System.NonSerialized] public bool hasFiredWeapon = false;
|
|
[System.NonSerialized] public bool shootButton;
|
|
[System.NonSerialized] public bool RunButtonPressed;
|
|
|
|
//Allows any script to restrict the player from running by incrementing and decrementing this value.If the value is 0, no script is locking the player's run input, and the player can therefore run.
|
|
[System.NonSerialized] public byte RunInputLockCount;
|
|
[System.NonSerialized] public bool IsAiming = false;
|
|
[System.NonSerialized] public bool CanAim = false;
|
|
private bool canShoot = false;
|
|
private bool isShootingBurstWeapon;
|
|
|
|
#endregion
|
|
|
|
#region Melee Weapon Variables
|
|
|
|
#endregion
|
|
|
|
#region Grass Properties
|
|
|
|
public ShaderInteractor grassShaderInteractor;
|
|
public GrassComputeScript[] grassScript;
|
|
private bool inTallGrass = false;
|
|
|
|
#endregion
|
|
|
|
private void Awake()
|
|
{
|
|
Instance = this;
|
|
|
|
Transform pcanvas = transform.Find("Canvas");
|
|
playerNameTextMesh = pcanvas.Find("CanvasContainer/Name").GetComponent<TextMeshProUGUI>();
|
|
ChatBubble = pcanvas.Find("CanvasContainer/ChatBubbleContainer/ChatBubble").GetComponent<ChatBubble>();
|
|
|
|
GameObject playerHealthBarGO = GameObject.Find("HealthBar");
|
|
playerHealthBarGO.gameObject.SetActive(true);
|
|
playerHealthBar = playerHealthBarGO.GetComponent<PlayerHealthBar>();
|
|
|
|
gameObject.AddComponent<AudioSource>();
|
|
|
|
PlayerEntity = GetComponent<PlayerEntity>();
|
|
|
|
playerController = GetComponent<FirstPersonController>();
|
|
cameraController = GetComponentInChildren<CameraController>();
|
|
inputHandler = GetComponent<InputHandler>();
|
|
|
|
grassShaderInteractor = GetComponent<ShaderInteractor>();
|
|
|
|
AddCameraShakerComponent();
|
|
|
|
Transform playerThirdPersonCamTransform;
|
|
playerThirdPersonCamTransform = transform.Find("ThirdPerson_Camera");
|
|
thirdPersonCamera = playerThirdPersonCamTransform.GetComponent<Camera>();
|
|
thirdPersonCamera.gameObject.SetActive(false);
|
|
|
|
excludeLayers = LayerMask.GetMask("PlayerProjectile") | LayerMask.GetMask("BlockPlayer");
|
|
}
|
|
|
|
private void AddCameraShakerComponent()
|
|
{
|
|
GameObject firstPersonCamTransform = transform.Find("FirstPersonCamera_Holder").gameObject;
|
|
EZCameraShake.CameraShaker camShake = firstPersonCamTransform.AddComponent<EZCameraShake.CameraShaker>();
|
|
camShake.DefaultPosInfluence = new Vector3(0.15f, 0.15f, 0.15f);
|
|
camShake.DefaultRotInfluence = new Vector3(1.0f, 1.0f, 1.0f);
|
|
}
|
|
|
|
void Start()
|
|
{
|
|
audioManager = GameObject.Find("AudioManager");
|
|
transform.localScale = new Vector3(1, 1, 1);
|
|
transform.position = new Vector3(55, 10, 63);
|
|
animator = GetComponent<Animator>();
|
|
|
|
grassScript = FindObjectsOfType<GrassComputeScript>();
|
|
for (int i = 0; i < grassScript.Length; i++)
|
|
{
|
|
grassScript[i].AssignCamera(cameraController.playerCam);
|
|
grassScript[i].AssignInteractionAffector(grassShaderInteractor);
|
|
|
|
if (grassScript[i].castShadow != UnityEngine.Rendering.ShadowCastingMode.Off)
|
|
{
|
|
grassScript[i].castShadow = UnityEngine.Rendering.ShadowCastingMode.Off;
|
|
}
|
|
}
|
|
|
|
|
|
//Set true / false if you require to see player model for main player or not.
|
|
OnlyCastPlayerShadows(true);
|
|
|
|
IsAiming = false;
|
|
CanAim = true;
|
|
|
|
//reset shot timer
|
|
lastShotTime = Time.time;
|
|
|
|
this.gameObject.layer = LayerMask.NameToLayer("Player"); //used to be ignore raycast
|
|
|
|
transform.position = new Vector3(0, 0, 0);
|
|
playerRights = Client.Instance.playerRights;
|
|
audioVolume = PlayerPrefs.GetFloat("audioVolume");
|
|
|
|
//add snow effect
|
|
// GameObject snow = Resources.Load<GameObject>("gfx/snow");
|
|
// snow = Instantiate(snow);
|
|
// snow.transform.parent = this.transform;
|
|
|
|
lastReload = Time.time;
|
|
|
|
//remove canvas from main player
|
|
transform.Find("Canvas").gameObject.SetActive(false);
|
|
InitWeaponSystem();
|
|
}
|
|
|
|
public void OnlyCastPlayerShadows(bool disablePlayerRenderer, string uiLayer = "PlayerUI")
|
|
{
|
|
SkinnedMeshRenderer[] playerRenderers = GetComponentsInChildren<SkinnedMeshRenderer>();
|
|
for (int i = 0; i < playerRenderers.Length; i++)
|
|
{
|
|
if (playerRenderers[i].name.Contains("Character_"))
|
|
{
|
|
playerRenderers[i].gameObject.layer = LayerMask.NameToLayer(uiLayer);
|
|
playerRenderers[i].shadowCastingMode = disablePlayerRenderer
|
|
? UnityEngine.Rendering.ShadowCastingMode.ShadowsOnly
|
|
: UnityEngine.Rendering.ShadowCastingMode.On;
|
|
playerRenderers[i].updateWhenOffscreen = disablePlayerRenderer;
|
|
}
|
|
}
|
|
}
|
|
|
|
public InputHandler GetInputHandler() => inputHandler;
|
|
|
|
private void InitWeaponSystem()
|
|
{
|
|
weaponSlot = transform.Find("Root/Hips/Spine_01/Spine_02/Spine_03/Clavicle_R/Shoulder_R/Elbow_R/Hand_R/Weapon")
|
|
.gameObject;
|
|
cameraWeaponSlot = GameObject
|
|
.Find(
|
|
"FirstPersonCamera_Holder/CameraController/Camera_Pivot/FirstPerson_Camera/WeaponCam/WeaponPositioner/WeaponSlot")
|
|
.gameObject;
|
|
|
|
|
|
|
|
|
|
//firstPerson
|
|
foreach (Transform weapon in cameraWeaponSlot.transform)
|
|
{
|
|
weapon.gameObject.SetActive(false);
|
|
firstPersonWeaponList.Add(weapon.gameObject);
|
|
}
|
|
|
|
foreach (GameObject weaponObj in firstPersonWeaponList)
|
|
{
|
|
firstPersonWeaponDictionary.Add(int.Parse(weaponObj.name), weaponObj);
|
|
}
|
|
|
|
//third person
|
|
foreach (Transform weapon in weaponSlot.transform)
|
|
{
|
|
thirdPersonWeaponList.Add(weapon.gameObject);
|
|
}
|
|
foreach (var manual in PlayerEntity.listOfManualInitWeaponslot)
|
|
{
|
|
thirdPersonWeaponList.Add(manual.gameObject);
|
|
}
|
|
|
|
foreach (GameObject weaponObj in thirdPersonWeaponList)
|
|
{
|
|
thirdPersonWeaponDictionary.Add(int.Parse(weaponObj.name), weaponObj);
|
|
}
|
|
|
|
}
|
|
|
|
public IEnumerator EquipWeaponCoroutine(Weapon weapon, Animator weaponAnimator = null,
|
|
WeaponController controller = null)
|
|
{
|
|
canShoot = false;
|
|
bool isWeaponAnimNull = weaponAnimator == null;
|
|
weaponData = null;
|
|
CurrentWeapon = controller;
|
|
if (!isWeaponAnimNull)
|
|
{
|
|
weaponAnim = weaponAnimator;
|
|
}
|
|
|
|
if (!isWeaponAnimNull)
|
|
{
|
|
weaponAnim.enabled = false;
|
|
}
|
|
|
|
if (weapon.playerAnimatorStance != null)
|
|
{
|
|
animator.runtimeAnimatorController = weapon.playerAnimatorStance;
|
|
}
|
|
|
|
if (!isWeaponAnimNull)
|
|
{
|
|
weaponAnim.enabled = true;
|
|
}
|
|
|
|
yield return new WaitForSeconds(weapon.equipDuration);
|
|
canShoot = true;
|
|
weaponData = weapon;
|
|
UIManager.Instance.ammoWeaponHud.enabled = false;
|
|
UIManager.Instance.rocketWeaponHud.enabled = false;
|
|
UIManager.Instance.flameWeaponHud.enabled = false;
|
|
switch (weapon.weaponAmmoType)
|
|
{
|
|
case WeaponAmmoType.Bullet:
|
|
UIManager.Instance.ammoWeaponHud.enabled = true;
|
|
break;
|
|
|
|
case WeaponAmmoType.Flame:
|
|
UIManager.Instance.flameWeaponHud.enabled = true;
|
|
break;
|
|
|
|
case WeaponAmmoType.Rocket:
|
|
UIManager.Instance.rocketWeaponHud.enabled = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
public Camera GetPlayerFirstPersonCamera() => cameraController.playerCam;
|
|
public Vector3 GetPlayerFirstPersonCameraPosition() => GetPlayerFirstPersonCamera().transform.position;
|
|
|
|
private void UpdatePlayerForNetwork()
|
|
{
|
|
if (Time.time - lastNetworkUpdate > 0.1f)
|
|
{
|
|
byte playerFlag = 0x00;
|
|
|
|
if (IsAiming)
|
|
{
|
|
playerFlag |= 0x01;
|
|
}
|
|
|
|
if (jumpTrigger == 1)
|
|
{
|
|
playerFlag |= 0x02;
|
|
}
|
|
|
|
PacketManager.sendPlayerUpdatePacket(transform.position.x, transform.position.y, transform.position.z,
|
|
transform.rotation.eulerAngles.y, cameraController.m_desiredPitch, animator.GetFloat(animatorXAxis),
|
|
animator.GetFloat(animatorZAxis), animator.GetFloat(animatorVelocityMag), playerFlag);
|
|
|
|
lastNetworkUpdate = Time.time;
|
|
if (jumpTrigger == 1)
|
|
{
|
|
jumpTrigger = 0;
|
|
}
|
|
|
|
if (!GISocket.Instance.isClosed())
|
|
GISocket.Instance.pushOutStream();
|
|
}
|
|
}
|
|
|
|
private void HandleUnderWaterSpeed()
|
|
{
|
|
float waterScale = Mathf.InverseLerp(
|
|
Client.MAX_WATER_DEPTH,
|
|
Client.WATER_HEIGHT,
|
|
transform.position.y
|
|
);
|
|
float speedScale = Mathf.Lerp(0.05f, 1, waterScale);
|
|
playerController.WalkSpeed = speedScale * playerController.MaxWalkSpeed;
|
|
playerController.RunSpeed = speedScale * playerController.MaxRunSpeed;
|
|
}
|
|
|
|
private void Update()
|
|
{
|
|
hasFiredWeapon = false;
|
|
audioManager.transform.position = transform.position;
|
|
audioManager.transform.rotation = transform.rotation;
|
|
|
|
//player updating is turned off when menus are open
|
|
if (updatePlayer)
|
|
{
|
|
LockCursor(true);
|
|
|
|
if (IsAlive())
|
|
{
|
|
Shoot();
|
|
HandleMovement();
|
|
HandleInput();
|
|
HandleUnderWaterSpeed();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LockCursor(false);
|
|
animator.SetFloat(animatorXAxis, 0.0f);
|
|
animator.SetFloat(animatorZAxis, 0.0f);
|
|
}
|
|
|
|
HandlePause();
|
|
|
|
//Debug.LogError($"IsRunning:{IsRunning}, RunButtonPressed:{runButtonPressed}, RunLock:{RunInputLockCount}");
|
|
}
|
|
|
|
private void HandlePause()
|
|
{
|
|
// If escape is pressed open in game escape menu
|
|
if (!SettingsMenu.Instance.settingsIsActive && inputHandler.PauseKeyPressed)
|
|
{
|
|
inputHandler.PauseKeyPressed = false;
|
|
if (!UIManager.Instance.loginScreen)
|
|
{
|
|
if (!UIManager.Instance.getInterface<GameObject>(ESCAPE_MENU).activeSelf)
|
|
{
|
|
LockCursor(true);
|
|
HandleInventorySystems();
|
|
}
|
|
else
|
|
{
|
|
HandleVictorySceenCanvas();
|
|
UIManager.Instance.hideInterface(ESCAPE_MENU);
|
|
UIManager.Instance.ChatBox.UsingChatBox = false;
|
|
}
|
|
|
|
HandleBankVaultCanvas();
|
|
HandleForgeCanvas();
|
|
HandleWeaponExchangeCanvas();
|
|
}
|
|
}
|
|
}
|
|
|
|
private void HandleInventorySystems()
|
|
{
|
|
if (!UIManager.Instance.BankVaultCanvas.activeInHierarchy && !UIManager.Instance.Inventory.activeInHierarchy)
|
|
{
|
|
updatePlayer = false;
|
|
UIManager.Instance.showInterface(ESCAPE_MENU);
|
|
UIManager.Instance.ChatInputField.interactable = false;
|
|
}
|
|
else if (UIManager.Instance.Inventory.activeInHierarchy)
|
|
{
|
|
UIManager.Instance.hideInterface(UIManager.Instance.Inventory.name);
|
|
UpdatePlayerOnMenuClose();
|
|
}
|
|
}
|
|
|
|
private void HandleVictorySceenCanvas()
|
|
{
|
|
if (!UIManager.Instance.IsGameLobbyCanvasesActive() && !UIManager.Instance.VictoryCanvas.activeSelf)
|
|
{
|
|
LockCursor(true);
|
|
//only let the player move again if they're alive and not in pre-game menus.
|
|
if (IsAlive())
|
|
{
|
|
updatePlayer = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void HandleBankVaultCanvas()
|
|
{
|
|
if (UIManager.Instance.BankVaultCanvas.activeInHierarchy)
|
|
{
|
|
UIManager.Instance.ResetDefaultCanvasesOnVaultClose();
|
|
}
|
|
else
|
|
{
|
|
if (UIManager.Instance.Inventory.activeInHierarchy)
|
|
{
|
|
UIManager.Instance.hideInterface(INVENTORY);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void HandleForgeCanvas()
|
|
{
|
|
if (UIManager.Instance.ForgeController.gameObject.activeInHierarchy)
|
|
{
|
|
UIManager.Instance.CloseForge();
|
|
}
|
|
else
|
|
{
|
|
if (UIManager.Instance.Inventory.activeInHierarchy)
|
|
{
|
|
UIManager.Instance.hideInterface(INVENTORY);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void HandleWeaponExchangeCanvas()
|
|
{
|
|
if (UIManager.Instance.WeaponExchangeController.gameObject.activeInHierarchy)
|
|
{
|
|
UIManager.Instance.CloseWeaponExchange();
|
|
}
|
|
else
|
|
{
|
|
if (UIManager.Instance.Inventory.activeInHierarchy)
|
|
{
|
|
UIManager.Instance.hideInterface(INVENTORY);
|
|
}
|
|
}
|
|
}
|
|
|
|
private Vector2 AngleToDirection(float angle)
|
|
{
|
|
return new Vector2(Mathf.Cos(angle * Mathf.Deg2Rad), Mathf.Sin(angle * Mathf.Deg2Rad));
|
|
}
|
|
|
|
public void LockCursor(bool isLocked)
|
|
{
|
|
Cursor.lockState = inputHandler.UsingGamePad || isLocked ? CursorLockMode.Locked : CursorLockMode.None;
|
|
Cursor.visible = !inputHandler.UsingGamePad && !isLocked;
|
|
}
|
|
|
|
public void ApplyKnockback(ref Vector3 knockbackAddition)
|
|
{
|
|
if (Time.time - this.knockbackTimer < 0.5f)
|
|
{
|
|
isBeingKnockedBack = true;
|
|
animator.Play(animatorKnockback);
|
|
Vector2 dir = AngleToDirection(knockbackAngle);
|
|
float x = dir.y * knockbackForce * knockbackForceMultiplier;
|
|
float y = 1.0f;
|
|
float z = dir.x * knockbackForce * knockbackForceMultiplier;
|
|
knockbackAddition += (Vector3.up * y);
|
|
Vector2 knockback = new Vector2(x, z);
|
|
knockbackVector = knockback;
|
|
this.knockbackTimer = 0f;
|
|
}
|
|
|
|
if (knockbackVector.magnitude > 3.5f)
|
|
{
|
|
Vector3 velocityVec = new Vector3(knockbackVector.x, knockbackAddition.y, knockbackVector.y);
|
|
knockbackAddition = velocityVec;
|
|
knockbackVector = Vector2.SmoothDamp(knockbackVector, Vector2.zero, ref knockbackRef, 0.25f);
|
|
return;
|
|
}
|
|
|
|
knockbackVector = Vector2.zero;
|
|
isBeingKnockedBack = false;
|
|
}
|
|
|
|
private void FixedUpdate()
|
|
{
|
|
//send a state update to the server every 100ms
|
|
UpdatePlayerForNetwork();
|
|
//ensure player height stays above the terrain
|
|
terrainHeightFix();
|
|
|
|
oldPosition = transform.position;
|
|
}
|
|
|
|
private void OnControllerColliderHit(ControllerColliderHit hit)
|
|
{
|
|
if (hit.collider != null)
|
|
{
|
|
//if the angle of the colliding object is greater than 50 degrees, Don't jump.
|
|
float normalAngle = Vector3.Angle(hit.normal, Vector3.up);
|
|
CanJump = normalAngle <= 50f;
|
|
|
|
if (hit.gameObject.layer == LayerMask.NameToLayer("Enemy") && normalAngle <= 15f)
|
|
{
|
|
//i am on enemys head, force placer off.
|
|
}
|
|
}
|
|
}
|
|
|
|
public void SetWeapon(int itemId)
|
|
{
|
|
PlayerEntity.weaponId = itemId;
|
|
PlayerEntity.projectileOrigin = null;
|
|
|
|
foreach (Transform child in cameraWeaponSlot.transform)
|
|
{
|
|
child.gameObject.SetActive(false);
|
|
}
|
|
|
|
foreach (Transform child in weaponSlot.transform)
|
|
{
|
|
child.gameObject.SetActive(false);
|
|
}
|
|
|
|
if (itemId != -1 && itemId != 11)
|
|
{
|
|
currentWeapon = firstPersonWeaponDictionary[itemId];
|
|
currentWeapon.SetActive(true);
|
|
|
|
current_3D_Weapon = thirdPersonWeaponDictionary[itemId];
|
|
current_3D_Weapon.SetActive(true);
|
|
|
|
current_3D_Weapon.layer = LayerMask.NameToLayer("PlayerUI");
|
|
PlayerEntity.projectileOrigin = currentWeapon.transform?.Find("projectileOrigin")?.gameObject;
|
|
}
|
|
}
|
|
|
|
|
|
public void ApplyRecoil(float yawRecoil, float pitchRecoil)
|
|
{
|
|
cameraController.m_desiredYaw += yawRecoil;
|
|
cameraController.m_desiredPitch += pitchRecoil;
|
|
}
|
|
|
|
private void terrainHeightFix()
|
|
{
|
|
/* if (transform.position.y < 22.5f)
|
|
{
|
|
transform.position = new Vector3(transform.position.x, 22.5f, transform.position.z);
|
|
}*/
|
|
|
|
Terrain terrain = Misc.GetClosestCurrentTerrain(transform.position);
|
|
if (terrain == null)
|
|
return;
|
|
float height = terrain.SampleHeight(transform.position);
|
|
if (transform.position.y < height)
|
|
{
|
|
transform.position = new Vector3(transform.position.x, height, transform.position.z);
|
|
}
|
|
}
|
|
|
|
private float sampleTerrainHeight(Vector3 position)
|
|
{
|
|
Terrain terrain = Misc.GetClosestCurrentTerrain(position);
|
|
if (terrain == null)
|
|
return 0.0f;
|
|
return terrain.SampleHeight(position);
|
|
}
|
|
|
|
private void Shoot()
|
|
{
|
|
if (weaponData != null)
|
|
{
|
|
shootButton = weaponData.isAutomatic
|
|
? inputHandler.FireKeyPressed
|
|
: inputHandler.FireKeyPressedThisFrame;
|
|
|
|
var active =
|
|
canShoot &&
|
|
HitPoints != 0 &&
|
|
Time.time - lastShotTime > weaponData.shootCooldown &&
|
|
shootButton;
|
|
|
|
if (weaponData.isGun || weaponData.isRocketLauncher)
|
|
{
|
|
if (active)
|
|
{
|
|
if (CurrentWeapon.hasAttackEffect) CurrentWeapon.PlayAttackLocalEffect();
|
|
if (weaponData.isBurstFire)
|
|
{
|
|
if (!isShootingBurstWeapon)
|
|
{
|
|
StartCoroutine(ShootBurstWeapon());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ShootWeapon(weaponData.bulletsPerTap);
|
|
}
|
|
}
|
|
else
|
|
if (CurrentWeapon.hasAttackEffect) CurrentWeapon.UnPlayAttackLocalEffect();
|
|
}
|
|
else
|
|
{
|
|
if (active && weaponData.weaponType == Weapon.WEAPON_TYPE.MINER)
|
|
{
|
|
MineWeapon();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void MineWeapon()
|
|
{
|
|
if (BreakShot()) return;
|
|
CurrentWeapon.Mining();
|
|
lastShotTime = Time.time;
|
|
}
|
|
|
|
private IEnumerator ShootBurstWeapon()
|
|
{
|
|
isShootingBurstWeapon = true;
|
|
int bullets = weaponData.bulletsPerTap;
|
|
float timeBetweenShots = weaponData.timeBetweenShots;
|
|
|
|
for (int i = 0; i < bullets; i++)
|
|
{
|
|
if (weaponData == null)
|
|
{
|
|
Debug.Log("Error: Weapon data is null");
|
|
}
|
|
ShootWeapon();
|
|
yield return new WaitForSeconds(timeBetweenShots);
|
|
}
|
|
|
|
isShootingBurstWeapon = false;
|
|
}
|
|
|
|
private bool BreakShot()
|
|
{
|
|
if (Time.time - lastReload < reloadTime)
|
|
{
|
|
return true;
|
|
}
|
|
if (HitPoints <= 0)
|
|
{
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private void ShootWeapon(int shotCount = 1)
|
|
{
|
|
if (this.weaponData == null) return;
|
|
if (shotCount < 1) shotCount = 1;
|
|
if (BreakShot()) return;
|
|
|
|
bool isRocketLauncher = this.weaponData.isRocketLauncher;
|
|
bool isShotgun = this.weaponData.isShotgun;
|
|
bool isMeleeFlameAttack = this.weaponData.isMeleeFlameAttack;
|
|
|
|
bool hasAmmo = true;
|
|
|
|
switch (isRocketLauncher)
|
|
{
|
|
case true when this.rocketAmmo <= 0:
|
|
case false when this.ammo <= 0:
|
|
hasAmmo = false;
|
|
break;
|
|
}
|
|
|
|
if (!hasAmmo)
|
|
{
|
|
//play blank fire sound
|
|
lastShotTime = Time.time;
|
|
AudioManager.Instance.playSound(weaponData.emptySound);
|
|
return;
|
|
}
|
|
|
|
if (IsRunning) return; //can only shoot if you're not running.
|
|
|
|
hasFiredWeapon = true;
|
|
|
|
float randPitch = UnityEngine.Random.Range(0.85f, 1.15f);
|
|
if (isMeleeFlameAttack && inputHandler.FireKeyPressedThisFrame)
|
|
{
|
|
CurrentWeapon.Fire(IsAiming);
|
|
animator.Play(animator3D_Shoot);
|
|
AudioManager.Instance.playSound(weaponData.fireSound, randPitch);
|
|
}
|
|
else
|
|
{
|
|
CurrentWeapon.Fire(IsAiming);
|
|
animator.Play(animator3D_Shoot);
|
|
AudioManager.Instance.playSound(weaponData.fireSound, randPitch);
|
|
|
|
}
|
|
|
|
lastShotTime = Time.time;
|
|
if (isRocketLauncher)
|
|
{
|
|
this.rocketAmmo -= 1;
|
|
}
|
|
else
|
|
{
|
|
this.ammo -= 1;
|
|
}
|
|
|
|
UIManager.Instance.clipCapacityText.SetText($"{ammo}");
|
|
UIManager.Instance.rocketCapacityText.SetText($"{rocketAmmo}");
|
|
|
|
|
|
int[] hitFlags = new int[shotCount];
|
|
Vector3[] hitPoints = new Vector3[shotCount];
|
|
string[] names = new string[shotCount];
|
|
int[] npcIds = new int[shotCount];
|
|
int[] hitShields = new int[shotCount];
|
|
|
|
Vector3 origin = PlayerEntity.GetProjectileOrigin();
|
|
|
|
//print the number of shots
|
|
print("shotcount " + shotCount);
|
|
for (int i = 0; i < shotCount; i++)
|
|
{
|
|
float xHipFire = UnityEngine.Random.Range(-weaponData.horizontalSpread, weaponData.horizontalSpread);
|
|
float yHipFire = UnityEngine.Random.Range(-weaponData.verticleSpread, weaponData.verticleSpread);
|
|
Vector2 hipFireOffset = new Vector2(xHipFire, yHipFire);
|
|
Vector2 aimedFire = new Vector2(Screen.width / 2f, Screen.height / 2f);
|
|
Vector2 hipFire = aimedFire + hipFireOffset;
|
|
Ray ray = cameraController.playerCam.ScreenPointToRay(IsAiming && !weaponData.isShotgun
|
|
? aimedFire
|
|
: hipFire);
|
|
Vector3 direction = ray.direction;
|
|
|
|
PlayerEntity.fireProjectile(direction, weaponData.projectile);
|
|
PlayerEntity.animator.Play(animator3D_Shoot);
|
|
|
|
int hitFlag = 0;
|
|
int hitShield = 0;
|
|
|
|
if (Physics.Raycast(ray, out RaycastHit hit, weaponData.effectiveRange, ~excludeLayers,
|
|
QueryTriggerInteraction.Ignore))
|
|
{
|
|
CheckDummyHit(hit);
|
|
if (hit.collider.CompareTag(SHIELD)) hitShield = 1;
|
|
if (hit.transform.root.TryGetComponent(out NPC npc))
|
|
OnRayHitTheNps(npc, hit, isRocketLauncher, i, hitShield);
|
|
else
|
|
SetPacketData(i, 0, hit.point, "", -1, 0);
|
|
}
|
|
else
|
|
SetPacketData(i, 0, hit.point, "", -1, 0);
|
|
}
|
|
|
|
void OnRayHitTheNps(NPC npc, RaycastHit hit, bool b, int i, int hitShield)
|
|
{
|
|
if (npc.type != 0) //red demon does not have these params.
|
|
{
|
|
if (hit.collider.CompareTag(HEAD))
|
|
{
|
|
npc.animator.SetTrigger(animator3D_HeadHit);
|
|
}
|
|
else
|
|
{
|
|
npc.animator.SetTrigger(animator3D_BodyHit);
|
|
}
|
|
}
|
|
var root = hit.transform.root;
|
|
var hitFlag = GetHitFlag(hit.transform.tag);
|
|
float calculatedWeaponDamage = CalculateWeaponDamage(transform.position,
|
|
root.position, weaponData.maxDamage, weaponData.effectiveRange, hitFlag);
|
|
|
|
CrosshairManager.Instance.CreateHitMarkerCoroutine(true, hit, b);
|
|
ApplyDamage(hit, npc.type, calculatedWeaponDamage, hitFlag);
|
|
SetPacketData(i, hitFlag, hit.point, root.name, npc.GetID(), hitShield);
|
|
}
|
|
void SetPacketData(int index , int hitFlag, Vector3 hitPoint, string nameOfUnit, int npsId, int hitShield )
|
|
{
|
|
hitFlags[index] = hitFlag;
|
|
hitPoints[index] = hitPoint;
|
|
names[index] = nameOfUnit;
|
|
npcIds[index] = npsId;
|
|
hitShields[index] = hitShield;
|
|
}
|
|
|
|
|
|
Vector3 dir = cameraController.playerCam.transform.forward;
|
|
PacketManager.sendPlayerShot(origin, dir, hitFlags, hitPoints, names, npcIds, hitShields);
|
|
|
|
}
|
|
|
|
public float CalculateWeaponDamage(Vector3 PlayerPos, Vector3 NPCPos, int maxDamage, int effectiveRange,
|
|
int hitFlag)
|
|
{
|
|
float distance = Vector3.Distance(PlayerPos, NPCPos);
|
|
float damage = (float)maxDamage * CalcDamage(effectiveRange, (int)distance);
|
|
damage *= (float)hitFlag / 100.0f;
|
|
|
|
return damage;
|
|
}
|
|
|
|
private static float CalcDamage(int effectiveRange, int distance)
|
|
{
|
|
int invert = effectiveRange - distance;
|
|
float scale10 = (10.0f / (float)effectiveRange) * invert;
|
|
float damage = (float)Mathf.Log10(scale10);
|
|
return damage;
|
|
}
|
|
|
|
public void ApplyDamage(RaycastHit hit, int npcID, float calculatedDamage, int hitFlag)
|
|
{
|
|
string effectName;
|
|
switch (npcID)
|
|
{
|
|
case 3:
|
|
if (hit.collider.CompareTag(SHIELD))
|
|
{
|
|
effectName = SPARKS;
|
|
}
|
|
else
|
|
{
|
|
effectName = BLOOD;
|
|
}
|
|
|
|
break;
|
|
case 9:
|
|
effectName = SPARKS;
|
|
break;
|
|
default:
|
|
effectName = BLOOD;
|
|
break;
|
|
}
|
|
|
|
if (weaponData.isGun)
|
|
{
|
|
if (hit.collider.CompareTag(BULLSEYE))
|
|
{
|
|
CreateDamageText(hit, "Bullseye!");
|
|
}
|
|
else if (calculatedDamage > 0)
|
|
{
|
|
CreateDamageText(hit, hitFlag, calculatedDamage);
|
|
}
|
|
}
|
|
|
|
CreateHitEffects(effectName, hit, npcID, calculatedDamage);
|
|
}
|
|
|
|
private void CreateDamageText(RaycastHit hit, int hitFlag, float calculatedDamage = 0.0f)
|
|
{
|
|
GameObject damageTextClone =
|
|
NetworkPooler.Instance.PooledInstantiate("FloatingDamageText", hit.point, Quaternion.identity);
|
|
FloatingDamageText text = damageTextClone.GetComponent<FloatingDamageText>();
|
|
text.MaxWaitTime = 1.0f;
|
|
Color color = hitFlag == 100 ? Color.red : Color.white;
|
|
text.GetText().color = color;
|
|
text.GetText().SetText(Mathf.RoundToInt(calculatedDamage).ToString());
|
|
}
|
|
|
|
private void CreateDamageText(RaycastHit hit, string textToDisplay)
|
|
{
|
|
GameObject damageTextClone =
|
|
NetworkPooler.Instance.PooledInstantiate("FloatingDamageText", hit.point, Quaternion.identity);
|
|
FloatingDamageText text = damageTextClone.GetComponent<FloatingDamageText>();
|
|
text.MaxWaitTime = 1.0f;
|
|
Color color = Color.yellow;
|
|
text.GetText().color = color;
|
|
text.GetText().SetText(textToDisplay);
|
|
}
|
|
|
|
public int GetHitFlag(string tag)
|
|
{
|
|
switch (tag)
|
|
{
|
|
case BULLSEYE:
|
|
ScoreManager.Instance.AddHeadShotMessage();
|
|
return 200;
|
|
case HEAD:
|
|
ScoreManager.Instance.AddHeadShotMessage();
|
|
return 100;
|
|
case BODY:
|
|
return 50;
|
|
case ARM:
|
|
case LEG:
|
|
return 30;
|
|
case FOOT:
|
|
return 20;
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
private void CheckDummyHit(RaycastHit hit)
|
|
{
|
|
Transform hitT = hit.transform;
|
|
LobbyDummyController lobbyDummy = hitT.GetComponentInParent<LobbyDummyController>();
|
|
if (lobbyDummy == null) return;
|
|
|
|
lobbyDummy.hitHead = hitT.TryGetComponent(out DummyHead _);
|
|
lobbyDummy.hitBody = hitT.TryGetComponent(out DummyBody _);
|
|
if (lobbyDummy.hitHead || lobbyDummy.hitBody)
|
|
{
|
|
CrosshairManager.Instance.CreateHitMarkerCoroutine(false, hit, false);
|
|
}
|
|
}
|
|
|
|
private void CreateHitEffects(string effect, RaycastHit hit, int npcID, float estimatedDamage)
|
|
{
|
|
GameObject bloodEffect = NetworkPooler.Instance.PooledInstantiate(effect, hit.point, Quaternion.identity);
|
|
|
|
VisualEffect effectProperties = bloodEffect.GetComponentInChildren<VisualEffect>();
|
|
|
|
Vector3 direction = (transform.position - hit.transform.position).normalized;
|
|
bloodEffect.transform.forward = Vector3.ProjectOnPlane(direction, Vector3.up);
|
|
if (effectProperties != null)
|
|
{
|
|
//Because VFX graph is GPU computed. it cannot do physics properly. For this, i calculate the floor height, and spawn the pool blood at that value.
|
|
Ray floorLevelRay = new Ray(hit.point, Vector3.down);
|
|
if (Physics.Raycast(floorLevelRay.origin, floorLevelRay.direction, out RaycastHit internalHit, 40,
|
|
LayerMask.GetMask("Default")))
|
|
{
|
|
float floorPos = internalHit.point.y;
|
|
floorPos -= 0.4f; //offset it by -1 because it spawns slightly above floor height.
|
|
effectProperties.SetFloat("TerrainHeight", floorPos);
|
|
}
|
|
|
|
Vector4 bloodColour;
|
|
switch (npcID)
|
|
{
|
|
case 11:
|
|
case 10:
|
|
//green blood
|
|
bloodColour = Client.Instance.GreenBloodColour * Client.Instance.colourIntensityModifier;
|
|
break;
|
|
case 3:
|
|
bloodColour = Client.Instance.RedBloodColour * Client.Instance.colourIntensityModifier;
|
|
break;
|
|
case 8:
|
|
//brown Colour
|
|
bloodColour = Client.Instance.BrownBloodColour * Client.Instance.colourIntensityModifier;
|
|
break;
|
|
default:
|
|
//red blood
|
|
bloodColour = Client.Instance.RedBloodColour * Client.Instance.colourIntensityModifier;
|
|
break;
|
|
}
|
|
|
|
effectProperties.SetVector4(Client.Instance.bloodID, bloodColour);
|
|
|
|
float calculatedDamage = estimatedDamage > 0f && estimatedDamage < 250f ? estimatedDamage : 40f;
|
|
effectProperties.SetFloat(visualEffect_Rate, calculatedDamage);
|
|
}
|
|
|
|
NetworkPooler.Instance.PooledDestroy(effect, bloodEffect, effectProperties == null ? 1.0f : 5.0f);
|
|
}
|
|
|
|
private void HandleInput()
|
|
{
|
|
//Debug.Log($"Run Lock = {runInputLockCount}");
|
|
|
|
bool isInteractingWithObjects = false;
|
|
|
|
HandleAiming();
|
|
|
|
if (UIManager.Instance.ChatBox.UsingChatBox)
|
|
{
|
|
return;
|
|
}
|
|
|
|
|
|
if (inputHandler.PingKeyPressed)
|
|
{
|
|
inputHandler.PingKeyPressed = false;
|
|
string parentObject = "";
|
|
Ray ray = cameraController.playerCam.ScreenPointToRay(new Vector3(Screen.width / 2f, Screen.height / 2f));
|
|
if (Physics.Raycast(ray, out var hit))
|
|
{
|
|
Collider collider = hit.collider;
|
|
|
|
if (collider.transform.root.gameObject.GetComponent<NPC>() != null)
|
|
{
|
|
parentObject = collider.transform.root.gameObject.name;
|
|
PacketManager.sendPing(0, 1.0f, 0, parentObject);
|
|
}
|
|
else if (collider.transform.root.gameObject.GetComponent<PlayerEntity>() != null)
|
|
{
|
|
parentObject = collider.transform.root.gameObject.name;
|
|
float x = collider.gameObject.transform.position.x;
|
|
float z = collider.gameObject.transform.position.z;
|
|
float y = sampleTerrainHeight(new Vector3(x, 0, z));
|
|
PacketManager.sendPing(x, y, z, parentObject);
|
|
}
|
|
else
|
|
{
|
|
float x = hit.point.x;
|
|
float z = hit.point.z;
|
|
float y = sampleTerrainHeight(new Vector3(x, 0, z));
|
|
PacketManager.sendPing(x, y, z, "");
|
|
}
|
|
}
|
|
}
|
|
|
|
//Debug.Log("max hitpoints: " + maxHitPoints);
|
|
if (IsAlive() && HitPoints < MaxHitPoints && inputHandler.DrinkPotionKeyPressed)
|
|
{
|
|
inputHandler.DrinkPotionKeyPressed = false;
|
|
for (int i = 0; i < InventoryManager.Instance.inventoryItems.Length; i++)
|
|
{
|
|
if (InventoryManager.Instance.inventoryItems[i] == 8)
|
|
{
|
|
PacketManager.sendClickItem(8, i);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (inputHandler.EquipGrenadeKeyPressed)
|
|
{
|
|
inputHandler.EquipGrenadeKeyPressed = false;
|
|
for (int i = 0; i < InventoryManager.Instance.inventoryItems.Length; i++)
|
|
{
|
|
if (ItemDef.GetInstance().isThrowable(InventoryManager.Instance.inventoryItems[i]))
|
|
{
|
|
PacketManager.sendClickItem(InventoryManager.Instance.inventoryItems[i], i);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
for (int i = 49; i <= 54; i++)
|
|
{
|
|
KeyCode numericKey = (KeyCode)i;
|
|
int inventorySlotIndex = i - 31;
|
|
|
|
if (Input.GetKeyDown(numericKey) && InventoryManager.Instance.inventoryItems[inventorySlotIndex] != -1)
|
|
{
|
|
int weaponId = InventoryManager.Instance.equipmentItems[0];
|
|
|
|
if (weaponId == 150)
|
|
{
|
|
Debug.Log("Building");
|
|
BuildMode.Instance.preview(InventoryManager.Instance.inventoryItems[inventorySlotIndex]);
|
|
|
|
}
|
|
else
|
|
{
|
|
PacketManager.sendClickItem(InventoryManager.Instance.inventoryItems[inventorySlotIndex],
|
|
inventorySlotIndex);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (inputHandler.InteractKeyPressed)
|
|
{
|
|
inputHandler.InteractKeyPressed = false;
|
|
if (interactableGroundItem != null && interactableWorldObject != null)
|
|
{
|
|
isInteractingWithObjects = true;
|
|
InteractWithHighestDotObject();
|
|
}
|
|
else if (interactableGroundItem != null)
|
|
{
|
|
isInteractingWithObjects = true;
|
|
PacketManager.sendPickupItem(int.Parse(interactableGroundItem.name),
|
|
(int)interactableGroundItem.transform.position.x, (int)interactableGroundItem.transform.position.z);
|
|
}
|
|
else if (interactableWorldObject != null)
|
|
{
|
|
isInteractingWithObjects = true;
|
|
PacketManager.sendObjectClick(interactableWorldObject.name,
|
|
(int)interactableWorldObject.transform.position.x,
|
|
(int)interactableWorldObject.transform.position.z);
|
|
}
|
|
}
|
|
|
|
if (weaponData != null)
|
|
{
|
|
int ammoType = 0;
|
|
if (weaponData.isGun)
|
|
{
|
|
ammoType = ammo;
|
|
}
|
|
else if (weaponData.isRocketLauncher)
|
|
{
|
|
ammoType = rocketAmmo;
|
|
}
|
|
|
|
if (ammoType < weaponData.ammoClipAmount)
|
|
{
|
|
UIManager.Instance.ReloadIndicator.text = InputMessageHandler.Instance.Interpolate("[[Reload]]");
|
|
}
|
|
else
|
|
{
|
|
UIManager.Instance.ReloadIndicator.text = "";
|
|
}
|
|
}
|
|
else
|
|
{
|
|
UIManager.Instance.ReloadIndicator.text =
|
|
""; //if weapon data is null, we also want to not display a key indicator.
|
|
}
|
|
|
|
if (weaponAnim != null && weaponData != null)
|
|
{
|
|
bool isInReloadingAnimationState = weaponAnim.GetCurrentAnimatorStateInfo(0).IsName("Reload");
|
|
if (IsAlive() && !isInteractingWithObjects && inputHandler.ReloadKeyPressed)
|
|
{
|
|
inputHandler.ReloadKeyPressed = false;
|
|
if (weaponData.isGun)
|
|
{
|
|
ReloadWeapon(ammo, isInReloadingAnimationState);
|
|
}
|
|
|
|
if (weaponData.isRocketLauncher)
|
|
{
|
|
ReloadWeapon(rocketAmmo, isInReloadingAnimationState);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void HandleAiming()
|
|
{
|
|
if (weaponData != null && (weaponData.isGun || weaponData.isRocketLauncher) && IsAlive())
|
|
{
|
|
if (CanAim && inputHandler.AimKeyPressed)
|
|
{
|
|
if (!IsAiming) RunInputLockCount++;
|
|
if (!SettingsMenu.Instance.ToggleADS)
|
|
{
|
|
IsAiming = true;
|
|
}
|
|
else
|
|
{
|
|
inputHandler.AimKeyPressed = false;
|
|
inputHandler.ToggleAiming = !inputHandler.ToggleAiming;
|
|
IsAiming = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
bool unAim = SettingsMenu.Instance.ToggleADS ? !inputHandler.ToggleAiming : !inputHandler.AimKeyPressed;
|
|
if (unAim || !CanAim)
|
|
{
|
|
if (IsAiming) RunInputLockCount--;
|
|
IsAiming = false;
|
|
}
|
|
}
|
|
|
|
private void InteractWithHighestDotObject()
|
|
{
|
|
Vector3 camForward = cameraController.playerCam.transform.forward;
|
|
float groundItemDot =
|
|
Vector3.Dot(camForward, (interactableGroundItem.transform.position - camForward).normalized);
|
|
float worldObjectDot =
|
|
Vector3.Dot(camForward, (interactableWorldObject.transform.position - camForward).normalized);
|
|
|
|
//ground items have priorty to be picked up before object interactions, if their bounds overlap.
|
|
if ((groundItemDot > worldObjectDot) || GroundItemManager.InteractingWithItem)
|
|
PacketManager.sendPickupItem(int.Parse(interactableGroundItem.name),
|
|
(int)interactableGroundItem.transform.position.x, (int)interactableGroundItem.transform.position.z);
|
|
else
|
|
PacketManager.sendObjectClick(interactableWorldObject.name,
|
|
(int)interactableWorldObject.transform.position.x, (int)interactableWorldObject.transform.position.z);
|
|
}
|
|
|
|
public Weapon GetWeaponData() => weaponData;
|
|
|
|
private void ReloadWeapon(int ammoType, bool reloadState)
|
|
{
|
|
if (ammoType < weaponData.ammoClipAmount)
|
|
{
|
|
if (IsAiming) RunInputLockCount--;
|
|
IsAiming = false;
|
|
|
|
animator.Play(animator3D_Reload); // need this for main player shadow.
|
|
if ((!reloadState) && canReload)
|
|
{
|
|
PacketManager.sendChatMessage("/reload");
|
|
StartCoroutine(ReloadCooldown());
|
|
}
|
|
}
|
|
}
|
|
|
|
private IEnumerator ReloadCooldown()
|
|
{
|
|
canReload = false;
|
|
CanAim = false;
|
|
yield return new WaitForSeconds(reloadTime);
|
|
CanAim = true;
|
|
canReload = true;
|
|
animator.speed = 1;
|
|
|
|
WeaponController weaponController = currentWeapon.GetComponent<WeaponController>();
|
|
if (weaponController && currentWeapon != null)
|
|
weaponController.SetAnimatorSpeedToDefault();
|
|
}
|
|
|
|
public float GetPlayerMagnitude()
|
|
{
|
|
Vector3 horizontalVel =
|
|
new Vector3(playerController.m_finalMoveVector.x, 0f, playerController.m_finalMoveVector.z);
|
|
float magnitude = horizontalVel.magnitude;
|
|
|
|
return magnitude;
|
|
}
|
|
|
|
public bool CanPlayRunningEvents()
|
|
{
|
|
if (playerController.CurrentMagnitude < playerController.LowestAllowedMagnitude) return false;
|
|
|
|
float horizontalAxis = inputHandler.GetMovementData().InputVectorX;
|
|
bool controllerIsPointingForward = horizontalAxis < 0.5f || horizontalAxis > -0.5f;
|
|
|
|
//uncomment this if you only want the run animations to play if ONLY pressing forward.
|
|
//bool notMovingLeftOrRight = inputHandler.UsingGamePad ? controllerIsPointingForward : horizontalAxis == 0;
|
|
|
|
bool isGoingForward = inputHandler.GetMovementData().InputVectorY > 0f /*&& notMovingLeftOrRight*/;
|
|
bool canPlayRunEvents = updatePlayer && (IsRunning && isGoingForward);
|
|
|
|
return canPlayRunEvents;
|
|
}
|
|
|
|
private void HandleMovement()
|
|
{
|
|
Vector3 horizontalVel =
|
|
new Vector3(playerController.m_finalMoveVector.x, 0f, playerController.m_finalMoveVector.z);
|
|
float magnitude = horizontalVel.magnitude;
|
|
Vector3 localVelocity = transform.InverseTransformDirection(horizontalVel);
|
|
animator.SetFloat(animatorXAxis, localVelocity.x);
|
|
animator.SetFloat(animatorZAxis, localVelocity.z);
|
|
animator.SetFloat(animatorVelocityMag, magnitude);
|
|
|
|
if (playerController.m_characterController.isGrounded)
|
|
{
|
|
distanceTravelled += magnitude * Time.deltaTime;
|
|
}
|
|
else
|
|
{
|
|
distanceTravelled = maxFootstepDistance - 0.01f;
|
|
}
|
|
|
|
if (distanceTravelled > maxFootstepDistance)
|
|
{
|
|
PlayFootstep();
|
|
distanceTravelled %= maxFootstepDistance;
|
|
}
|
|
|
|
//keep player within world bounds // we dont really need this.
|
|
Vector3 position = transform.position;
|
|
position.x = Mathf.Clamp(position.x, 0.0f, World.WORLD_SIZE_X - 1);
|
|
position.z = Mathf.Clamp(position.z, 0.0f, World.WORLD_SIZE_Y - 1);
|
|
transform.position = position;
|
|
}
|
|
|
|
private void PlayFootstep()
|
|
{
|
|
int randomFootstep = UnityEngine.Random.Range(0, playerController.FootStepClips.Count);
|
|
float randRunPitch = IsRunning ? Random.Range(1.5f, 1.8f) : Random.Range(1.1f, 1.4f);
|
|
AudioManager.Instance.PlaySound(playerController.FootStepClips[randomFootstep], randRunPitch);
|
|
}
|
|
|
|
private void OnTriggerEnter(Collider other)
|
|
{
|
|
if (other.CompareTag("TallGrass"))
|
|
{
|
|
Debug.Log("In tall grass");
|
|
inTallGrass = true;
|
|
}
|
|
}
|
|
|
|
private void OnTriggerExit(Collider other)
|
|
{
|
|
if (other.CompareTag("TallGrass"))
|
|
{
|
|
inTallGrass = false;
|
|
}
|
|
}
|
|
|
|
public void setId(int id)
|
|
{
|
|
this.id = id;
|
|
}
|
|
|
|
public int GetID()
|
|
{
|
|
return id;
|
|
}
|
|
|
|
public void setPlayerName(string playerName)
|
|
{
|
|
this.playerName = playerName;
|
|
}
|
|
|
|
public void ProcessEntityUpdate(int id, float x, float y, float z, int hitPoints, string name, float rotationY)
|
|
{
|
|
this.HitPoints = hitPoints;
|
|
this.playerName = name;
|
|
playerNameTextMesh.text = playerName;
|
|
|
|
if (x > 0.0f)
|
|
{
|
|
transform.position = new Vector3(x, y, z);
|
|
transform.rotation = Quaternion.Euler(
|
|
transform.rotation.eulerAngles.x,
|
|
rotationY,
|
|
transform.rotation.eulerAngles.z);
|
|
}
|
|
Debug.Log($"Teleporting to: {x}, {y}, {z}");
|
|
}
|
|
|
|
public void BeginDeathCamera()
|
|
{
|
|
updatePlayer = false;
|
|
OnlyCastPlayerShadows(false);
|
|
cameraController.playerCam.gameObject.SetActive(false);
|
|
thirdPersonCamera.gameObject.SetActive(true);
|
|
ChangeGrassCameraAssignment(thirdPersonCamera);
|
|
}
|
|
|
|
int spectatingPlayerId;
|
|
|
|
public void spectatePlayer(int playerId)
|
|
{
|
|
this.spectatingPlayerId = playerId;
|
|
//disable your own 3rd person camera after 5 seconds, to allow another players camera to be active.
|
|
thirdPersonCamera.gameObject.SetActive(false);
|
|
|
|
if (playerId == -1)
|
|
{
|
|
//stop spectating
|
|
CancelDeathCamera();
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
PlayerEntity.spectatePlayer(playerId);
|
|
ChangeGrassCameraAssignment(PlayerEntity.spectatedPlayersThirdPersonCamera);
|
|
}
|
|
}
|
|
|
|
public void CancelDeathCamera()
|
|
{
|
|
PlayerEntity spectatedPlayer = PlayerManager.Instance.GetPlayer(spectatingPlayerId);
|
|
|
|
if (spectatedPlayer != null)
|
|
{
|
|
if (spectatedPlayer.thirdPersonCameraObject != null)
|
|
spectatedPlayer.thirdPersonCameraObject.SetActive(false);
|
|
}
|
|
|
|
|
|
thirdPersonCamera.gameObject.SetActive(false);
|
|
cameraController.playerCam.gameObject.SetActive(true);
|
|
ChangeGrassCameraAssignment(cameraController.playerCam);
|
|
UIManager.Instance.hideInterface("RespawnWaitCanvas");
|
|
OnlyCastPlayerShadows(true);
|
|
|
|
updatePlayer = true;
|
|
}
|
|
|
|
private void ChangeGrassCameraAssignment(Camera cameraToAssign)
|
|
{
|
|
for (int i = 0; i < grassScript.Length; i++)
|
|
{
|
|
grassScript[i].AssignCamera(cameraToAssign);
|
|
}
|
|
}
|
|
|
|
public void mainPlayerUpdate(float reloadTime, float reloadSpeedMultiplier, int rocketAmmo, int ammo, int health,
|
|
string animation, int score, int damage)
|
|
{
|
|
this.rocketAmmo = rocketAmmo;
|
|
if (weaponData)
|
|
{
|
|
ammo = Misc.Clamp(ammo, 0, weaponData.ammoClipAmount);
|
|
}
|
|
|
|
this.ammo = ammo;
|
|
|
|
this.HitPoints = health;
|
|
int difference = score - this.score;
|
|
this.score = score;
|
|
this.damage = damage;
|
|
this.reloadSpeedMultiplier = reloadSpeedMultiplier;
|
|
|
|
if (difference > 0)
|
|
{
|
|
ScoreManager.Instance.AddPoints(difference);
|
|
}
|
|
|
|
if (difference < 0)
|
|
{
|
|
ScoreManager.Instance.RemovePoints(difference);
|
|
}
|
|
|
|
if (reloadTime > 0.0f)
|
|
{
|
|
this.lastReload = Time.time;
|
|
this.reloadTime = reloadTime;
|
|
}
|
|
|
|
if (animation == "") return;
|
|
// Debug.Log($"ANIM {animation}");
|
|
animator.speed *= this.reloadSpeedMultiplier;
|
|
CurrentWeapon.playAnimation(this.reloadSpeedMultiplier, animation);
|
|
animator.Play(animation);
|
|
|
|
StartCoroutine(ReloadCooldown());
|
|
}
|
|
|
|
public int getPlayerRights()
|
|
{
|
|
return this.playerRights;
|
|
}
|
|
|
|
public void UpdatePlayerOnMenuClose()
|
|
{
|
|
lastJumpTime = Time.time;
|
|
if (IsAlive())
|
|
{
|
|
updatePlayer = true;
|
|
}
|
|
}
|
|
|
|
private int id;
|
|
private string playerName;
|
|
private float lastShotTime;
|
|
|
|
[System.NonSerialized] public int rocketAmmo;
|
|
[System.NonSerialized] public int ammo;
|
|
public Animator animator;
|
|
private float lastNetworkUpdate;
|
|
public bool updatePlayer = false;
|
|
private bool canReload = true;
|
|
|
|
|
|
private int playerRights;
|
|
|
|
private int _maxHitPoints;
|
|
|
|
public int MaxHitPoints
|
|
{
|
|
get => _maxHitPoints;
|
|
set
|
|
{
|
|
_maxHitPoints = value;
|
|
playerHealthBar.ChangeMaxHealth(value, HitPoints);
|
|
}
|
|
}
|
|
|
|
public bool IsRunning => RunButtonPressed && RunInputLockCount == 0 && runEnergy >= 0.0f;
|
|
|
|
private int _hitPoints;
|
|
|
|
public int HitPoints
|
|
{
|
|
get => _hitPoints;
|
|
set
|
|
{
|
|
if (value < 0)
|
|
{
|
|
value = 0;
|
|
}
|
|
|
|
_hitPoints = value;
|
|
playerHealthBar.ChangeHealth(_hitPoints);
|
|
SetDeathAnimation();
|
|
}
|
|
}
|
|
|
|
public bool IsDead() => HitPoints <= 0;
|
|
public bool IsAlive() => !IsDead();
|
|
|
|
private void SetDeathAnimation()
|
|
{
|
|
animator.SetBool(animatorIsDead, IsDead());
|
|
}
|
|
|
|
public ChatBubble ChatBubble { get; internal set; }
|
|
|
|
//Total damage the player has done in the current game
|
|
public int damage;
|
|
|
|
public float audioVolume = 1.0f;
|
|
private float walkingSoundTimer;
|
|
|
|
//GameObject snow;
|
|
|
|
public float lastReload; // = Time.time;
|
|
public float reloadTime = 1.0f;
|
|
public float reloadSpeedMultiplier = 1.0f;
|
|
|
|
private TextMeshProUGUI playerNameTextMesh;
|
|
|
|
public GameObject interactableWorldObject;
|
|
public GameObject interactableGroundItem;
|
|
|
|
//knockback variables
|
|
public float knockbackTimer = -100.0f;
|
|
public float knockbackAngle = -1.0f;
|
|
private Vector2 knockbackVector;
|
|
private float knockbackForce = 35.0f;
|
|
public float knockbackForceMultiplier;
|
|
|
|
private GameObject audioManager;
|
|
private PlayerHealthBar playerHealthBar;
|
|
public byte jumpTrigger;
|
|
|
|
private GameObject weaponSlot;
|
|
private GameObject cameraWeaponSlot;
|
|
|
|
[System.NonSerialized] public GameObject currentWeapon;
|
|
private List<GameObject> firstPersonWeaponList = new List<GameObject>();
|
|
private readonly Dictionary<int, GameObject> firstPersonWeaponDictionary = new Dictionary<int, GameObject>();
|
|
|
|
[System.NonSerialized] public GameObject current_3D_Weapon;
|
|
private List<GameObject> thirdPersonWeaponList = new List<GameObject>();
|
|
private readonly Dictionary<int, GameObject> thirdPersonWeaponDictionary = new Dictionary<int, GameObject>();
|
|
} |