Photon BOLT 유니티 멀티게임 만들기 Webinar 4탄





LobbyManager.cs 소스입니다



using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Bolt.Matchmaking;
using UnityEngine.UI;
using UdpKit;

public class LobbyManager : Bolt.GlobalEventListener
{
public Text LogText;
public InputField SessionInput;
public InputField NickInput;

public void StartServer()
{
BoltLauncher.StartServer();
}

public override void BoltStartDone()
{
PlayerPrefs.SetString("nick", NickInput.text);
BoltMatchmaking.CreateSession(sessionID:SessionInput.text, sceneToLoad:"FPSGame");
}

public void StartClient()
{
BoltLauncher.StartClient();
}

public void JoinSession()
{
BoltMatchmaking.JoinSession(SessionInput.text);
}

public override void SessionListUpdated(Map<System.Guid, UdpSession> sessionList)
{
string log = "";
foreach (var session in sessionList)
{
UdpSession photonSession = session.Value;
if (photonSession.Source == UdpSessionSource.Photon)
log += $"{photonSession.HostName}\n";
}
LogText.text = log;
}
}














NetworkManager.cs 소스입니다



using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Bolt;

public class NetworkManager : GlobalEventListener
{
public static NetworkManager NM;
private void Awake() => NM = this;


public List<BoltEntity> players = new List<BoltEntity>();
public BoltEntity myPlayer;

public GameObject SpawnPrefab;


public override void SceneLoadLocalDone(string scene, IProtocolToken token)
{
var spawnPos = new Vector3(Random.Range(-5, 5), 0, 0);
myPlayer = BoltNetwork.Instantiate(SpawnPrefab, spawnPos, Quaternion.identity);
}

public override void OnEvent(JoinedEvent evnt)
{
Invoke("JoinedEventDelay", 0.2f);
}

void JoinedEventDelay() 
{
foreach (var player in players)
{
if (player != myPlayer)
player.GetComponent<PlayerScript>().HideObject();
}
}

public override void OnEvent(PlayerHitEvent evnt)
{
if (myPlayer == evnt.targetEntity) 
{
myPlayer.GetComponent<PlayerScript>().DamageHealth(evnt.damage);
}
}
}











PlayerScript.cs 소스입니다





using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using static NetworkManager;

public class PlayerScript : Bolt.EntityBehaviour<IFPSPlayerState>
{
public GameObject[] HideObjects;
public Transform arm;
public Slider HealthSlider;
public Slider UIHealthSlider;
public Transform canvas;
public Text NickText;


void Start() => NM.players.Add(entity);

void OnDestroy() => NM.players.Remove(entity);


public override void Attached()
{
CreateJoinedEvent();
state.SetTransforms(state.playerTransform, transform);
state.SetTransforms(state.armTransform, arm);
state.health = 100;
state.nick = PlayerPrefs.GetString("nick", "플레이어" + Random.Range(0,100));
state.AddCallback("health", HealthCallback);
state.AddCallback("nick", NickCallback);
}

void CreateJoinedEvent() 
{
var evnt = JoinedEvent.Create();
evnt.Send();
}

public void HideObject() 
{
foreach (var go in HideObjects) 
go.SetActive(false);
}

public void DamageHealth(float health) 
{
state.health -= health;
}

void HealthCallback() 
{
HealthSlider.value = state.health;
UIHealthSlider.value = state.health;

if (state.health <= 0) 
Respawn();
}

void NickCallback() 
{
NickText.text = state.nick;
}

void Respawn() 
{
state.health = 100;
transform.position = new Vector3(Random.Range(-5, 5), 0, 0);
}

void Update()
{
canvas.transform.LookAt(Camera.main.transform);
}
}










FPSControllerLPFP.cs 소스입니다




using System;
using System.Linq;
using UnityEngine;

namespace FPSControllerLPFP
{
    /// Manages a first person character
    [RequireComponent(typeof(Rigidbody))]
    [RequireComponent(typeof(CapsuleCollider))]
    [RequireComponent(typeof(AudioSource))]
    public class FpsControllerLPFP : Bolt.EntityBehaviour<IFPSPlayerState>
    {
#pragma warning disable 649
[Header("Arms")]
        [Tooltip("The transform component that holds the gun camera."), SerializeField]
        private Transform arms;

        [Tooltip("The position of the arms and gun camera relative to the fps controller GameObject."), SerializeField]
        private Vector3 armPosition;

[Header("Audio Clips")]
        [Tooltip("The audio clip that is played while walking."), SerializeField]
        private AudioClip walkingSound;

        [Tooltip("The audio clip that is played while running."), SerializeField]
        private AudioClip runningSound;

[Header("Movement Settings")]
        [Tooltip("How fast the player moves while walking and strafing."), SerializeField]
        private float walkingSpeed = 5f;

        [Tooltip("How fast the player moves while running."), SerializeField]
        private float runningSpeed = 9f;

        [Tooltip("Approximately the amount of time it will take for the player to reach maximum running or walking speed."), SerializeField]
        private float movementSmoothness = 0.125f;

        [Tooltip("Amount of force applied to the player when jumping."), SerializeField]
        private float jumpForce = 35f;

[Header("Look Settings")]
        [Tooltip("Rotation speed of the fps controller."), SerializeField]
        private float mouseSensitivity = 7f;

        [Tooltip("Approximately the amount of time it will take for the fps controller to reach maximum rotation speed."), SerializeField]
        private float rotationSmoothness = 0.05f;

        [Tooltip("Minimum rotation of the arms and camera on the x axis."),
         SerializeField]
        private float minVerticalAngle = -90f;

        [Tooltip("Maximum rotation of the arms and camera on the axis."),
         SerializeField]
        private float maxVerticalAngle = 90f;

        [Tooltip("The names of the axes and buttons for Unity's Input Manager."), SerializeField]
        private FpsInput input;
#pragma warning restore 649

        private Rigidbody _rigidbody;
        private CapsuleCollider _collider;
        private AudioSource _audioSource;
        private SmoothRotation _rotationX;
        private SmoothRotation _rotationY;
        private SmoothVelocity _velocityX;
        private SmoothVelocity _velocityZ;
        private bool _isGrounded;

        private readonly RaycastHit[] _groundCastResults = new RaycastHit[8];
        private readonly RaycastHit[] _wallCastResults = new RaycastHit[8];

        /// Initializes the FpsController on start.
        private void Start()
        {
            _rigidbody = GetComponent<Rigidbody>();
            _rigidbody.constraints = RigidbodyConstraints.FreezeRotation;
            _collider = GetComponent<CapsuleCollider>();
            _audioSource = GetComponent<AudioSource>();
arms = AssignCharactersCamera();
            _audioSource.clip = walkingSound;
            _audioSource.loop = true;
            _rotationX = new SmoothRotation(RotationXRaw);
            _rotationY = new SmoothRotation(RotationYRaw);
            _velocityX = new SmoothVelocity();
            _velocityZ = new SmoothVelocity();
            Cursor.lockState = CursorLockMode.Locked;
            ValidateRotationRestriction();
        }
        private Transform AssignCharactersCamera()
        {
            var t = transform;
arms.SetPositionAndRotation(t.position, t.rotation);
return arms;
        }
        
        /// Clamps <see cref="minVerticalAngle"/> and <see cref="maxVerticalAngle"/> to valid values and
        /// ensures that <see cref="minVerticalAngle"/> is less than <see cref="maxVerticalAngle"/>.
        private void ValidateRotationRestriction()
        {
            minVerticalAngle = ClampRotationRestriction(minVerticalAngle, -90, 90);
            maxVerticalAngle = ClampRotationRestriction(maxVerticalAngle, -90, 90);
            if (maxVerticalAngle >= minVerticalAngle) return;
            Debug.LogWarning("maxVerticalAngle should be greater than minVerticalAngle.");
            var min = minVerticalAngle;
            minVerticalAngle = maxVerticalAngle;
            maxVerticalAngle = min;
        }

        private static float ClampRotationRestriction(float rotationRestriction, float min, float max)
        {
            if (rotationRestriction >= min && rotationRestriction <= max) return rotationRestriction;
            var message = string.Format("Rotation restrictions should be between {0} and {1} degrees.", min, max);
            Debug.LogWarning(message);
            return Mathf.Clamp(rotationRestriction, min, max);
        }
        /// Checks if the character is on the ground.
        private void OnCollisionStay()
        {
            var bounds = _collider.bounds;
            var extents = bounds.extents;
            var radius = extents.x - 0.01f;
            Physics.SphereCastNonAlloc(bounds.center, radius, Vector3.down,
                _groundCastResults, extents.y - radius * 0.5f, ~0, QueryTriggerInteraction.Ignore);
            if (!_groundCastResults.Any(hit => hit.collider != null && hit.collider != _collider)) return;
            for (var i = 0; i < _groundCastResults.Length; i++)
            {
                _groundCastResults[i] = new RaycastHit();
            }

            _isGrounded = true;
        }
        /// Processes the character movement and the camera rotation every fixed framerate frame.
        private void FixedUpdate()
        {
            if (!entity.IsOwner) return;

            // FixedUpdate is used instead of Update because this code is dealing with physics and smoothing.
            RotateCameraAndCharacter();
            MoveCharacter();
            _isGrounded = false;
        }
        /// Moves the camera to the character, processes jumping and plays sounds every frame.
        private void Update()
        {
            if (!entity.IsOwner) return;

arms.position = transform.position + transform.TransformVector(armPosition);
            Jump();
            PlayFootstepSounds();
        }





private void RotateCameraAndCharacter()
        {
            var rotationX = _rotationX.Update(RotationXRaw, rotationSmoothness);
            var rotationY = _rotationY.Update(RotationYRaw, rotationSmoothness);
            var clampedY = RestrictVerticalRotation(rotationY);
            _rotationY.Current = clampedY;
var worldUp = arms.InverseTransformDirection(Vector3.up);
var rotation = arms.rotation *
                           Quaternion.AngleAxis(rotationX, worldUp) *
                           Quaternion.AngleAxis(clampedY, Vector3.left);
            transform.eulerAngles = new Vector3(0f, rotation.eulerAngles.y, 0f);
arms.rotation = rotation;
        }
        /// Returns the target rotation of the camera around the y axis with no smoothing.
        private float RotationXRaw
        {
            get { return input.RotateX * mouseSensitivity; }
        }
        /// Returns the target rotation of the camera around the x axis with no smoothing.
        private float RotationYRaw
        {
            get { return input.RotateY * mouseSensitivity; }
        }
        /// Clamps the rotation of the camera around the x axis
        /// between the <see cref="minVerticalAngle"/> and <see cref="maxVerticalAngle"/> values.
        private float RestrictVerticalRotation(float mouseY)
        {
var currentAngle = NormalizeAngle(arms.eulerAngles.x);
            var minY = minVerticalAngle + currentAngle;
            var maxY = maxVerticalAngle + currentAngle;
            return Mathf.Clamp(mouseY, minY + 0.01f, maxY - 0.01f);
        }
        /// Normalize an angle between -180 and 180 degrees.
        /// <param name="angleDegrees">angle to normalize</param>
        /// <returns>normalized angle</returns>
        private static float NormalizeAngle(float angleDegrees)
        {
            while (angleDegrees > 180f)
            {
                angleDegrees -= 360f;
            }

            while (angleDegrees <= -180f)
            {
                angleDegrees += 360f;
            }

            return angleDegrees;
        }

        private void MoveCharacter()
        {
            var direction = new Vector3(input.Move, 0f, input.Strafe).normalized;
            var worldDirection = transform.TransformDirection(direction);
            var velocity = worldDirection * (input.Run ? runningSpeed : walkingSpeed);
            //Checks for collisions so that the character does not stuck when jumping against walls.
            var intersectsWall = CheckCollisionsWithWalls(velocity);
            if (intersectsWall)
            {
                _velocityX.Current = _velocityZ.Current = 0f;
                return;
            }

            var smoothX = _velocityX.Update(velocity.x, movementSmoothness);
            var smoothZ = _velocityZ.Update(velocity.z, movementSmoothness);
            var rigidbodyVelocity = _rigidbody.velocity;
            var force = new Vector3(smoothX - rigidbodyVelocity.x, 0f, smoothZ - rigidbodyVelocity.z);
            _rigidbody.AddForce(force, ForceMode.VelocityChange);
        }

        private bool CheckCollisionsWithWalls(Vector3 velocity)
        {
            if (_isGrounded) return false;
            var bounds = _collider.bounds;
            var radius = _collider.radius;
            var halfHeight = _collider.height * 0.5f - radius * 1.0f;
            var point1 = bounds.center;
            point1.y += halfHeight;
            var point2 = bounds.center;
            point2.y -= halfHeight;
            Physics.CapsuleCastNonAlloc(point1, point2, radius, velocity.normalized, _wallCastResults,
                radius * 0.04f, ~0, QueryTriggerInteraction.Ignore);
            var collides = _wallCastResults.Any(hit => hit.collider != null && hit.collider != _collider);
            if (!collides) return false;
            for (var i = 0; i < _wallCastResults.Length; i++)
            {
                _wallCastResults[i] = new RaycastHit();
            }

            return true;
        }

        private void Jump()
        {
            if (!_isGrounded || !input.Jump) return;
            _isGrounded = false;
            _rigidbody.AddForce(Vector3.up * jumpForce, ForceMode.Impulse);
        }

        private void PlayFootstepSounds()
        {
            if (_isGrounded && _rigidbody.velocity.sqrMagnitude > 0.1f)
            {
                _audioSource.clip = input.Run ? runningSound : walkingSound;
                if (!_audioSource.isPlaying)
                {
                    _audioSource.Play();
                }
            }
            else
            {
                if (_audioSource.isPlaying)
                {
                    _audioSource.Pause();
                }
            }
        }
        /// A helper for assistance with smoothing the camera rotation.
        private class SmoothRotation
        {
            private float _current;
            private float _currentVelocity;

            public SmoothRotation(float startAngle)
            {
                _current = startAngle;
            }
            /// Returns the smoothed rotation.
            public float Update(float target, float smoothTime)
            {
                return _current = Mathf.SmoothDampAngle(_current, target, ref _currentVelocity, smoothTime);
            }

            public float Current
            {
                set { _current = value; }
            }
        }
        /// A helper for assistance with smoothing the movement.
        private class SmoothVelocity
        {
            private float _current;
            private float _currentVelocity;

            /// Returns the smoothed velocity.
            public float Update(float target, float smoothTime)
            {
                return _current = Mathf.SmoothDamp(_current, target, ref _currentVelocity, smoothTime);
            }

            public float Current
            {
                set { _current = value; }
            }
        }
        /// Input mappings
        [Serializable]
        private class FpsInput
        {
            [Tooltip("The name of the virtual axis mapped to rotate the camera around the y axis."),
             SerializeField]
            private string rotateX = "Mouse X";

            [Tooltip("The name of the virtual axis mapped to rotate the camera around the x axis."),
             SerializeField]
            private string rotateY = "Mouse Y";

            [Tooltip("The name of the virtual axis mapped to move the character back and forth."),
             SerializeField]
            private string move = "Horizontal";

            [Tooltip("The name of the virtual axis mapped to move the character left and right."),
             SerializeField]
            private string strafe = "Vertical";

            [Tooltip("The name of the virtual button mapped to run."),
             SerializeField]
            private string run = "Fire3";

            [Tooltip("The name of the virtual button mapped to jump."),
             SerializeField]
            private string jump = "Jump";

            /// Returns the value of the virtual axis mapped to rotate the camera around the y axis.
            public float RotateX
            {
                get { return Input.GetAxisRaw(rotateX); }
            }
         
            /// Returns the value of the virtual axis mapped to rotate the camera around the x axis.        
            public float RotateY
            {
                get { return Input.GetAxisRaw(rotateY); }
            }
        
            /// Returns the value of the virtual axis mapped to move the character back and forth.        
            public float Move
            {
                get { return Input.GetAxisRaw(move); }
            }
       
            /// Returns the value of the virtual axis mapped to move the character left and right.         
            public float Strafe
            {
                get { return Input.GetAxisRaw(strafe); }
            }
    
            /// Returns true while the virtual button mapped to run is held down.          
            public bool Run
            {
                get { return Input.GetButton(run); }
            }
     
            /// Returns true during the frame the user pressed down the virtual button mapped to jump.          
            public bool Jump
            {
                get { return Input.GetButtonDown(jump); }
            }
        }
    }
}













AutomaticGunScriptLPFP.cs 소스입니다





using UnityEngine;
using System.Collections;
using UnityEngine.UI;

// ----- Low Poly FPS Pack Free Version -----
public class AutomaticGunScriptLPFP : Bolt.EntityBehaviour<IFPSPlayerState> {

//Animator component attached to weapon
Animator anim;

[Header("Gun Camera")]
//Main gun camera
public Camera gunCamera;

[Header("Gun Camera Options")]
//How fast the camera field of view changes when aiming 
[Tooltip("How fast the camera field of view changes when aiming.")]
public float fovSpeed = 15.0f;
//Default camera field of view
[Tooltip("Default value for camera field of view (40 is recommended).")]
public float defaultFov = 40.0f;

public float aimFov = 25.0f;

[Header("UI Weapon Name")]
[Tooltip("Name of the current weapon, shown in the game UI.")]
public string weaponName;
private string storedWeaponName;

[Header("Weapon Sway")]
//Enables weapon sway
[Tooltip("Toggle weapon sway.")]
public bool weaponSway;

public float swayAmount = 0.02f;
public float maxSwayAmount = 0.06f;
public float swaySmoothValue = 4.0f;

private Vector3 initialSwayPosition;

//Used for fire rate
private float lastFired;
[Header("Weapon Settings")]
//How fast the weapon fires, higher value means faster rate of fire
[Tooltip("How fast the weapon fires, higher value means faster rate of fire.")]
public float fireRate;
//Eanbles auto reloading when out of ammo
[Tooltip("Enables auto reloading when out of ammo.")]
public bool autoReload;
//Delay between shooting last bullet and reloading
public float autoReloadDelay;
//Check if reloading
private bool isReloading;

//Holstering weapon
private bool hasBeenHolstered = false;
//If weapon is holstered
private bool holstered;
//Check if running
private bool isRunning;
//Check if aiming
private bool isAiming;
//Check if walking
private bool isWalking;
//Check if inspecting weapon
private bool isInspecting;

//How much ammo is currently left
private int currentAmmo;
//Totalt amount of ammo
[Tooltip("How much ammo the weapon should have.")]
public int ammo;
//Check if out of ammo
private bool outOfAmmo;

[Header("Bullet Settings")]
//Bullet
[Tooltip("How much force is applied to the bullet when shooting.")]
public float bulletForce = 400.0f;
[Tooltip("How long after reloading that the bullet model becomes visible " +
"again, only used for out of ammo reload animations.")]
public float showBulletInMagDelay = 0.6f;
[Tooltip("The bullet model inside the mag, not used for all weapons.")]
public SkinnedMeshRenderer bulletInMagRenderer;

[Header("Grenade Settings")]
public float grenadeSpawnDelay = 0.35f;

[Header("Muzzleflash Settings")]
public bool randomMuzzleflash = false;
//min should always bee 1
private int minRandomValue = 1;

[Range(2, 25)]
public int maxRandomValue = 5;

private int randomMuzzleflashValue;

public bool enableMuzzleflash = true;
public ParticleSystem muzzleParticles;
public bool enableSparks = true;
public ParticleSystem sparkParticles;
public int minSparkEmission = 1;
public int maxSparkEmission = 7;

[Header("Muzzleflash Light Settings")]
public Light muzzleflashLight;
public float lightDuration = 0.02f;

[Header("Audio Source")]
//Main audio source
public AudioSource mainAudioSource;
//Audio source used for shoot sound
public AudioSource shootAudioSource;

[Header("UI Components")]
public Text timescaleText;
public Text currentWeaponText;
public Text currentAmmoText;
public Text totalAmmoText;

[System.Serializable]
public class prefabs
{  
[Header("Prefabs")]
public Transform bulletPrefab;
public Transform casingPrefab;
public Transform grenadePrefab;
}
public prefabs Prefabs;
[System.Serializable]
public class spawnpoints
{  
[Header("Spawnpoints")]
//Array holding casing spawn points 
//(some weapons use more than one casing spawn)
//Casing spawn point array
public Transform casingSpawnPoint;
//Bullet prefab spawn from this point
public Transform bulletSpawnPoint;

public Transform grenadeSpawnPoint;
}
public spawnpoints Spawnpoints;

[System.Serializable]
public class soundClips
{
public AudioClip shootSound;
public AudioClip takeOutSound;
public AudioClip holsterSound;
public AudioClip reloadSoundOutOfAmmo;
public AudioClip reloadSoundAmmoLeft;
public AudioClip aimSound;
}
public soundClips SoundClips;

private bool soundHasPlayed = false;



private void Awake () {
//Set the animator component
anim = GetComponent<Animator>();
//Set current ammo to total ammo value
currentAmmo = ammo;

muzzleflashLight.enabled = false;
}

public override void Attached()
{
state.SetAnimator(anim);
state.AddCallback("AnimPlay", AnimPlayCallback);
state.OnmuzzleParticleTirgger += MuzzleParticleCallback;
state.OnsparkParticleTirgger += SparkParticleCallback;
}

void AnimPlayCallback() 
{
if (state.AnimPlay != "o") 
{
state.Animator.Play(state.AnimPlay);
Invoke("AnimPlayDelay", 0.05f);
}
}

void AnimPlayDelay() => state.AnimPlay = "o";

void MuzzleParticleCallback() 
{
muzzleParticles.Emit(1);
StartCoroutine(MuzzleFlashLight());
}

void SparkParticleCallback() 
{
sparkParticles.Emit(Random.Range(minSparkEmission, maxSparkEmission));
}

void PlayerHitCheck() 
{
Physics.Raycast(Spawnpoints.bulletSpawnPoint.position, Spawnpoints.bulletSpawnPoint.forward, out RaycastHit hit);
if (hit.collider != null && hit.collider.CompareTag("FPSPlayer")) 
{
//hit.collider.gameObject.GetComponent<PlayerScript>().DamageHealth(3);
var evnt = PlayerHitEvent.Create();
evnt.targetEntity = hit.collider.gameObject.GetComponent<BoltEntity>();
evnt.damage = 3;
evnt.Send();
}
}


private void Start () {
//Save the weapon name
storedWeaponName = weaponName;
//Get weapon name from string to text
currentWeaponText.text = weaponName;
//Set total ammo text from total ammo int
totalAmmoText.text = ammo.ToString();

//Weapon sway
initialSwayPosition = transform.localPosition;

//Set the shoot sound to audio source
shootAudioSource.clip = SoundClips.shootSound;
}

private void LateUpdate () {

if (!entity.IsOwner) return;

//Weapon sway
if (weaponSway == true) 
{
float movementX = -Input.GetAxis ("Mouse X") * swayAmount;
float movementY = -Input.GetAxis ("Mouse Y") * swayAmount;
//Clamp movement to min and max values
movementX = Mathf.Clamp 
(movementX, -maxSwayAmount, maxSwayAmount);
movementY = Mathf.Clamp 
(movementY, -maxSwayAmount, maxSwayAmount);
//Lerp local pos
Vector3 finalSwayPosition = new Vector3 
(movementX, movementY, 0);
transform.localPosition = Vector3.Lerp 
(transform.localPosition, finalSwayPosition + 
initialSwayPosition, Time.deltaTime * swaySmoothValue);
}
}
private void Update () {

if (!entity.IsOwner) return;


//if(Input.GetKeyDown(KeyCode.O))


//Aiming
//Toggle camera FOV when right click is held down
if (Input.GetButton("Fire2") && !isReloading && !isRunning && !isInspecting) 
{
isAiming = true;
//Start aiming
state.Aim = true;
anim.SetBool("Aim", state.Aim);
//anim.SetBool ("Aim", true);

//When right click is released
gunCamera.fieldOfView = Mathf.Lerp(gunCamera.fieldOfView,
aimFov,fovSpeed * Time.deltaTime);

if (!soundHasPlayed) 
{
mainAudioSource.clip = SoundClips.aimSound;
mainAudioSource.Play ();
soundHasPlayed = true;
}
else 
{
//When right click is released
gunCamera.fieldOfView = Mathf.Lerp(gunCamera.fieldOfView,
defaultFov,fovSpeed * Time.deltaTime);

isAiming = false;
//Stop aiming
state.Aim = false;
anim.SetBool("Aim", state.Aim);
//anim.SetBool ("Aim", false);
soundHasPlayed = false;
}
//Aiming end

//If randomize muzzleflash is true, genereate random int values
if (randomMuzzleflash == true) 
{
randomMuzzleflashValue = Random.Range (minRandomValue, maxRandomValue);
}

//Timescale settings
//Change timescale to normal when 1 key is pressed
if (Input.GetKeyDown (KeyCode.Alpha1)) 
{
Time.timeScale = 1.0f;
timescaleText.text = "1.0";
}
//Change timesccale to 50% when 2 key is pressed
if (Input.GetKeyDown (KeyCode.Alpha2)) 
{
Time.timeScale = 0.5f;
timescaleText.text = "0.5";
}
//Change timescale to 25% when 3 key is pressed
if (Input.GetKeyDown (KeyCode.Alpha3)) 
{
Time.timeScale = 0.25f;
timescaleText.text = "0.25";
}
//Change timescale to 10% when 4 key is pressed
if (Input.GetKeyDown (KeyCode.Alpha4)) 
{
Time.timeScale = 0.1f;
timescaleText.text = "0.1";
}
//Pause game when 5 key is pressed
if (Input.GetKeyDown (KeyCode.Alpha5)) 
{
Time.timeScale = 0.0f;
timescaleText.text = "0.0";
}

//Set current ammo text from ammo int
currentAmmoText.text = currentAmmo.ToString ();

//Continosuly check which animation 
//is currently playing
AnimationCheck ();

//Play knife attack 1 animation when Q key is pressed
if (Input.GetKeyDown (KeyCode.Q) && !isInspecting) 
{
state.AnimPlay = "Knife Attack 1";
//anim.Play ("Knife Attack 1", 0, 0f);
}
//Play knife attack 2 animation when F key is pressed
if (Input.GetKeyDown (KeyCode.F) && !isInspecting) 
{
state.AnimPlay = "Knife Attack 2";
//anim.Play ("Knife Attack 2", 0, 0f);
}
//Throw grenade when pressing G key
if (Input.GetKeyDown (KeyCode.G) && !isInspecting) 
{
StartCoroutine (GrenadeSpawnDelay ());
//Play grenade throw animation
state.AnimPlay = "GrenadeThrow";
//anim.Play("GrenadeThrow", 0, 0.0f);
}

//If out of ammo
if (currentAmmo == 0) 
{
//Show out of ammo text
currentWeaponText.text = "OUT OF AMMO";
//Toggle bool
outOfAmmo = true;
//Auto reload if true
if (autoReload == true && !isReloading) 
{
StartCoroutine (AutoReload ());
}
else 
{
//When ammo is full, show weapon name again
currentWeaponText.text = storedWeaponName.ToString ();
//Toggle bool
outOfAmmo = false;
//anim.SetBool ("Out Of Ammo", false);
}
//AUtomatic fire
//Left click hold 
if (Input.GetMouseButton (0) && !outOfAmmo && !isReloading && !isInspecting && !isRunning) 
{
//Shoot automatic
if (Time.time - lastFired > 1 / fireRate) 
{
lastFired = Time.time;

//Remove 1 bullet from ammo
currentAmmo -= 1;

shootAudioSource.clip = SoundClips.shootSound;
shootAudioSource.Play ();

if (!isAiming) //if not aiming
{
state.AnimPlay = "Fire";
//anim.Play ("Fire", 0, 0f);
//If random muzzle is false
if (!randomMuzzleflash && 
enableMuzzleflash == true) 
{
//state.onmuzzleParticleTirgger().Invoke();

state.muzzleParticleTirgger();
//muzzleParticles.Emit (1);
//Light flash start
//StartCoroutine(MuzzleFlashLight());
else if (randomMuzzleflash == true)
{
//Only emit if random value is 1
if (randomMuzzleflashValue == 1) 
{
if (enableSparks == true) 
{
//Emit random amount of spark particles
state.sparkParticleTirgger();
//sparkParticles.Emit (Random.Range (minSparkEmission, maxSparkEmission));
}
if (enableMuzzleflash == true) 
{
state.muzzleParticleTirgger();
//muzzleParticles.Emit (1);
//Light flash start
//StartCoroutine (MuzzleFlashLight ());
}
}
}
else //if aiming
{
state.AnimPlay = "Aim Fire";
//anim.Play ("Aim Fire", 0, 0f);

//If random muzzle is false
if (!randomMuzzleflash) {
state.muzzleParticleTirgger();
//muzzleParticles.Emit (1);
//If random muzzle is true
else if (randomMuzzleflash == true) 
{
//Only emit if random value is 1
if (randomMuzzleflashValue == 1) 
{
if (enableSparks == true) 
{
//Emit random amount of spark particles
sparkParticles.Emit (Random.Range (minSparkEmission, maxSparkEmission));
}
if (enableMuzzleflash == true) 
{
state.muzzleParticleTirgger();
//muzzleParticles.Emit (1);
//Light flash start
//StartCoroutine (MuzzleFlashLight ());
}
}
}
}

//Spawn bullet from bullet spawnpoint
Transform bullet = BoltNetwork.Instantiate (
Prefabs.bulletPrefab.gameObject,
Spawnpoints.bulletSpawnPoint.transform.position,
Spawnpoints.bulletSpawnPoint.transform.rotation).transform;

//Add velocity to the bullet
bullet.GetComponent<Rigidbody>().velocity = 
bullet.transform.forward * bulletForce;

//Spawn casing prefab at spawnpoint
Instantiate (Prefabs.casingPrefab.gameObject, 
Spawnpoints.casingSpawnPoint.transform.position, 
Spawnpoints.casingSpawnPoint.transform.rotation);

PlayerHitCheck();
}
}

//Inspect weapon when T key is pressed
if (Input.GetKeyDown (KeyCode.T)) 
{
state.Inspect();
//anim.SetTrigger ("Inspect");
}

//Toggle weapon holster when E key is pressed
if (Input.GetKeyDown (KeyCode.E) && !hasBeenHolstered) 
{
holstered = true;

mainAudioSource.clip = SoundClips.holsterSound;
mainAudioSource.Play();

hasBeenHolstered = true;
else if (Input.GetKeyDown (KeyCode.E) && hasBeenHolstered) 
{
holstered = false;

mainAudioSource.clip = SoundClips.takeOutSound;
mainAudioSource.Play ();

hasBeenHolstered = false;
}
//Holster anim toggle
if (holstered == true) 
{
state.Holster = true;
anim.SetBool("Holster", state.Holster);
//anim.SetBool ("Holster", true);
else 
{
state.Holster = false;
anim.SetBool("Holster", state.Holster);
//anim.SetBool ("Holster", false);
}

//Reload 
if (Input.GetKeyDown (KeyCode.R) && !isReloading && !isInspecting) 
{
//Reload
Reload ();
}

//Walking when pressing down WASD keys
if (Input.GetKey (KeyCode.W) && !isRunning || 
Input.GetKey (KeyCode.A) && !isRunning || 
Input.GetKey (KeyCode.S) && !isRunning || 
Input.GetKey (KeyCode.D) && !isRunning) 
{
state.Walk = true;
anim.SetBool("Walk", state.Walk);
//anim.SetBool ("Walk", true);
} else {
state.Walk = false;
anim.SetBool("Walk", state.Walk);
//anim.SetBool ("Walk", false);
}

//Running when pressing down W and Left Shift key
if ((Input.GetKey (KeyCode.W) && Input.GetKey (KeyCode.LeftShift))) 
{
isRunning = true;
} else {
isRunning = false;
}
//Run anim toggle
if (isRunning == true) 
{
state.Run = true;
anim.SetBool("Run", state.Run);
//anim.SetBool ("Run", true);
else 
{
state.Run = false;
anim.SetBool("Run", state.Run);
//anim.SetBool ("Run", false);
}
}

private IEnumerator GrenadeSpawnDelay () {
//Wait for set amount of time before spawning grenade
yield return new WaitForSeconds (grenadeSpawnDelay);
//Spawn grenade prefab at spawnpoint
BoltNetwork.Instantiate(Prefabs.grenadePrefab.gameObject, 
Spawnpoints.grenadeSpawnPoint.transform.position, 
Spawnpoints.grenadeSpawnPoint.transform.rotation);
}

private IEnumerator AutoReload () {
//Wait set amount of time
yield return new WaitForSeconds (autoReloadDelay);

if (outOfAmmo == true) 
{
//Play diff anim if out of ammo
state.AnimPlay = "Reload Out Of Ammo";
//anim.Play ("Reload Out Of Ammo", 0, 0f);

mainAudioSource.clip = SoundClips.reloadSoundOutOfAmmo;
mainAudioSource.Play ();

//If out of ammo, hide the bullet renderer in the mag
//Do not show if bullet renderer is not assigned in inspector
if (bulletInMagRenderer != null) 
{
bulletInMagRenderer.GetComponent
<SkinnedMeshRenderer> ().enabled = false;
//Start show bullet delay
StartCoroutine (ShowBulletInMag ());
}
//Restore ammo when reloading
currentAmmo = ammo;
outOfAmmo = false;
}

//Reload
private void Reload () {
if (outOfAmmo == true) 
{
//Play diff anim if out of ammo
state.AnimPlay = "Reload Out Of Ammo";
//anim.Play ("Reload Out Of Ammo", 0, 0f);

mainAudioSource.clip = SoundClips.reloadSoundOutOfAmmo;
mainAudioSource.Play ();

//If out of ammo, hide the bullet renderer in the mag
//Do not show if bullet renderer is not assigned in inspector
if (bulletInMagRenderer != null) 
{
bulletInMagRenderer.GetComponent
<SkinnedMeshRenderer> ().enabled = false;
//Start show bullet delay
StartCoroutine (ShowBulletInMag ());
}
else 
{
//Play diff anim if ammo left
state.AnimPlay = "Reload Ammo Left";
//anim.Play ("Reload Ammo Left", 0, 0f);

mainAudioSource.clip = SoundClips.reloadSoundAmmoLeft;
mainAudioSource.Play ();

//If reloading when ammo left, show bullet in mag
//Do not show if bullet renderer is not assigned in inspector
if (bulletInMagRenderer != null) 
{
bulletInMagRenderer.GetComponent
<SkinnedMeshRenderer> ().enabled = true;
}
}
//Restore ammo when reloading
currentAmmo = ammo;
outOfAmmo = false;
}

//Enable bullet in mag renderer after set amount of time
private IEnumerator ShowBulletInMag () {
//Wait set amount of time before showing bullet in mag
yield return new WaitForSeconds (showBulletInMagDelay);
bulletInMagRenderer.GetComponent<SkinnedMeshRenderer> ().enabled = true;
}

//Show light when shooting, then disable after set amount of time
private IEnumerator MuzzleFlashLight () {
muzzleflashLight.enabled = true;
yield return new WaitForSeconds (lightDuration);
muzzleflashLight.enabled = false;
}

//Check current animation playing
private void AnimationCheck () {
//Check if reloading
//Check both animations
if (anim.GetCurrentAnimatorStateInfo (0).IsName ("Reload Out Of Ammo") || 
anim.GetCurrentAnimatorStateInfo (0).IsName ("Reload Ammo Left")) 
{
isReloading = true;
else 
{
isReloading = false;
}

//Check if inspecting weapon
if (anim.GetCurrentAnimatorStateInfo (0).IsName ("Inspect")) 
{
isInspecting = true;
else 
{
isInspecting = false;
}
}
}
// ----- Low Poly FPS Pack Free Version -----