Implement Api Call Functions
Alright! Great job coming this far. We're about complete the game play of our realtime multiplayer Shooter Arena.
Update Shooting
First off, we'd need to ensure that our Api calls UpdateHitTargets()
, UpdateDefendedTargets()
and UpdateMisses()
are called at the right time.
Head over to PlayerShooting.cs
in Assets/_Game/Scripts/Player/PlayerShooting.cs
As the name implies, this scripts controls the shooting mechanics of the player.
Go the the Shoot()
function and make the following changes.
Replace
if (user.role == Data.User.Role.SHOOTER){gameData.shouldCount = !complete;}
with
if (user.role == Data.User.Role.SHOOTER){gameData.shouldCount = !complete;gameData.UpdateHitTargets(complete);}else{gameData.UpdateDefendedTargets();}
This calls UpdateHitTargets()
if the player is a Shooter
and UpdateDefendedTargets()
if the player is a Defender
.
Next, replace
if (gameData.bullets <= 0){gameData.PlayDelayedSound(gameData.sounds.disappointments, 0.2f);gameData.shouldCount = false;gameData.gameManager.hud.SetActive(false);}
with
if (gameData.bullets <= 0){gameData.PlayDelayedSound(gameData.sounds.disappointments, 0.2f);if (user.role == Data.User.Role.SHOOTER)gameData.UpdateHitTargets(true);elsegameData.UpdateDefendedTargets(true);gameData.shouldCount = false;gameData.gameManager.hud.SetActive(false);}gameData.UpdateMiss();
The full Shoot()
function becomes
public virtual void Shoot(){if (player.inactive)return;if (!canShoot)return;Ray ray = new Ray(transform.position, transform.forward);Debug.DrawRay(transform.position, transform.forward * 100, Color.red, 2);Vector3 destination = transform.forward * 150;gameData.bullets--;player.Shake();player.Shoot();gameData.sfxPlayer.PlayOneShot(gameData.sounds.zap);if (Physics.Raycast(ray, out RaycastHit hit)){destination = hit.point;if (hit.transform.CompareTag("Target")){Target target = hit.transform.GetComponent<Target>();target.ActivateTarget();bool complete = gameData.bullets <= 0;gameData.gameManager.hud.SetActive(!complete);gameData.PlayDelayedSound(gameData.sounds.activation, 0.2f);gameData.PlayDelayedSound(gameData.sounds.claps, 0.2f);if (user.role == Data.User.Role.SHOOTER){gameData.shouldCount = !complete;gameData.UpdateHitTargets(complete);}else{gameData.UpdateDefendedTargets();}}else{if (gameData.bullets <= 0){gameData.PlayDelayedSound(gameData.sounds.disappointments, 0.2f);if (user.role == Data.User.Role.SHOOTER)gameData.UpdateHitTargets(true);elsegameData.UpdateDefendedTargets(true);gameData.shouldCount = false;gameData.gameManager.hud.SetActive(false);}}}Game.Bullet bullet = Instantiate(bulletPrefab, player.activeGun.position, Quaternion.identity).GetComponent<Game.Bullet>();bullet.Move(destination);}
Update the Game Manager
Next up, we have to update GameManager.cs
in Assets/_Game/Scripts/Managers/GameManager.cs
In the function ShowGameOver()
, replace
gameOverText.text = "GameOver"
with
gameOverText.text = gameData.battle.hitTargets.Count == gameData.battle.defendedTargets.Count? "<color=green>Defender</color> Wins": "<color=red>Shooter</color> Wins";
This changes the game over text from simply "GameOver" to either "Shooter Wins" or "Defender Wins" depending on who actually wins the game.
It determines who wins the game by comparing our arrays, battle.hitTargets
and battle.defendedTargets
.
Next, in BeginDefenderTurn()
, add
foreach (Target target in targetSpawner.targets){if (gameData.battle.hitTargets.Contains(target.index)){target.HighlightTarget(Color.red);target.targeted = true;}}
so the whole function becomes
private void BeginDefenderTurn(OnDefenderTurn defenderTurn){if (user.role == Data.User.Role.DEFENDER){opponentTurn.SetActive(false);countdown.SetActive(true);foreach (Target target in targetSpawner.targets){if (gameData.battle.hitTargets.Contains(target.index)){target.HighlightTarget(Color.red);target.targeted = true;}}}else{opponentTurn.SetActive(true);hud.SetActive(false);}}
And that's it for our Game Manager.
Update Target's Left
We have a little script called TargetLeft.cs
that controls the Ui that displays our targets remain to be shot by the Defender
or to show how many targets the Shooter
has hit,
We need to make a change to this to properly reflect this data.
Open TargetLeft.cs
in Assets/_Game/Scripts/Ui/TargetLeft.cs
Replace
private void Update(){int hit = gameData.hitTargets.Count;int defend = gameData.defendedTargets.Count;targetLeft.text = (hit - defend).ToString();}
with
private void Update(){int hit = gameData.battle.hitTargets?.Count ?? gameData.hitTargets.Count;hit = gameData.user.role == Game.Data.User.Role.SHOOTER ? gameData.hitTargets.Count : hit;int defend = gameData.battle.defendedTargets?.Count ?? gameData.defendedTargets.Count;defend = gameData.user.role == Game.Data.User.Role.DEFENDER ? gameData.defendedTargets.Count : defend;targetLeft.text = (hit - defend).ToString();}
Timer
Lastly, we have to update our Timer.cs
to end the game when the Defender
's time is up.
Open Timer.cs
in Assets/_Game/Scripts/Ui/Timer.cs
In the Update()
function, add
gameData.UpdateDefendedTargets(true);
So it becomes
private void Update(){if (!gameData.shouldCount)return;if (user.role == Data.User.Role.SHOOTER){gameData.time += Time.deltaTime;}else{gameData.time -= Time.deltaTime;if (gameData.time <= 0){if (!completeCalled){Debug.Log("Game over");gameData.shouldCount = false;gameData.gameManager.hud.SetActive(false);completeCalled = true;gameData.UpdateDefendedTargets(true);}}}timer.text = gameData.time.ToString("N2");}
And that's it!
Build the game to a device and try it out! You'd see that we've perfectly created the gameplay of Shooter Arena.
- Build apps and APIs 10x faster
- Built-in authorization and caching
- 8x more performant than hand-rolled APIs