Προς το περιεχόμενο

Προτεινόμενες αναρτήσεις

Δημοσ.

έστω ότι έχουμε την παρακάτω συνάρτηση

>

public void SetEXP(uint _EXP)
{
if (_EXP > MaxEXP)
_EXP = MaxEXP;

EXP = _EXP;

if (EXP < 0)
EXP = 0;

UpdateLevel(EXP);
}

 

και έχουμε κάποιο Interface-Textbox(οτιδήποτε) που χρησιμοποιεί αυτή τη συνάρτηση,

το ερώτημα μου είναι, όταν ο χρήστης δώσει σαν τιμή -100 θα χτυπήσει ?

 

- βλέποντας το UINT λογικά δεν θα γίνει τίποτα...

 

Αν αυτό όμως προκαλέσει Exception και σταματήσει η εφαρμογή, δεν θα ήταν καλύτερα να το κάναμε όπως παρακάτω για να μην γινόταν ο 2ος έλεγχος

 

>
 public void SetEXP(uint _EXP)
 {
	 try
	 {
		 if (_EXP > MaxEXP)
               _EXP = MaxEXP;
	 }
	 catch (Exception)
	 { _EXP = 0; }

	 UpdateLevel(EXP);
 }

 

* Πρέπει να έχει θέμα με τη στοίχιση το Insomnia γιατί δεν τα δείχνει σωστά και σε κάθε διόρθωση τα χαλάει

Δημοσ.

Θα μπορούσες να γράψεις μια συνάρτηση ή ,αν έχεις τέτοια δυνατότητα, να ρυθμίσεις τα properties του textbox ώστε να μην δέχεται αρνητικούς αριθμόυς. Έτσι δεν θα χρειάζεται να μπλέξεις με exception handling

Δημοσ.

Το δοκίμασα και δεν αφήνει ο Compiler να βάλεις σαν παράμετρο αρνητική τιμή,

 

Και κάτι άλλο, επειδή η κλάση Player περιέχει πολλά δεδομένα αποφάσισα να φτιάξω ένα βοηθητικό αρχείο (DefaultValues.cs) το οποίο περιέχει κάποια DEFAULT values και κάποια MAX - LIMITS

 

http://pastebin.com/PtTnfpAt

 

κατά πόσο αυτό είναι σωστό? μήπως επιβαρύνει το πρόγραμμα, από την άλλη όμως αν τα βάλω στην κλάση Player θα είναι μπάχαλο μέσα.

Δημοσ.

Καταρχάς διάβασε για τα properties στη C#, θα σε βγάλει απ' όλο τον κόπο να φτιάχνεις μεθόδους για Get και Set.

Δεν πιστεύω ότι χρειάζεσαι αυτές τις μεταβλητές συνέχεια για να τις ορίσεις σε μεταβλητή. Θα πρότεινα να βάλεις τις default τιμές στον Constructor και μέσα στα properties (στην set να ορίσεις τα μέγιστα). Αν τώρα χρειάζεσαι να τα χρησιμοποιήσεις σε διάφορα τμήματα δοκίμασε να τα κάνεις const ώστε να μην αλλάζει.

 

Αν θέλεις οπωσδήποτε να τα βάλεις σε άλλο αρχείο δες το partial που σου επιτρέπει να σπασεις την κλάση σε τμήματα και να την βάλεις σε ξεχωριστά αρχεία για καλύτερη οργάνωση.

  • Like 1
Δημοσ.

Ο χρήστης δεν πρόκειται να δώσει την τιμή -100 κατευθείαν σε καμία μεταβλητή ή παράμετρο που βλέπουμε στον κώδικα που δείχνεις. Ο,τι είναι να γίνει θα γίνει στον κώδικα που μετατρέπει την τιμή που υπάρχει στο textbox (και είναι string) σε κάτι άλλο (λογικά uint αλλά δεν ξέρουμε). Επομένως δεν μας δείχνεις το μοναδικό πράγμα που έχει σημασία για να απαντηθεί η ερώτηση που θέτεις.

 

Απο κει και πέρα είναι φανερό από τον κώδικα ότι δεν έχεις καταλάβει πως δουλεύουν απολύτως βασικά πράγματα στη C#.

 

>if (_EXP > MaxEXP)
 _EXP = MaxEXP;
EXP = _EXP;
if (EXP < 0)
 EXP = 0;
UpdateLevel(EXP);

 

Πρώτον: τα ονόματα μεταβλητών και fields είναι πολύ άσχημα επιλεγμένα. Σαν rule of thumb κάνε ο,τι λέει εδώ.

 

Δεύτερον: αφού κάνεις τον ένα έλεγχο (για ανώτατο όριο) πριν αναθέσεις τιμή στην EXP γιατί κάνεις τον άλλο έλεγχο αφού αναθέσεις την τιμή; Πέραν του ποιό είναι σωστότερο (το πριν), αυτό δεν έχει καμία λογική!

 

Τρίτον: είναι προφανές ότι ένας uint δεν μπορεί να πάρει τιμή μικρότερη του μηδέν, επομένως: α) αν το EXP (που δε μας δείχνεις) είναι uint τότε το if είναι τζάμπα φλυαρία και β) αν το EXP είναι απλό int... τότε γιατί είναι int αφού έχεις σκοπό να μη το αφήσεις να πάει κάτω από το μηδέν; Όπως και να 'χει, αν τα EXP και _EXP είναι διαφορετικού τύπου τότε διαπράττεις έγκλημα θέτοντας κατευθείαν την τιμή του ενός στο άλλο (και γι' αυτό το λόγο στο σημείο εκείνο υπό συνθήκες μπορεί να πάρεις exception). Θα έπρεπε να έχουν τον ίδιο τύπο οπωσδήποτε.

 

Τέταρτον: properties όπως λέει και ο mitsakos.

 

Τέλος: αφού το EXP δε μπορεί να είναι τίποτα άλλο εκτός από field ή property, σχεδόν νομοτελειακά η UpdateLevel έχει πρόσβαση στην τιμή του κατευθείαν. Ποιός ο λόγος να το περνάς σαν παράμετρο; (ρητορική ερώτηση, δεν υπάρχει κανένας λόγος και αυτό που κάνεις πρέπει να αποφεύγεται).

 

>[try {
 if (_EXP > MaxEXP)
   _EXP = MaxEXP;
}
catch (Exception) {
 _EXP = 0;
}

 

Πρώτον: αν _EXP και MaxEXP έχουν τον ίδιο τύπο, τότε οι δύο γραμμές του if δε θα μπορούσαν ποτέ να βγάλουν exception (πώς θα ήταν δυνατόν το αντίθετο???). Αν δέν έχουν τον ίδιο τύπο, αυτό είναι bug που πρέπει να φτιαχτεί αμέσως. Σε κάθε περίπτωση αυτό το συγκεκριμένο try/catch είναι περιττό.

 

Δεύτερον: ΠΟΤΕ ΜΑ ΠΟΤΕ ΠΟΤΕ ΠΟΤΕ ΔΕΝ ΕΙΝΑΙ ΣΩΣΤΟ να γράφεις catch (Exception) (official documentation, εκτενες blog post). Στην προκειμένη περίπτωση δεν έχει ιδιαίτερη σημασία (όπως και να έγραφες το catch έτσι κι αλλιώς όλο το try/catch είναι περιττό) αλλά πρόκειται για κλασικό σφάλμα που σε βάζει σε λάθος μονοπάτι.

  • Like 2
Δημοσ.

>
// An event handler must return void.
private async void button1_Click(object sender, RoutedEventArgs e)
{
   textBox1.Clear();
   // SumPageSizesAsync returns a Task.
   await SumPageSizesAsync();
   textBox1.Text += "\r\nControl returned to button1_Click.\r\n";
}
// The following async lambda expression creates an equivalent anonymous
// event handler.
button1.Click += async (sender, e) => {
   textBox1.Clear();
   // SumPageSizesAsync returns a Task.
   await SumPageSizesAsync();
   textBox1.Text += "\r\nControl returned to button1_Click.\r\n";
}
// The following async method returns a Task<T>.
private async Task<byte[]> GetURLContentsAsync(string url)
{
   // The download will end up in variable content.
   var content = new MemoryStream();
   // Initialize an HttpWebRequest for the current URL.
   var webReq = (HttpWebRequest)WebRequest.Create(url);
   // Send the request to the Internet resource and wait for
   // the response.
   using (WebResponse response = await webReq.GetResponseAsync())
   {
    // Get the data stream that is associated with the specified url.
    using (Stream responseStream = response.GetResponseStream())
    {
	    await responseStream.CopyToAsync(content);
    }
   }
   // Return the result as a byte array.
   return content.ToArray();
}

 

Αυτη η γλωσσα θα παει πολυ μπροστα

Δημοσ.

Αυτη η γλωσσα θα παει πολυ μπροστα

 

LINQ, iterator blocks, lambdas με την καλύτερη σύνταξη που έχω δει ever, αναίμακτες closures χωρίς να χρειαστεί να κάνεις τίποτα, και τώρα async/await.

 

Δίνουν άλλη έννοια στην έκφραση "ο compiler δουλέυει για σένα" -- αντί να γράφεις κατεβατά κώδικα για τα "διαδικαστικά", τώρα πια τα κάνει μόνο του. :)

 

Με τεράστια διαφορά η C# είναι η γλώσσα που με κάνει συχνότερα από κάθε άλλη να αισθάνομαι ninja. :wub:

Δημοσ.

@defacer

Σχετικά με το Exception, απλά δεν με ενδιαφέρει να δω το μήνυμα λάθους γιατί ξέρω τι θα παραχθεί

 

Να ξεκαθαρίσουμε μερικά πράγματα, σχετικά με το EXP & _EXP, όπως τον βολεύει τον καθένα.. προσωπικά στα υποπρογράμματα συνηθίζω να έχω το ίδιο όνομα προσθέτοντας απλά το _ (ξέρω ότι μπερδεύει αυτό, αλλά είναι για μένα όχι για κάποιον)

 

Σχετικά με τους τύπους επέλεξα uint σχεδόν για τα περισσότερα Status(EXP/HP/MP...) γιατί μου εξασφαλίζει ότι δεν θα έχω αρνητικές τιμές που είναι και το ζητούμενο μου και 2ον δεν χρειάζεται έλεγχος για αυτό.

 

παρακάτω είναι 3 κλάσεις, πρώτα να εξηγήσω το σκεπτικό μου.

 

- Θα πρέπει να υπάρχουν κάποια Limits στα Status

- Δεν πρέπει να υπάρχουν αρνητικά Status (-100 MDEF Πχ)

- Τα Level είναι άμεσα συνδεδεμένα με το EXP (ανεβαίνει ή κατεβαίνει ανάλογα με το EXP)

-

 

Player.cs

>
class Player
{
   public uint EXP = DefaultValue.DEFAULT_EXP;
   //...............
   public void SetEXP(uint _EXP)
   {
    EXP = _EXP;
    if (EXP > DefaultValue.MAX_EXP)
	    EXP = DefaultValue.MAX_EXP;
    // IMPORTAND: Update Level
    UpdateLevel();
   }
   public void IncreaseEXP(uint _EXP)
   {
    EXP += _EXP;
    if (EXP > DefaultValue.MAX_EXP)
	    EXP = DefaultValue.MAX_EXP;
    // IMPORTAND: Update Level
    UpdateLevel();
   }
   private void UpdateLevel()
   {
    // WARNING: NEED REWORK
    uint Temp = 1;
    foreach (uint IN_LIST_EXP in Experience.EXP)
    {
	    if (EXP > IN_LIST_EXP)
	    {
		    Level = Temp;
		    Temp++;
		    if (Temp > 100)
			    Temp = 100;
	    }
    }//foreach
   }
   public void SetLevel(uint _Level)
   {
    if (_Level > DefaultValue.MAX_LEVEL)
	    _Level = DefaultValue.MAX_LEVEL;
    EXP = Experience.EXP[_Level - 1];
    EXP += 1; // Safe Action (Don't Delevel)
    // IMPORTAND: Update Level
    UpdateLevel();
   }
   //................................
   public uint GetEXP()
   { return EXP; }
}

 

DefaultValues.cs

 

>
   class DefaultValue
   {
    // Player Status
    public const uint DEFAULT_EXP	   =   0;
    public const uint DEFAULT_LEVEL	 =   1;
    public const uint DEFAULT_HP	    =   100;
    public const uint DEFAULT_MP	    =   100;
    public const uint DEFAULT_PATK	  =   70;
    public const uint DEFAULT_PDEF	  =   120;
    public const uint DEFAULT_MATK	  =   80;
    public const uint DEFAULT_MDEF	  =   140;
    public const uint DEFAULT_SPEED	 =   20;
    public const uint DEFAULT_ATKSPEED  =   450;
    // LIMITS
    public const uint MAX_EXP		   =   2100000;
    public const uint MAX_LEVEL		 =    100;
    public const uint MAX_HP		    =    8000;
    public const uint MAX_MP		    =    5000;
    public const uint MAX_PATK		  =    10000;
    public const uint MAX_PDEF		  =    7000;
    public const uint MAX_MATK		  =    12000;
    public const uint MAX_MDEF		  =    7000;
    public const uint MAX_SPEED		 =    200;
    public const uint MAX_ATKSPEED	  =    1000;
   }

 

Experience.cs

>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Pokemon
{
   class Experience
   {
    public static readonly uint[] EXP =
    {
	    0,	  // 1 Level
	    20,
	    54,
	    145,
	    391,
	    1055,
	    2848,
	    4215,
	    6238,
	    9232,
	    13663, // 10 Level
	    20221,
	    //.....
	    1015377,
	    1066145,
	    1119452, // 90 Level
	    1186619,
	    //......
	    1891284,
	    2004760  // 100 Level
    };
   }//Class
}

 

όσον αφορά τα Caps (EXP/MP/HP) πιστεύω ότι έχω κάνει την σωστή επιλογή (όλα CAPS) γιατί υπάρχει μια ιδιαίτερη βαρύτητα σε αυτά.

αυτό με το HP & _HP | EXP & _EXP θα το αλλάξω, πρέπει να είναι πιο περιγραφικά της λειτουργίας τους...

 

Σχετικά με την UpdateLevel, όπως είπα πάνω όταν παίρνεις ή χάνεις Experience πρέπει να γίνει έλεγχος αφού το Level εξαρτάται από το Exp

 

ΥΓ: Η κλάση είναι ημιτελής, το σκεπτικό μου είναι ως εξής

 

- Δημιουργία παίχτη

- Ανάθεση Default Τιμών

- Αποθήκευση των τιμών αυτών στην βάση (στην δημιουργία του παίχτη)

- Όταν μπει στο παιχνίδι τα Stats του θα γίνονται Load από τη βάση (άρα τα Default Values μας χρησιμεύουν μόνο στην δημιουργία)

 

- Όταν ανεβεί level και ανεβούν τα Stats θα αποθηκεύονται στη βάση, και αφού φορτώνονται από κει δεν θα γίνει κάνα μπέρδεμα του τύπου (Level 30 Character με Default-Niewbie Stats)

Δημοσ.

Κοιτα γραφεις σε OO αρα χωρις πολλες σκεψεις το Experience γινεται μια class

 

Ενα παραδειγμα

>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication3
{
   public interface IExperienceFormula
   {
    float Exp2Lvl(float exp);
    float Lvl2Exp(float lvl);
   }
   public class ExperienceFormulaFromGoogleSearchAndIFoundItAtStackOverflowWithSeartchParamCalcLevelFromExperience
    : IExperienceFormula
   {
    public float Exp2Lvl(float exp)
    {
	    return (float)((Math.Sqrt(625.0 + 100 * exp) - 25.0) / 50.0 );
    }
    public float Lvl2Exp(float lvl)
    {
	    return 25 * lvl * (1 + lvl);
    }
   }
   public class Experience
   {
    //one instance for All game
    public static IExperienceFormula ExperienceFormula { get; set; }

    uint experience;
    public Experience()
    {
	    Level = 1;
    }
    public uint AddExp(Experience exp)
    {
	    float difficultyBonus = (float)exp.Level / (float)this.Level;
	    float gainingExp = ExperienceFormula.Lvl2Exp(this.Level + 1) - ExperienceFormula.Lvl2Exp(this.Level);
	    gainingExp /= (float)this.Level;
	    gainingExp *= difficultyBonus;
	    experience += (uint)gainingExp;
	    return (uint)gainingExp;
    }
    public uint Level
    {
	    get
	    {
		    return (uint) ExperienceFormula.Exp2Lvl((float)experience);
	    }
	    set
	    {
		    experience = (uint)ExperienceFormula.Lvl2Exp((float)value);
	    }
    }
    public uint CurrentExperience
    {
	    get
	    {
		    if (this.Level == 1) return experience;
		    else
		    {
			    return experience - (uint)ExperienceFormula.Lvl2Exp(this.Level) ;
		    }
	    }
    }
    public uint ExperienceForNextLevel
    {
	    get { return (uint)ExperienceFormula.Lvl2Exp(this.Level + 1) - (uint)ExperienceFormula.Lvl2Exp(this.Level); }
    }
	
   }
   class Program
   {
    static void Main(string[] args)
    {
	    //game init
	    Experience.ExperienceFormula = new ExperienceFormulaFromGoogleSearchAndIFoundItAtStackOverflowWithSeartchParamCalcLevelFromExperience();
	    //...
	    Experience me = new Experience { Level = 1 };
	    Experience npc1 = new Experience { Level = 1 };
	    Experience npc2 = new Experience { Level = 3 };
	    Experience npc3 = new Experience { Level = 12 };
	    uint gaintXp = 0;
	    Console.WriteLine("Me Start\nLevel:{0}\nExp:{1}/{2}\n", me.Level, me.CurrentExperience, me.ExperienceForNextLevel);
	    gaintXp = me.AddExp(npc1);
	    Console.WriteLine("Me killing npc1\nLevel:{0}\nExp:{1}/{2} (+{3})\n", me.Level, me.CurrentExperience, me.ExperienceForNextLevel, gaintXp);
	    gaintXp = me.AddExp(npc1);
	    Console.WriteLine("Me killing npc1\nLevel:{0}\nExp:{1}/{2} (+{3})\n", me.Level, me.CurrentExperience, me.ExperienceForNextLevel, gaintXp);
	    gaintXp = me.AddExp(npc1);
	    Console.WriteLine("Me killing npc1\nLevel:{0}\nExp:{1}/{2} (+{3})\n", me.Level, me.CurrentExperience, me.ExperienceForNextLevel, gaintXp);
	    gaintXp = me.AddExp(npc1);
	    Console.WriteLine("Me killing npc1\nLevel:{0}\nExp:{1}/{2} (+{3})\n", me.Level, me.CurrentExperience, me.ExperienceForNextLevel, gaintXp);
	    gaintXp = me.AddExp(npc1);
	    Console.WriteLine("Me killing npc1\nLevel:{0}\nExp:{1}/{2} (+{3})\n", me.Level, me.CurrentExperience, me.ExperienceForNextLevel, gaintXp);
	    gaintXp = me.AddExp(npc1);
	    Console.WriteLine("Me killing npc1\nLevel:{0}\nExp:{1}/{2} (+{3})\n", me.Level, me.CurrentExperience, me.ExperienceForNextLevel, gaintXp);
	    gaintXp = me.AddExp(npc1);
	    Console.WriteLine("Me killing npc1\nLevel:{0}\nExp:{1}/{2} (+{3})\n", me.Level, me.CurrentExperience, me.ExperienceForNextLevel, gaintXp);
	    gaintXp = me.AddExp(npc1);
	    Console.WriteLine("Me killing npc1\nLevel:{0}\nExp:{1}/{2} (+{3})\n", me.Level, me.CurrentExperience, me.ExperienceForNextLevel, gaintXp);
	    gaintXp = me.AddExp(npc2);
	    Console.WriteLine("Me killing npc2\nLevel:{0}\nExp:{1}/{2} (+{3})\n", me.Level, me.CurrentExperience, me.ExperienceForNextLevel, gaintXp);
	    gaintXp = me.AddExp(npc3);
	    Console.WriteLine("Me killing npc3\nLevel:{0}\nExp:{1}/{2} (+{3})\n", me.Level, me.CurrentExperience, me.ExperienceForNextLevel, gaintXp);

	    Console.Read();
    }
   }
}

 

output

>
Me Start
Level:1
Exp:50/100
Me killing npc1
Level:2
Exp:0/150 (+100)
Me killing npc1
Level:2
Exp:37/150 (+37)
Me killing npc1
Level:2
Exp:74/150 (+37)
Me killing npc1
Level:2
Exp:111/150 (+37)
Me killing npc1
Level:2
Exp:148/150 (+37)
Me killing npc1
Level:3
Exp:35/200 (+37)
Me killing npc1
Level:3
Exp:57/200 (+22)
Me killing npc1
Level:3
Exp:79/200 (+22)
Me killing npc2
Level:3
Exp:145/200 (+66)
Me killing npc3
Level:4
Exp:211/250 (+266)

 

Ετσι ολη η διαδικασια με τα lvl τα xp κλπ πανε σε ενα αντικειμενο με αποτελεσμα το κυριως προγραμμα να εινει πιο ευαναγνωστο εφοσον δεν θα εχεις xp clacs lvl calcs κλπ αλλα μονο ενα object Experience

Δημιουργήστε ένα λογαριασμό ή συνδεθείτε για να σχολιάσετε

Πρέπει να είστε μέλος για να αφήσετε σχόλιο

Δημιουργία λογαριασμού

Εγγραφείτε με νέο λογαριασμό στην κοινότητα μας. Είναι πανεύκολο!

Δημιουργία νέου λογαριασμού

Σύνδεση

Έχετε ήδη λογαριασμό; Συνδεθείτε εδώ.

Συνδεθείτε τώρα
  • Δημιουργία νέου...