Building it Single Player
Making it Multiplayer
|
using System.Collections; |
|
using System.Collections.Generic; |
|
using UnityEngine; |
|
|
|
public class Bomb : MonoBehaviour |
|
{ |
|
[SerializeField] float _countdownTime = 5f; |
|
[SerializeField] float _radius = 5f; |
|
[SerializeField] int _damage = 5; |
|
|
|
float _explodeTime; |
|
int _playerNumber; |
|
|
|
public void SetPlayer(int playerNumber) => _playerNumber = playerNumber; |
|
|
|
// Start is called before the first frame update |
|
IEnumerator Start() |
|
{ |
|
_explodeTime = Time.time + _countdownTime; |
|
while (Time.time < _explodeTime) |
|
{ |
|
yield return null; |
|
float randomRed = Random.Range(0, 255); |
|
Color newColor = new Color(randomRed, 0, 0); |
|
GetComponent<Renderer>().material.color = newColor; |
|
} |
|
// Do damage |
|
Collider[] colliders = Physics.OverlapSphere(transform.position, _radius); |
|
foreach (var collider in colliders) |
|
{ |
|
var enemy = collider.GetComponent<Enemy>(); |
|
if (enemy) |
|
enemy.TakeDamage(enemy.transform.position, _playerNumber, _damage); |
|
} |
|
|
|
Destroy(gameObject); |
|
} |
|
} |
|
using UnityEngine; |
|
|
|
public class BombDropper : MonoBehaviour |
|
{ |
|
[SerializeField] Bomb _bombPrefab; |
|
[SerializeField] float _delay = 5; |
|
[SerializeField] float _releaseVelocity = 10f; |
|
|
|
float _nextDropTime; |
|
Player _player; |
|
|
|
void Awake() => _player = GetComponent<Player>(); |
|
|
|
void Update() |
|
{ |
|
if (ShouldDropBomb()) |
|
DropBomb(); |
|
} |
|
|
|
void DropBomb() |
|
{ |
|
_nextDropTime = Time.time + _delay; |
|
Bomb bomb = Instantiate(_bombPrefab, transform.position, transform.rotation); |
|
bomb.SetPlayer(_player.PlayerNumber); |
|
var rigidbody = bomb.GetComponent<Rigidbody>(); |
|
if (rigidbody != null) |
|
rigidbody.velocity = transform.forward * _releaseVelocity; |
|
} |
|
|
|
bool ShouldDropBomb() |
|
{ |
|
if (Time.time >= _nextDropTime && Input.GetButtonDown("Bomb" + _player.PlayerNumber)) |
|
return true; |
|
|
|
return false; |
|
} |
|
} |
|
using UnityEngine; |
|
|
|
public class Bullet: MonoBehaviour |
|
{ |
|
[SerializeField] float _maxLifetime = 10; |
|
|
|
Gun _gun; |
|
float _disableTime; |
|
|
|
public void SetGun(Gun gun) => _gun = gun; |
|
|
|
void OnCollisionEnter(Collision collision) |
|
{ |
|
gameObject.SetActive(false); |
|
_gun?.AddToPool(this); |
|
|
|
var enemy = collision.collider.GetComponent<Enemy>(); |
|
if (enemy != null) |
|
{ |
|
int playerNumber = _gun.GetComponent<Player>().PlayerNumber; |
|
enemy.TakeDamage(collision.contacts[0].point, playerNumber); |
|
} |
|
} |
|
|
|
void Update() |
|
{ |
|
if (Time.time >= _disableTime) |
|
gameObject.SetActive(false); |
|
} |
|
|
|
void OnEnable() => _disableTime = Time.time + _maxLifetime; |
|
} |
|
using System; |
|
using UnityEngine; |
|
using UnityEngine.AI; |
|
using UnityEngine.SceneManagement; |
|
|
|
public class Enemy : MonoBehaviour |
|
{ |
|
[SerializeField] GameObject _hitPrefab; |
|
[SerializeField] GameObject _explosionPrefab; |
|
[SerializeField] int _health = 3; |
|
[SerializeField] int _pointValue = 100; |
|
|
|
AudioSource _audioSource; |
|
int _currentHealth; |
|
|
|
void OnEnable() |
|
{ |
|
_audioSource = GetComponent<AudioSource>(); |
|
_currentHealth = _health; |
|
} |
|
|
|
void Update() |
|
{ |
|
var player = FindObjectOfType<Player>(); |
|
GetComponent<NavMeshAgent>().SetDestination(player.transform.position); |
|
} |
|
|
|
public void TakeDamage(Vector3 impactPoint, int playerNumber, int amount = 1) |
|
{ |
|
_currentHealth -= amount ; |
|
Instantiate(_hitPrefab, impactPoint, transform.rotation); |
|
|
|
if (_audioSource != null) |
|
_audioSource.Play(); |
|
|
|
if (_currentHealth <= 0) |
|
{ |
|
Instantiate(_explosionPrefab, impactPoint, transform.rotation); |
|
gameObject.SetActive(false); |
|
|
|
ScoreSystem.Add(_pointValue, playerNumber); |
|
} |
|
} |
|
|
|
void OnCollisionEnter(Collision collision) |
|
{ |
|
var player = collision.collider.GetComponent<Player>(); |
|
if (player != null) |
|
{ |
|
SceneManager.LoadScene(0); |
|
} |
|
} |
|
} |
|
using System.Collections.Generic; |
|
using UnityEngine; |
|
|
|
public class Gun : MonoBehaviour |
|
{ |
|
[SerializeField] Bullet _bulletPrefab; |
|
|
|
[SerializeField] float _delay = 0.2f; |
|
[SerializeField] float _bulletSpeed = 5f; |
|
|
|
float _nextShootTime; |
|
Vector3 _direction; |
|
Queue<Bullet> _pool = new Queue<Bullet>(); |
|
Player _player; |
|
|
|
void Awake() => _player = GetComponent<Player>(); |
|
|
|
void Update() |
|
{ |
|
if (CanShoot()) |
|
Shoot(); |
|
} |
|
|
|
void Shoot() |
|
{ |
|
_nextShootTime = Time.time + _delay; |
|
var bullet = GetBullet(); |
|
bullet.transform.position = _player.ShootPoint.position; |
|
bullet.transform.rotation = _player.ShootPoint.rotation; |
|
bullet.GetComponent<Rigidbody>().velocity = transform.forward * _bulletSpeed; |
|
} |
|
|
|
Bullet GetBullet() |
|
{ |
|
if (_pool.Count > 0) |
|
{ |
|
var bullet = _pool.Dequeue(); |
|
bullet.gameObject.SetActive(true); |
|
return bullet; |
|
} |
|
else |
|
{ |
|
var bullet = Instantiate(_bulletPrefab, _player.ShootPoint.position, _player.ShootPoint.rotation); |
|
bullet.SetGun(this); |
|
return bullet; |
|
} |
|
} |
|
|
|
bool CanShoot() |
|
{ |
|
return Time.time >= _nextShootTime; |
|
} |
|
|
|
public void AddToPool(Bullet bullet) |
|
{ |
|
_pool.Enqueue(bullet); |
|
} |
|
} |
|
using UnityEngine; |
|
|
|
public class Player : MonoBehaviour |
|
{ |
|
[SerializeField] float _speed = 1f; |
|
[SerializeField] Transform _direction; |
|
[SerializeField] Transform _shootPoint; |
|
[SerializeField] int _playerNumber = 1; |
|
|
|
public Transform ShootPoint => _shootPoint; |
|
|
|
public int PlayerNumber => _playerNumber; |
|
|
|
Animator _animator; |
|
|
|
|
|
void Awake() => _animator = GetComponent<Animator>(); |
|
|
|
void Update() |
|
{ |
|
MoveWithController(); |
|
AimWithController(); |
|
} |
|
|
|
void MoveWithController() |
|
{ |
|
float horizontal = Input.GetAxis("Horizontal" + _playerNumber); |
|
float vertical = Input.GetAxis("Vertical" + _playerNumber); |
|
|
|
Vector3 movement = new Vector3(horizontal, 0f, vertical); |
|
transform.Translate(movement * Time.deltaTime * _speed, _direction); |
|
_animator.SetBool("Run", movement.magnitude > 0); |
|
} |
|
|
|
void AimWithController() |
|
{ |
|
float horizontalAim = Input.GetAxis("HorizontalAim" + _playerNumber); |
|
float verticalAim = Input.GetAxis("VerticalAim" + _playerNumber); |
|
|
|
if (horizontalAim != 0 && verticalAim != 0) |
|
transform.forward = new Vector3(horizontalAim, 0, verticalAim); |
|
} |
|
} |
|
using TMPro; |
|
using UnityEngine; |
|
|
|
public class ScoreSystem : MonoBehaviour |
|
{ |
|
int _player1; |
|
int _player2; |
|
|
|
static int _highScore; |
|
static ScoreSystem _instance; |
|
|
|
void Awake() => _instance = this; |
|
|
|
[SerializeField] TMP_Text _player1Text; |
|
[SerializeField] TMP_Text _player2Text; |
|
[SerializeField] TMP_Text _highScoreText; |
|
|
|
public void ResetHighScore() |
|
{ |
|
_highScore = 0; |
|
PlayerPrefs.SetInt("HighScore", _highScore); |
|
UpdateText(); |
|
} |
|
|
|
void OnEnable() |
|
{ |
|
_highScore = PlayerPrefs.GetInt("HighScore"); |
|
UpdateText(); |
|
} |
|
|
|
void UpdateText() |
|
{ |
|
_player1Text.SetText(_player1.ToString()); |
|
_player2Text.SetText(_player2.ToString()); |
|
_highScoreText.SetText(_highScore.ToString()); |
|
} |
|
|
|
public static void Add(int points, int playerNumber) |
|
{ |
|
_instance.AddPoints(points, playerNumber); |
|
} |
|
|
|
void AddPoints(int points, int playerNumber) |
|
{ |
|
if (playerNumber == 1) |
|
{ |
|
_player1 += points; |
|
if (_player1 >= _highScore) |
|
{ |
|
_highScore = _player1; |
|
PlayerPrefs.SetInt("HighScore", _highScore); |
|
} |
|
} |
|
else |
|
{ |
|
_player2 += points; |
|
if (_player2 >= _highScore) |
|
{ |
|
_highScore = _player2; |
|
PlayerPrefs.SetInt("HighScore", _highScore); |
|
} |
|
} |
|
|
|
UpdateText(); |
|
} |
|
} |
|
using System; |
|
using UnityEngine; |
|
|
|
public class Spawner : MonoBehaviour |
|
{ |
|
float _nextSpawnTime; |
|
|
|
[SerializeField] float _delay = 2f; |
|
[SerializeField] Transform[] _spawnPoints; |
|
[SerializeField] Enemy[] _enemies; |
|
|
|
void Update() |
|
{ |
|
if (ShouldSpawn()) |
|
Spawn(); |
|
} |
|
|
|
void Spawn() |
|
{ |
|
_nextSpawnTime = Time.time + _delay; |
|
Transform spawnPoint = ChooseSpawnPoint(); |
|
Enemy enemy = ChooseEnemy(); |
|
Instantiate(enemy, spawnPoint.position, spawnPoint.rotation); |
|
} |
|
|
|
Enemy ChooseEnemy() |
|
{ |
|
int randomIndex = UnityEngine.Random.Range(0, _enemies.Length); |
|
var enemy = _enemies[randomIndex]; |
|
return enemy; |
|
} |
|
|
|
Transform ChooseSpawnPoint() |
|
{ |
|
int randomIndex = UnityEngine.Random.Range(0, _spawnPoints.Length); |
|
var spawnPoint = _spawnPoints[randomIndex]; |
|
return spawnPoint; |
|
} |
|
|
|
bool ShouldSpawn() |
|
{ |
|
return Time.time >= _nextSpawnTime; |
|
} |
|
} |