How To Make A Mmo Camera In Unity
First-Person Shooter (FPS) is a subgenre of shooter games where the role player is controlled from a first-person perspective.
To make an FPS game in Unity we will need a player controller, an array of items (weapons in this case), and the enemies.
Step i: Create the Player Controller
Hither we will create a controller that will be used by our actor.
- Create a new Game Object (Game Object -> Create Empty) and proper noun it "Player"
- Create new Sheathing (Game Object -> 3D Object -> Capsule) and motility it inside "Role player" Object
- Remove Capsule Collider component from Capsule and modify its position to (0, 1, 0)
- Move the Main Camera within "Player" Object and change its position to (0, 1.64, 0)
- Create a new script, proper name it "SC_CharacterController" and paste the code below inside it:
SC_CharacterController.cs
using UnityEngine; [RequireComponent(typeof(CharacterController))] public class SC_CharacterController : MonoBehaviour { public float speed = 7.5f; public float jumpSpeed = 8.0f; public bladder gravity = 20.0f; public Camera playerCamera; public float lookSpeed = 2.0f; public bladder lookXLimit = 45.0f; CharacterController characterController; Vector3 moveDirection = Vector3.zero; Vector2 rotation = Vector2.zero; [HideInInspector] public bool canMove = true; void Start() { characterController = GetComponent<CharacterController>(); rotation.y = transform.eulerAngles.y; } void Update() { if (characterController.isGrounded) { // We are grounded, and then recalculate move direction based on axes Vector3 forrard = transform.TransformDirection(Vector3.forward); Vector3 right = transform.TransformDirection(Vector3.correct); float curSpeedX = canMove ? speed * Input.GetAxis("Vertical") : 0; float curSpeedY = canMove ? speed * Input.GetAxis("Horizontal") : 0; moveDirection = (forwards * curSpeedX) + (right * curSpeedY); if (Input.GetButton("Leap") && canMove) { moveDirection.y = jumpSpeed; } } // Apply gravity. Gravity is multiplied past deltaTime twice (once here, and one time below // when the moveDirection is multiplied by deltaTime). This is considering gravity should be practical // as an acceleration (ms^-2) moveDirection.y -= gravity * Time.deltaTime; // Move the controller characterController.Move(moveDirection * Time.deltaTime); // Role player and Camera rotation if (canMove) { rotation.y += Input.GetAxis("Mouse 10") * lookSpeed; rotation.x += -Input.GetAxis("Mouse Y") * lookSpeed; rotation.ten = Mathf.Clamp(rotation.x, -lookXLimit, lookXLimit); playerCamera.transform.localRotation = Quaternion.Euler(rotation.x, 0, 0); transform.eulerAngles = new Vector2(0, rotation.y); } } }
- Attach SC_CharacterController script to "Player" Object (You will notice that information technology also added another component called Character Controller, alter its center value to (0, 1, 0))
- Assign the Primary Photographic camera to the Player Camera variable in SC_CharacterController
The Histrion controller is at present ready:
Pace 2: Create the Weapon Organisation
The player weapon system will consist of 3 components: a Weapon manager, a Weapon script, and a Bullet script.
- Create a new script, proper name it "SC_WeaponManager" and paste the code below within it:
SC_WeaponManager.cs
using UnityEngine; public class SC_WeaponManager : MonoBehaviour { public Camera playerCamera; public SC_Weapon primaryWeapon; public SC_Weapon secondaryWeapon; [HideInInspector] public SC_Weapon selectedWeapon; // Start is called before the commencement frame update void Start() { //At the start we enable the main weapon and disable the secondary primaryWeapon.ActivateWeapon(truthful); secondaryWeapon.ActivateWeapon(false); selectedWeapon = primaryWeapon; primaryWeapon.manager = this; secondaryWeapon.manager = this; } // Update is called once per frame void Update() { //Select secondary weapon when pressing ane if (Input.GetKeyDown(KeyCode.Alpha1)) { primaryWeapon.ActivateWeapon(false); secondaryWeapon.ActivateWeapon(truthful); selectedWeapon = secondaryWeapon; } //Select primary weapon when pressing two if (Input.GetKeyDown(KeyCode.Alpha2)) { primaryWeapon.ActivateWeapon(true); secondaryWeapon.ActivateWeapon(false); selectedWeapon = primaryWeapon; } } }
- Create a new script, proper name it "SC_Weapon" and paste the code below within it:
SC_Weapon.cs
using Organization.Collections; using UnityEngine; [RequireComponent(typeof(AudioSource))] public form SC_Weapon : MonoBehaviour { public bool singleFire = false; public bladder fireRate = 0.1f; public GameObject bulletPrefab; public Transform firePoint; public int bulletsPerMagazine = xxx; public float timeToReload = 1.5f; public float weaponDamage = 15; //How much damage should this weapon deal public AudioClip fireAudio; public AudioClip reloadAudio; [HideInInspector] public SC_WeaponManager manager; float nextFireTime = 0; bool canFire = truthful; int bulletsPerMagazineDefault = 0; AudioSource audioSource; // Get-go is chosen before the first frame update void Start() { bulletsPerMagazineDefault = bulletsPerMagazine; audioSource = GetComponent<AudioSource>(); audioSource.playOnAwake = faux; //Make sound 3D audioSource.spatialBlend = 1f; } // Update is chosen once per frame void Update() { if (Input.GetMouseButtonDown(0) && singleFire) { Fire(); } if (Input.GetMouseButton(0) && !singleFire) { Fire(); } if (Input.GetKeyDown(KeyCode.R) && canFire) { StartCoroutine(Reload()); } } void Burn down() { if (canFire) { if (Time.time > nextFireTime) { nextFireTime = Time.time + fireRate; if (bulletsPerMagazine > 0) { //Betoken burn signal at the electric current center of Camera Vector3 firePointPointerPosition = manager.playerCamera.transform.position + managing director.playerCamera.transform.forward * 100; RaycastHit hit; if (Physics.Raycast(managing director.playerCamera.transform.position, director.playerCamera.transform.forrad, out hit, 100)) { firePointPointerPosition = hitting.point; } firePoint.LookAt(firePointPointerPosition); //Burn GameObject bulletObject = Instantiate(bulletPrefab, firePoint.position, firePoint.rotation); SC_Bullet bullet = bulletObject.GetComponent<SC_Bullet>(); //Set bullet impairment according to weapon harm value bullet.SetDamage(weaponDamage); bulletsPerMagazine--; audioSource.prune = fireAudio; audioSource.Play(); } else { StartCoroutine(Reload()); } } } } IEnumerator Reload() { canFire = fake; audioSource.prune = reloadAudio; audioSource.Play(); yield return new WaitForSeconds(timeToReload); bulletsPerMagazine = bulletsPerMagazineDefault; canFire = true; } //Called from SC_WeaponManager public void ActivateWeapon(bool actuate) { StopAllCoroutines(); canFire = true; gameObject.SetActive(activate); } }
- Create a new script, name it "SC_Bullet" and paste the code below inside information technology:
SC_Bullet.cs
using System.Collections; using UnityEngine; public course SC_Bullet : MonoBehaviour { public bladder bulletSpeed = 345; public bladder hitForce = 50f; public float destroyAfter = 3.5f; float currentTime = 0; Vector3 newPos; Vector3 oldPos; bool hasHit = false; float damagePoints; // Start is chosen before the starting time frame update IEnumerator Start() { newPos = transform.position; oldPos = newPos; while (currentTime < destroyAfter && !hasHit) { Vector3 velocity = transform.frontwards * bulletSpeed; newPos += velocity * Fourth dimension.deltaTime; Vector3 direction = newPos - oldPos; float distance = direction.magnitude; RaycastHit hit; // Check if we hit annihilation on the way if (Physics.Raycast(oldPos, direction, out hit, altitude)) { if (hitting.rigidbody != goose egg) { hitting.rigidbody.AddForce(direction * hitForce); IEntity npc = hit.transform.GetComponent<IEntity>(); if (npc != null) { //Apply damage to NPC npc.ApplyDamage(damagePoints); } } newPos = hit.point; //Adjust new position StartCoroutine(DestroyBullet()); } currentTime += Time.deltaTime; yield return new WaitForFixedUpdate(); transform.position = newPos; oldPos = newPos; } if (!hasHit) { StartCoroutine(DestroyBullet()); } } IEnumerator DestroyBullet() { hasHit = true; yield return new WaitForSeconds(0.5f); Destroy(gameObject); } //Fix how much impairment this bullet volition deal public void SetDamage(float points) { damagePoints = points; } }
Now, you will detect that SC_Bullet script has some errors. That's because nosotros have one final thing to do, which is to define IEntity interface.
Interfaces in C# are useful for when you demand to brand sure that the script which uses information technology, has certain methods implemented.
The IEntity interface will have i method which is ApplyDamage, that's later on will be used to inflict damage to enemies and our player.
- Create a new script, name it "SC_InterfaceManager" and paste the code beneath within it:
SC_InterfaceManager.cs
//Entity interafce interface IEntity { void ApplyDamage(bladder points); }
Setting Upwards a Weapon Manager
Weapon managing director is an Object that volition reside under the Main Camera Object and will comprise all the weapons.
- Create a new GameObject and proper name it "WeaponManager"
- Motility the WeaponManager inside the Actor Main Camera and alter its position to (0, 0, 0)
- Attach SC_WeaponManager script to "WeaponManager"
- Assign the Chief Camera to the Player Camera variable in SC_WeaponManager
Setting Upward a Burglarize
- Drag and drib your gun model into the scene (or simply create a Cube and stretch information technology if yous do not take a model withal).
- Scale the model so its size is relative to a Player Capsule
In my case I will be using a custom-made Rifle model (BERGARA BA13):
- Create a new GameObject and name it "Rifle" then motion the rifle model inside it
- Motility the "Rifle" Object inside the "WeaponManager" Object and place it in front of the Photographic camera like this:
To fix the object clipping, simply change the Photographic camera'southward near clipping plane to something smaller (in my case I fix information technology to 0.15):
Much better.
- Attach SC_Weapon script to a Rifle Object (You lot volition notice that it as well added an Audio Source component, this is needed to play the burn and reload audios).
As you can run into, SC_Weapon has 4 variables to assign. You can assign Fire audio and Reload audio variables correct away if you accept suitable Audio Clips in your project.
The Bullet Prefab variable will be explained later in this tutorial.
For now, we will but assign the Fire indicate variable:
- Create a new GameObject, rename it to "FirePoint" and move information technology within Rifle Object. Place it right in front of the barrel or slightly within, like this:
- Assign FirePoint Transform to a Burn down point variable at SC_Weapon
- Assign Burglarize to a Secondary Weapon variable in SC_WeaponManager script
Setting Up a Submachinegun
- Duplicate the Rifle Object and rename it to Submachinegun
- Replace the gun model inside it with a different model (In my example I volition use the custom-fabricated model of TAVOR X95)
- Motion Fire Betoken transform till information technology fits the new model
- Assign Submachinegun to a Primary Weapon variable in SC_WeaponManager script
Setting Up a Bullet Prefab
Bullet prefab will be spawned according to a Weapon'south burn down rate and will use Raycast to observe whether information technology hitting something and inflict damage.
- Create a new GameObject and name it "Bullet"
- Add Trail Renderer component to information technology and modify its Time variable to 0.1.
- Set the Width curve to a lower value (ex. Commencement 0.1 terminate 0), to add a trail that pointy wait
- Create new Textile and name it bullet_trail_material and change its Shader to Particles/Additive
- Assign a newly created textile to a Trail Renderer
- Modify the Color of Trail Renderer to something different (ex. Beginning: Brilliant Orange End: Darker Orange)
- Save the Bullet Object to Prefab and delete it from the Scene.
- Assign a newly created Prefab (drag & drop from the Project view) to Rifle and Submachinegun Bullet Prefab variable
Submachinegun:
Burglarize:
The weapons are now prepare.
Footstep iii: Create the Enemy AI
The enemies will be uncomplicated Cubes that follow the Role player and attack one time they are close enough. They will attack in waves, with each wave having more enemies to eliminate.
Setting Up Enemy AI
Below I take created 2 variations of the Cube (The Left one is for the alive example and the Right one will exist spawned once the enemy is killed):
- Add a Rigidbody component to both dead and alive instances
- Salve the Dead Instance to Prefab and delete it from Scene.
Now, the live example will need a couple more than components to exist able to navigate the game level and inflict damage to the Player.
- Create a new script and name information technology "SC_NPCEnemy" and so paste the code below inside it:
SC_NPCEnemy.cs
using UnityEngine; using UnityEngine.AI; [RequireComponent(typeof(NavMeshAgent))] public class SC_NPCEnemy : MonoBehaviour, IEntity { public float attackDistance = 3f; public float movementSpeed = 4f; public float npcHP = 100; //How much harm will npc deal to the player public float npcDamage = v; public float attackRate = 0.5f; public Transform firePoint; public GameObject npcDeadPrefab; [HideInInspector] public Transform playerTransform; [HideInInspector] public SC_EnemySpawner es; NavMeshAgent amanuensis; bladder nextAttackTime = 0; // Showtime is called before the kickoff frame update void Get-go() { agent = GetComponent<NavMeshAgent>(); agent.stoppingDistance = attackDistance; agent.speed = movementSpeed; //Set Rigidbody to Kinematic to prevent striking register bug if (GetComponent<Rigidbody>()) { GetComponent<Rigidbody>().isKinematic = true; } } // Update is called once per frame void Update() { if (agent.remainingDistance - attackDistance < 0.01f) { if(Time.time > nextAttackTime) { nextAttackTime = Fourth dimension.fourth dimension + attackRate; //Attack RaycastHit hit; if(Physics.Raycast(firePoint.position, firePoint.forward, out hitting, attackDistance)) { if (hit.transform.CompareTag("Player")) { Debug.DrawLine(firePoint.position, firePoint.position + firePoint.forward * attackDistance, Color.cyan); IEntity player = hit.transform.GetComponent<IEntity>(); player.ApplyDamage(npcDamage); } } } } //Motility towardst he player agent.destination = playerTransform.position; //Always look at player transform.LookAt(new Vector3(playerTransform.transform.position.x, transform.position.y, playerTransform.position.z)); } public void ApplyDamage(float points) { npcHP -= points; if(npcHP <= 0) { //Destroy the NPC GameObject npcDead = Instantiate(npcDeadPrefab, transform.position, transform.rotation); //Slightly bounce the npc dead prefab up npcDead.GetComponent<Rigidbody>().velocity = (-(playerTransform.position - transform.position).normalized * viii) + new Vector3(0, 5, 0); Destroy(npcDead, 10); es.EnemyEliminated(this); Destroy(gameObject); } } }
- Create a new script, name it "SC_EnemySpawner" then paste the code below within it:
SC_EnemySpawner.cs
using UnityEngine; using UnityEngine.SceneManagement; public class SC_EnemySpawner : MonoBehaviour { public GameObject enemyPrefab; public SC_DamageReceiver actor; public Texture crosshairTexture; public float spawnInterval = two; //Spawn new enemy each n seconds public int enemiesPerWave = 5; //How many enemies per wave public Transform[] spawnPoints; bladder nextSpawnTime = 0; int waveNumber = 1; bool waitingForWave = true; float newWaveTimer = 0; int enemiesToEliminate; //How many enemies we already eliminated in the current moving ridge int enemiesEliminated = 0; int totalEnemiesSpawned = 0; // Start is chosen before the showtime frame update void Starting time() { //Lock cursor Cursor.lockState = CursorLockMode.Locked; Cursor.visible = imitation; //Wait x seconds for new moving ridge to start newWaveTimer = 10; waitingForWave = truthful; } // Update is called in one case per frame void Update() { if (waitingForWave) { if(newWaveTimer >= 0) { newWaveTimer -= Time.deltaTime; } else { //Initialize new moving ridge enemiesToEliminate = waveNumber * enemiesPerWave; enemiesEliminated = 0; totalEnemiesSpawned = 0; waitingForWave = false; } } else { if(Time.time > nextSpawnTime) { nextSpawnTime = Time.time + spawnInterval; //Spawn enemy if(totalEnemiesSpawned < enemiesToEliminate) { Transform randomPoint = spawnPoints[Random.Range(0, spawnPoints.Length - 1)]; GameObject enemy = Instantiate(enemyPrefab, randomPoint.position, Quaternion.identity); SC_NPCEnemy npc = enemy.GetComponent<SC_NPCEnemy>(); npc.playerTransform = player.transform; npc.es = this; totalEnemiesSpawned++; } } } if (player.playerHP <= 0) { if (Input.GetKeyDown(KeyCode.Space)) { Scene scene = SceneManager.GetActiveScene(); SceneManager.LoadScene(scene.proper noun); } } } void OnGUI() { GUI.Box(new Rect(ten, Screen.tiptop - 35, 100, 25), ((int)player.playerHP).ToString() + " HP"); GUI.Box(new Rect(Screen.width / 2 - 35, Screen.tiptop - 35, lxx, 25), player.weaponManager.selectedWeapon.bulletsPerMagazine.ToString()); if(player.playerHP <= 0) { GUI.Box(new Rect(Screen.width / 2 - 85, Screen.height / 2 - xx, 170, 40), "Game Over\due north(Press 'Space' to Restart)"); } else { GUI.DrawTexture(new Rect(Screen.width / 2 - iii, Screen.height / two - 3, 6, half-dozen), crosshairTexture); } GUI.Box(new Rect(Screen.width / 2 - 50, 10, 100, 25), (enemiesToEliminate - enemiesEliminated).ToString()); if (waitingForWave) { GUI.Box(new Rect(Screen.width / 2 - 125, Screen.height / 4 - 12, 250, 25), "Waiting for Wave " + waveNumber.ToString() + " (" + ((int)newWaveTimer).ToString() + " seconds left...)"); } } public void EnemyEliminated(SC_NPCEnemy enemy) { enemiesEliminated++; if(enemiesToEliminate - enemiesEliminated <= 0) { //Start next wave newWaveTimer = 10; waitingForWave = truthful; waveNumber++; } } }
- Create a new script, name it "SC_DamageReceiver" then paste the code below within it:
SC_DamageReceiver.cs
using UnityEngine; public class SC_DamageReceiver : MonoBehaviour, IEntity { //This script will go on track of player HP public bladder playerHP = 100; public SC_CharacterController playerController; public SC_WeaponManager weaponManager; public void ApplyDamage(float points) { playerHP -= points; if(playerHP <= 0) { //Player is dead playerController.canMove = imitation; playerHP = 0; } } }
- Attach SC_NPCEnemy script to alive enemy instance (Y'all'll detect it added another component called NavMesh Agent, which is needed to navigate the NavMesh)
- Assign the recently created expressionless case prefab to the Npc Expressionless Prefab variable
- For the Burn down Bespeak, create a new GameObject, motion it inside the alive enemy instance and place it slightly in front of the instance, and then assign it to the Burn Signal variable:
- Finally, Save the alive instance to Prefab and delete information technology from Scene.
Setting Up Enemy Spawner
Now let's move to SC_EnemySpawner. This script will spawn enemies in waves and as well volition show some UI information on the screen, such as Thespian HP, current Ammo, how many Enemies are left in a current wave, etc.
- Create a new GameObject and name it "_EnemySpawner"
- Attach SC_EnemySpawner script to it
- Assign the newly created enemy AI to the Enemy Prefab variable
- Assign the texture below to the Crosshair Texture variable
- Create a couple of new GameObjects and place them around the Scene then assign them to the Spawn Points array
You lot'll notice that there is ane last variable left to assign which is the Actor variable.
- Attach SC_DamageReceiver script to a Player example
- Modify Role player example tag to "Player"
- Assign Player Controller and Weapon Managing director variables in SC_DamageReceiver
- Assign Histrion instance to a Thespian variable in SC_EnemySpawner
And lastly, we have to bake the NavMesh in our scene so the enemy AI volition be able to navigate.
Also, don't forget to mark every static Object in Scene every bit Navigation Static earlier baking NavMesh:
- Go to NavMesh window (Window -> AI -> Navigation), click on Bake tab and so click Bake push. Subsequently the NavMesh is baked information technology should await something similar this:
At present it'due south fourth dimension to press Play and test it:
Everything works as expected!
Source: https://sharpcoderblog.com/blog/fps-with-enemy-ai-in-unity-3d
Posted by: baconfitionly.blogspot.com
0 Response to "How To Make A Mmo Camera In Unity"
Post a Comment