• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Interfejs | Dziedziczenie | C#

Object Storage Arubacloud
0 głosów
302 wizyt
pytanie zadane 12 lipca 2019 w C# przez KazikBozia Obywatel (1,600 p.)

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);
    }
}

 

1 odpowiedź

+1 głos
odpowiedź 14 lipca 2019 przez DeBos123 Nałogowiec (44,950 p.)

Napewno na początku powinieneś poprawić nazewnictwo:

  • Wszystkie nazwy powinny być w języku angielskim, tak samo komentarze.
  • Zamiast shoot, co oznacza strzelać, powinieneś mieć shot co oznacza strzał lub projectile co oznacza pocisk.
  • Bez przeglądania całego kodu, przynajmniej ja nie wiem za co odpowiada zmienna DamageLotery oraz czym różnią się zmienne ReloadTime i ReloadMagazieTime (chyba powinno być ReloadMagazineTime).

Co do interface'ów:

  • IShoot, które powinno nazywać się IShot, powinno mieć tylko pola Damage i DamageLotery, cokolwiek ta zmienna robi.
  • Pola takie jak MaxAmmo i TempMaxAmmo powinny znajdować się w interface'ie czołgu z którego wtedy dziedziczyłyby rodzaje pojazdów, czyli czołg gracza, czołg sterowany przez grę itp.
    To samo tyczy się pól ReloadTime i ReloadMagazieTime.
komentarz 14 lipca 2019 przez KazikBozia Obywatel (1,600 p.)

Mój angielski nie jest najlepszy ale staram się go doskonalić. Niektóre czołgi posiadają magazynek i ten czas pomiędzy przeładowaniem pocisku w kasecie istnieje i stąd ReloadMagazineTime. DamageLotery to maksymalne wahanie obrażeń jakie może zadać czołg gracza. (więcej lub mniej, może lepsze MaxDamageDisparity)
Dzięki, że zwróciłeś mi uwagę na nazewnictwo, to nie jest trudne do naprawy a pewnie dużo da.
Pozdrawiam

Podobne pytania

0 głosów
3 odpowiedzi 624 wizyt
pytanie zadane 11 sierpnia 2017 w C# przez Wasacz Początkujący (480 p.)
0 głosów
1 odpowiedź 1,174 wizyt
pytanie zadane 14 lipca 2017 w C# przez Matheoosh Nowicjusz (120 p.)
0 głosów
1 odpowiedź 796 wizyt

92,568 zapytań

141,420 odpowiedzi

319,620 komentarzy

61,954 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Kolejna edycja największej imprezy hakerskiej w Polsce, czyli Mega Sekurak Hacking Party odbędzie się już 20 maja 2024r. Z tej okazji mamy dla Was kod: pasjamshp - jeżeli wpiszecie go w koszyku, to wówczas otrzymacie 40% zniżki na bilet w wersji standard!

Więcej informacji na temat imprezy znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...