Dobry wieczór!
Chciałem wykorzystać dziedziczenie i interfejs w kodzie mojej gry (C#/Unity) ale strasznie mi się to pokomplikowało i jestem pewien, że da się to zrobić prościej i czyściej.
Są to skrypty czołgu 2D odpowiedzialne za jego strzelanie. Interfejsu i klasy Shoot nie "urzywam w grze" tylko TankSchoot : Shoot (są jeszcze `BotShoot : Schoot` i `AutoSchoot : Shoot`)
Jeśli coś pominąłem lub coś źle wyjaśniłem to proszę komentować i krytykować.
Z góry dzięki i pozdrawiam!
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public interface IShoot
{
int MaxAmmo { get; }
int TempMaxAmmo { get; }
float ReloadTime { get; }
float ReloadMagazieTime { get; }
float Damage { get; }
float DamageLotery { get; }
void Shooting();
void CheckShooting();
IEnumerator Reload();
IEnumerator ReloadEffect();
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public abstract class Shoot : Photon.MonoBehaviour, IShoot
{
[Header("'Shoot' Reference")]
[Space]
[SerializeField]
protected PhotonView myPV;
[SerializeField]
protected Transform startFirePoint; //Miejsce z kąd wylatuje pocisk
[SerializeField]
protected Transform maxFirePoint; //Miejsce gdzie jest maxymalny zasięg lotu pocisku
[SerializeField]
protected GameObject shootSoundEffect; //Prefab odtwarzacza dzwięku wystrzału
[SerializeField]
protected GameObject BulletTrailPrefab; //Prefab pocisku
[Header("'Shoot' Details")]
[Space]
public float shootDistance = 7.75f;
protected float timeToFire = 0;
public float realReloadTime;
protected int tempMaxAmmo;
public int TempMaxAmmo { get { return tempMaxAmmo; } }
public bool isReloadnig = false;
public LayerMask whatToHit;
//protected int maxAmmo;
public virtual int MaxAmmo { get; }
//protected float reloadTime;
public virtual float ReloadTime { get; }
//protected float reloadMagazieTime;
public virtual float ReloadMagazieTime { get; }
//protected float damage;
public virtual float Damage { get; }
//protected float damageLotery;
public virtual float DamageLotery { get; }
public virtual void Shooting()
{
tempMaxAmmo--;
if(shootSoundEffect != null)
Instantiate(shootSoundEffect, transform.position, transform.rotation);
myPV.RPC("RpcDoShootEffect", PhotonTargets.All, startFirePoint.position, startFirePoint.rotation);
}
protected bool ICanShoot = false;
public virtual void CheckShooting()
{
if (isReloadnig)
{
ICanShoot = false;
return;
}
if (tempMaxAmmo <= 0) //If you put in a whole magazine
{
StartCoroutine(Reload()); //start loading magazine
StartCoroutine(ReloadEffect()); //show loading effect
ICanShoot = false;
return;
}
ICanShoot = true;
}
public virtual IEnumerator Reload()
{
isReloadnig = true;
realReloadTime = ReloadTime - 0.1f;
yield return new WaitForSecondsRealtime(ReloadTime);
tempMaxAmmo = MaxAmmo;
isReloadnig = false;
}
public virtual IEnumerator ReloadEffect()
{
for (int i = 0; i <= ReloadTime * 10; i++)
if (realReloadTime >= 0f)
{
yield return new WaitForSecondsRealtime(0.1f);
realReloadTime -= 0.1f;
realReloadTime = Mathf.Round(realReloadTime * 100f) / 100f;
}
}
protected RaycastHit2D MakeRaycastHit2D ()
{
Vector2 mousePosition = new Vector2(maxFirePoint.position.x, maxFirePoint.position.y);
Vector2 firePointPosition = new Vector2(startFirePoint.position.x, startFirePoint.position.y);
Debug.DrawLine(firePointPosition, mousePosition, Color.cyan);
return Physics2D.Raycast(firePointPosition, mousePosition - firePointPosition, shootDistance, whatToHit);
}
/// <summary>
/// Jestem lokalnym graczem i trafiam BOTa
/// </summary>
/// <param name="hit"></param>
protected void HitBotHowPlayer(RaycastHit2D hit, float damage)
{
if (hit.collider.tag == Tag.BOT)
{
hit.collider.GetComponent<BOTHealt>().myPV.RPC("AdBotDamage", PhotonTargets.All, damage); //niech bot sprawdza jako czołg ma gracz
hit.collider.GetComponent<BOTHealt>().SetLastShooter(myPV.GetComponent<PlayerGO>().myPlayer);
hit.collider.GetComponent<BOTHealt>().SyncHP(hit.collider.GetComponent<BOTHealt>().healtPoint);
}
}
/// <summary>
/// Jestem botem i trafiam gracza lokalnego jak i zdalnego
/// </summary>
/// <param name="hit"></param>
/// <param name="damage"></param>
protected void HitPlayerHowBot(RaycastHit2D hit, float damage)
{
if (hit.collider.tag == Tag.LOCALPLAYERBODY || hit.collider.tag == Tag.REMOTEPLAYERBODY)
{
if (hit.collider.GetComponent<TankObject>().Player.hp > 0)
GameManager.Instance.photonView.RPC("OdbierzHpGraczowiJakoBotRPC", PhotonTargets.MasterClient,
hit.collider.GetComponent<TankObject>().Player.pp, damage);
SetCameraTargetOnMeBOT(hit,myPV.viewID);
PlayHitAudioPlayer(hit);
}
}
/// <summary>
/// Jestem lokalnym graczem i trafiam zdalnego
/// </summary>
/// <param name="hit"></param>
protected void HitPlayerHowPlayer(RaycastHit2D hit, float damage)
{
if (hit.collider.tag == Tag.REMOTEPLAYERBODY)
{
if (hit.collider.GetComponent<TankObject>().Player.hp > 0)
GameManager.Instance.photonView.RPC("OdbierzHpGraczowiRPC", PhotonTargets.MasterClient,
hit.collider.GetComponent<TankObject>().Player.pp, damage);
SetCameraTargetOnMePlayer(hit);
PlayHitAudioPlayer(hit);
}
}
protected void HitPlayerHowAutoTurretPlayer(RaycastHit2D hit, float damage)
{
HitPlayerHowBot(hit, damage);
}
protected void PlayHitAudioPlayer(RaycastHit2D hit)
{
hit.collider.GetComponent<TankObject>().PlayerGO.GetComponent<TankRPC>().myPV.RPC("PlayAudioHitRPC",
hit.collider.GetComponent<TankObject>().Player.pp, null);
}
protected void SetCameraTargetOnMePlayer(RaycastHit2D hit)
{
hit.collider.GetComponent<TankObject>().PlayerGO.GetComponent<TankRPC>().myPV.RPC("SetCameraDeathRPC",
hit.collider.GetComponent<TankObject>().Player.pp, null);
}
protected void SetCameraTargetOnMeBOT(RaycastHit2D hit, int ID)
{
hit.collider.GetComponent<TankObject>().PlayerGO.GetComponent<TankRPC>().myPV.RPC("SetCameraDeathHowBotRPC",
hit.collider.GetComponent<TankObject>().Player.pp, ID);
}
[PunRPC]
protected abstract void RpcDoShootEffect(Vector3 pos, Quaternion rot, PhotonMessageInfo pmi);
}
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
public class TankShoot : Shoot, IShoot
{
public static TankShoot Instance { get; private set; }
[Header("'TankShoot' Reference")]
[Space]
[SerializeField]
protected GameOver playerGameOver;
[SerializeField]
protected ParticleSystem muzzleFlash;
[SerializeField]
protected TechTree techTree;
[SerializeField]
protected Text reloadText;
private bool shoot = true;
public override int MaxAmmo
{
get { return TankEvolution.Instance.Magazynek; }
}
public override float ReloadTime
{
get { return TankEvolution.Instance.Reload; }
}
public override float ReloadMagazieTime
{
get { return TankEvolution.Instance.ReloadBetweenMagazine; }
}
public override float Damage
{
get { return TankEvolution.Instance.Damage; }
}
public override float DamageLotery
{
get { return TankEvolution.Instance.DamageLotery; }
}
public void Awake()
{
if(!photonView.isMine)
enabled = false;
else if (Instance == null)
Instance = this;
else
enabled = false;
}
void Update ()
{
CheckShooting();
}
public void SetShootingOpportunity(bool decision)
{
StartCoroutine(OdblokujStrzelanie(decision,0));
}
public void SetShootingOpportunity(bool decision, float time)
{
StartCoroutine(OdblokujStrzelanie(decision, time));
}
IEnumerator OdblokujStrzelanie(bool decision, float time)
{
yield return new WaitForSecondsRealtime(time);
shoot = decision;
}
public void ResetMagazine(int ammo)
{
tempMaxAmmo = ammo;
}
public override void Shooting()
{
muzzleFlash.Play();
//~~~~
base.Shooting();
//~~~~
RaycastHit2D hit = MakeRaycastHit2D();
if (hit.collider != null)
{
float tempDamage = Mathf.Round(Random.Range(Damage - DamageLotery, Damage + DamageLotery));
HitPlayerHowPlayer(hit, tempDamage);
HitBotHowPlayer(hit, tempDamage);
}
}
public override void CheckShooting()
{
if (realReloadTime <= 0f)
{
realReloadTime = 0f;
reloadText.text = "0.0";
reloadText.color = Color.red;
}
else
{
reloadText.text = realReloadTime.ToString();
reloadText.color = Color.white;
}
//~~~~
base.CheckShooting();
if (!ICanShoot)
return;
//~~~~
if (Input.GetButton("Fire1") && Time.time >= timeToFire)
{
timeToFire = Time.time + ReloadMagazieTime / 8;
if (!shoot)
return;
Shooting();
}
}
[PunRPC]
protected override void RpcDoShootEffect(Vector3 pos, Quaternion rot, PhotonMessageInfo pmi)
{
if(Player.FindPlayer(pmi.sender).gameObject != null)
BulletTrailPrefab.GetComponent<BulletMovment>().own =
Player.FindPlayer(pmi.sender).gameObject.GetComponent<TankEvolution>().HullGameObject;
Instantiate(BulletTrailPrefab, pos, rot);
}
}