Diskuze: Co dělám špatně??
V předchozím kvízu, Test znalostí C# .NET online, jsme si ověřili nabyté zkušenosti z kurzu.

Člen

Zobrazeno 34 zpráv z 34.
//= Settings::TRACKING_CODE_B ?> //= Settings::TRACKING_CODE ?>
V předchozím kvízu, Test znalostí C# .NET online, jsme si ověřili nabyté zkušenosti z kurzu.
Ono celej ten způsob vyřešení útoku se mi zdá špatnej, ty při
každým volání funkce Attack() snížíš jeho damage (takže po několika
voláních může být i záporný ). a ten další řádek pod tím mi taky nepřijde správně a jak už
pako poznamenal, nikde se nesnižuje hp.
druhého bojovníka ti to nevypíše, protože celej ten while cyklus (ten s live > 0) se provede v rámci jednoho volání orc.Attack(elf). a protože se hodnota proměnné live nemění tak se ti to nekonečně zacyklí.
Teď jsem si toho taky trochu všiml, dělal jsem to narychlo večer, ten útok zkusím dneska po škole upravit. Je tam ještě něco co se někomu nelíbí, nechci si navyknout na špatný návyky.
mel by sis udelat zakladni abstraktni tridy pro objekty, o kterych vis ze maji stejny zaklad ale lisi se zpusobem jak budou pracovat.
napr. mas ruzne druhy nepratel, kteri maji ruzne aury a ruzne druhy utoku,
tak is udelas CreepBase a od toho budou dedit ostatni nepratele. To same treba
pro pro hrace. Udelas PlayerBase a toho odvodis Warrior,Mage .... Vyhoda je ze
pak v kodu misto:
public void Attack(Warrior rival)
public void Attack(Mage rival)
public void Attack(Paladin rival)
mas jednotnou metodu
public void Attack(PlayerBase rival) nebo public void Attack(CreepBase
rival)
(zalezi jak slozita ta hra bude)
Přesně nad tím jsem taky přemýšlel,jestli udělat abstraktní třídu a
z toho zdědit Mága a Bojovníka.Nakonec jsem to udělal takhle,jelikož jsem
si říkal,že mágovi nebudu dávat manu a nepotřeboval by nic navíc oproti
válečníkovi,kdyby jo,tak bych to kdyžtak udělal s polymorfismem a v mágovi
bych to přepsal ten Attack,ale asi s tou abstraktní třídou to bude
lepší.Určitě to zkusím .
abstraktní třída:
class PlayerBase
{
protected string name;
protected int life;
protected int damage;
protected int defense;
public PlayerBase(string name,int life,int damage,int defense)
{
this.name = name;
this.life = life;
this.damage = damage;
this.defense = defense;
}
public void Attack(PlayerBase rival)
{
rival.life = rival.life + rival.defense;
damage = rival.life - this.damage;
Console.WriteLine("Hráč {0} zaútočil na hráče {1} a sebral mu životy za {2} hp",this.name,rival.name,damage);
}
}
Warrior :
class Warrior:PlayerBase
{
public Warrior(string name,int life,int damage,int defense):base (name,life,damage,defense)
{
}
}
Mage :
class Mage:PlayerBase
{
public Mage(string name,int life,int damage,int defense):base (name,life,damage,defense)
{
}
}
a Program :
{
Warrior orc = new Warrior("Baltazar",100,25,50);
Mage shadow = new Mage("Blood",50,80,10);
orc.Attack(shadow);
shadow.Attack(orc);
Console.ReadKey();
}
už to v pohodě útočí,bere i druhý hráč,zkusím tam dát ještě ten
cyklus,+ při 0 hp se přestane bojovat
no tak zrovna v tomhle pripade by mela byt metoda bud metoda Attack virtualni
a z podedenych tridach by se mela upravit protoze warrior asi utoci jinak nez
mage . pripadne udelat par
protected metod jako OnAttack a CalculateDamage a Attack bych prepsal na neco
jako
public void Attack(PlayerBase rival)
{
if(rival.OnAttack(this))
{ int damage=CalculateDamage(); rival.TakeDamage(damage);
this.DoDamage(damage); }
else
//nemuze utocit, (miss,dodge,parry,aura...)
Samozřejmě to udělám,taky,ale zatím mi stačí to mít u mága a bojovníka stejný.Časem tam chci přidat i věci,tak potom tam použiju ten polymorfismus a zkusím to nějak vylepšit.Ale díky za radu,až se dostanu ze školy domů,kdyžtak to zkusím napsat a ukázat ti to jestli to dělám správně.
Promiň,že píšu asi tak špatný kód,ale jak říkám je to můj první
projekt.Byl bych rád,kdyby si měl někdy náhodou čas a chtěl mi pomoci
jestli by si mi ten kód upravit,tak aby byl správně.Chtěl bych se podívat
co jsem udělal špatně a porovnat to.Ono se i říká,že z těhle prográmku
se naučíš nejvíc a já bych rád příště neopakoval chyby:
Program.cs :
class Program
{
static void Main(string[] args)
{
Warrior orc = new Warrior("Strong",500,100,150,50);
Mage elf = new Mage("Shadow",500,150,100,80);
orc.Attack(elf);
elf.Attack(orc);
Console.ReadKey();
}
PlayerBase :
class PlayerBase
{
protected string name;
protected int life;
protected int damage;
protected int defense;
protected int writeDMG;
public PlayerBase(string name,int life,int damage,int defense)
{
this.name = name;
this.life = life;
this.damage = damage;
this.defense = defense;
}
public virtual void Attack(PlayerBase rival)
{
rival.life = rival.life + rival.defense;
damage = rival.life - this.damage;
Console.WriteLine("Hráč {0} zaútočil na hráče {1} a sebral mu životy za {2} hp", this.name, rival.name, damage);
}
Mage:
class Mage:PlayerBase
{
private int magicStrike;
Staff staff;
public Mage(string name,int life,int damage,int defense,int magicStrike):base (name,life,damage,defense)
{
this.magicStrike = magicStrike;
}
public override void Attack(PlayerBase rival)
{
magicStrike = this.magicStrike + staff.magicAT + this.damage;
writeDMG = life - this.magicStrike;
Console.WriteLine("Hráč {0} zaútočil na hráče {1} a sebral mu životy za {2} hp", this.name, name, writeDMG);
}
Warrior:
class Warrior:PlayerBase
{
private int strike;
public Warrior(string name,int life,int damage,int defense,int strike):base (name,life,damage,defense)
{
this.strike = strike;
}
public override void Attack(PlayerBase rival)
{
strike = this.strike + this.damage;
writeDMG = life - this.strike;
Console.WriteLine("Hráč {0} zaútočil na hráče {1} a sebral mu životy za {2} hp",this.name,name,writeDMG);
}
Staff :
public class Staff
{
public int magicAT;
public Staff(int magicAT)
{
this.magicAT = magicAT;
}
První věc, kterou bych na tvém místě nedělal, je toto:
Console.WriteLine("Hráč {0} zaútočil na hráče {1} a sebral mu životy za {2} hp",this.name,name,writeDMG)
Místo toho vrať hodnotu(ideální varianta) nebo si alespon udelej
jednoduchou třídu render, přes kterou budeš vypisovat. To má tu výhodu,
že ti stačí změnit kód na jednom místě, kdežto teď musíš vyeditovat
všechna místa v kódu, kde máš Console.WriteLine. Což je opravdu špatně
Zkus zauvažovat nad tím, že bys svou hru dodělal a pak chtěl místo textového výstupu grafický. Anebo jen jiné formátování. Kolik změn by to pro tebe znamenalo?
Další věc, kterou bych ti doporučil, je konsistentní řádkování. A hlavně maximálně cca 60-70 znaků na řádek. Řádky přes celý monitor opravdu nejsou pravé ořechové, nehledě na známou skutečnost, že dlouhé řádky se špatně čtou.
Ty myslíš to s tím
public override string ToString()
jo a když se snažím spustit program vypíše mi to : NullReferenceException was unhandled a zastaví se mi u jednoho řádku taková šipka u tohoto řádku :
magicStrike = this.magicStrike + staff.magicAT + this.damage;
Ale jinak jsem rád,že si mi poradil,aspoň to příště neudělám.
staff nikde neinicializuješ, takže je defaultně null.
Jo a jak mám abstraktní třídu PlayerBase a pak metodu Attack přepišuju u Mage a Warrior,tak jak to mám udělat,aby to vypsalo jméno druhého bojovníka.Mohl jsem tam dát třeba rival.name jen když jsem měl
public void Attack(Warrior rival
,ale já tam mám
public void Attack(PlayerBase rival)
a to mi jde jen name,nemůžu dát třeba rival.name.
Možná,že ti přijdou tyto moje chyby takový začátečnický,nebo divný,ale zatím jsem to moc nepoužíval jen u nějakých lehkých prográmků.
A jo teď jsem si toho všiml .Ale i když jsem to tam dal,tak mi to stejně vypisuje to
stejný.
Tak se to chce zamyslet nad modifikátorem přístupu (např. udělat getter).
Ty gettery a settery se budu učit teprv teď,teď jsem akorát u statiky
(toje kapitola před tím) .Ale podívám se teda na to.
toho rival.name muzes dosahnout treba tak jak sem psal ve svem poslednim prispevku. obecne se tento postup jmenuje NVI (non virtual interface, nebo take zname jako template method). funguje tak ze ze napr. metoda attack NENI virtualni a nejde overidovat. avsak v jejim tele nekde volas metodu attackCore a ta attack core se overiduje a v ni se pocita/dela to dulezite.
"Rád bych někoho požádal,jestli by přepsal aspoň 1 třídu"
no ty chyby se musi pochopit a nejlip je pochopis tak ze je udelas abys pak
vedel proc je nemas delat
Já bych ti doporučil, aby ses nebál dělat chyby.
Protože z vlastních chyb se člověk učí nejlíp.
Když budeš kopírovat cizí věci, nikdy nepochopíš, oč skutečně jde.
Žádný perfektní kód neexistuje.
Nepoužívej vlastnost jazyka jen proto, že ji použil někdo jiný. Použij ji
až tehdy, kdy pochopíš, že přináší výhodu. Popřípadě ji nepoužívej
vůbec, pokud ji nepotřebuješ.
Programátoři jsou tlupa výjimečných. Proto si vymysleli výraz refaktorovat. Všichni ostatní ovšem svá díla předělávají nebo přepisují. Ale ty se neboj refaktorovat, budeš výjimečný.
Tak jo pokusím se o to to opravit a najít ještě nějaký chyby .Až to dodělám budu mít i
lepší pocit,že jsem to zvládl sám
.
Zatím jsem nic neupravoval,ale zkusil jsem to takhle a útok proběhl bez chyby: PlayerBase:
public class PlayerBase
{
public string name;
public int life;
public int damage;
public int defense;
public PlayerBase(string name,int life,int damage,int defense)
{
this.name = name;
this.life = life;
this.damage = damage;
this.defense = defense;
}
public void Attack(PlayerBase rival)
{
rival.life = rival.life + rival.defense;
damage = rival.life - this.damage;
Console.WriteLine("Hráč {0} zaútočil na hráče {1} a sebral mu životy za {2} hp",this.name,rival.name,damage);
}
Warrior:
class Warrior:PlayerBase
{
public Warrior(string name,int life,int damage,int defense):base (name,life,damage,defense)
{
}
Mage :
class Mage:PlayerBase
{
public Mage(string name,int life,int damage,int defense):base (name,life,damage,defense)
{
}
IronArmor :
class IronArmor
{
public bool Iarmor;
private int defense = 25;
public void IArmorWearing(PlayerBase user)
{
if (Iarmor == true)
{
user.defense = user.defense + this.defense;
}
else
{
defense = user.defense;
}
}
Program.cs :
class Program
{
static void Main(string[] args)
{
Warrior orc = new Warrior("Star",250,80,120);
Mage elf = new Mage("Shadow",150,130,70);
IronArmor iron = new IronArmor();
iron.IArmorWearing(orc);
orc.Attack(elf);
elf.Attack(orc);
Console.ReadKey();
}
Budu rád za všechnu kritiku .
Tvoje zděděné třídy jsou momentálně k ničemu. Kdyby tohle mělo být finále, tak bych radši udělal něco takového:
public class Player
{
public string name;
public int life;
public int damage;
public int defense;
public void Attack(Player rival)
{
rival.life = rival.life + rival.defense;
damage = rival.life - this.damage;
Console.WriteLine("Hráč {0} zaútočil na hráče {1} a sebral mu životy za {2} hp", this.name, rival.name, damage);
}
}
a pak můžeš vytvářet instanci takto:
Player warrior = new Player { damage = 20, life = 100, defense = 10, name = "Garrosh"};
Jednotlivé třídy, které reprezentují zbraně, různé výzbroje apod. bych si nechal jako instance uvnitř třídy. pak by měla dědičnost nějaký smysl, protože warrior bude asi nosit jiné věci než mage.
Děkuji,tohle ještě určitě není finální,taky jsem si všiml,že to je k ničemu,ale jestli tam ještě něco přidám (chci tam přidat mágovi magickou útok a manu a válečníkovi něco s útokem),tak se to bude hodit.Ale zatím to můžu takhle předělat,jelikož teď asi nebudu mít moc času,tak aby to tam zbytečně nebylo.
Ještě nějaká kritika nebo rada?
Pisu z mobilu takze se omlouvam. zajimalo by mne jak bys udelal tridu Monstrum, aniz bys dedil z base player. Dale jak bys poresil ruzne druhy brneni. A posledni IArmorWearing - to mel byt pokus o interface?
Taky jsem si ale nejdřív říkal, že takhle interface nefunguje
Mimochodem takhle muzes prepisovat do nekonecna. Co si napred ujasnit, ceho chces dosahnout.
Zobrazeno 34 zpráv z 34.