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

Interfejs | Dziedziczenie | C#

0 głosów
113 wizyt
pytanie zadane 12 lipca w C# i .NET przez KazikBozia Obywatel (1,440 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 przez DeBos123 Nałogowiec (34,670 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 przez KazikBozia Obywatel (1,440 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 321 wizyt
pytanie zadane 11 sierpnia 2017 w C# i .NET przez Wasacz Początkujący (480 p.)
0 głosów
1 odpowiedź 710 wizyt
pytanie zadane 14 lipca 2017 w C# i .NET przez Matheoosh Nowicjusz (120 p.)
0 głosów
1 odpowiedź 131 wizyt
Porady nie od parady
Odznacz odpowiedź zieloną fajką, jeśli uważasz, że jest ona najlepsza ze wszystkich i umożliwiła ci rozwiązanie problemu.Najlepsza odpowiedź

65,639 zapytań

112,264 odpowiedzi

236,873 komentarzy

46,639 pasjonatów

Przeglądających: 227
Pasjonatów: 14 Gości: 213

Motyw:

Akcja Pajacyk

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

Oto dwie polecane książki warte uwagi. Pełną listę znajdziesz tutaj.

...