Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

De_Struktor

unregistriert

1

09.08.2013, 18:38

Basisklassenproblem: wie die Klasse sicher designen?

Hi liebe Community,

da ich erstmal bevor ichc eines Tages mit
Unity3D weiter arbeite, meine OOP- Kenntnise erweitern möchte, habe ich
mir gedacht, das werde ich dann auch tun, bevor es in die
"professionelle" Spieleentwicklung geht.
(XNA 4.0-----> C# .NET 4.5)
Ich habe immernoch bei
dem gleichen Bomberman, was ich schon lange hätte fertig haben können,
ein Problem zu einem Basisklassendesign!

Da ich mit "Pokemonfiguren" arbeite, dachte ich mir, auf Befehl der OOP eine "vernünftige"
Basisklasse zu erstellen, welche den Namen <<Pokemon>>
trägt. Von der wird jedes andere Pokemon abgeleitet.

Dann habe ich noch eine abstrakte Klasse <<Animation>> von der Pokemon erbt, denn eigentlich sind alle Pokemon nichts anderes als Animationen.

Daher dieser Gedanke.

Zurzeit sieht die Klasse so aus:

C#-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;

namespace Revenge_of_Pokemon.Classes_and_Interfaces
{
    public abstract class Pokemon : Animation
    {
        public int figurePosition_x { get; set; }
        public int figurePosition_y { get; set; }

        protected const int figureWidth = 30;
        protected const int figureHeight = 30;
        
        private float velocity { get; set; }

        /// <summary>
        /// technicel data 
        /// </summary>

        int timerDurrate { get; set; }
        int currTime { get; set; }

        Keys[] keys { get; set; }
        GameTime gameTime;

        protected KeyboardState keyboard { get; set; }
       

        Direction direction;

        public Pokemon(Texture2D texture, int position_x, int position_y, int frameWidth, int frameHeight)
            : base(texture, frameWidth, frameHeight, new Rectangle(position_x, position_y, figureWidth, figureHeight))
        {
            velocity = 3.0f;
            this.figurePosition_x = position_x;
            this.figurePosition_y = position_y;
            this.direction = Direction.W;

            timerDurrate = 0;
            currTime = 0;
            keys = new Keys[3];
            gameTime = new GameTime();
            keyboard = Keyboard.GetState();
        }

        protected abstract void Update(GameTime gameTime);

    }
}


Und ich weiß das ich noch unerfahren bin, was das korrekte Designen von Klassen angeht bin, daher frage ich euch, denn ich komme einfach nicht weiter, wie ich die Datenelemente kapseln sollte, das auch die Subklassen, sie wieder verwenden können. (protected, ich weiß, nur habe ich gelesen, man sollte sie möglichst nicht verwenden)

Ich weiß gerade einfach nicht weiter und ich habe mich seit Tagen mit Lösungsvorschlägen beschäftigt, jedoch, komme ich nicht zu einem guten Design, daher bitte ich um professionellen Rat :(


P.s(momentan ist es so, das ich eine Spielerklasse habe, in Form eines Pokemons, welche von <<Animation>> erbt. Und ich will ja mahrere Pokemons haben, daher die Pokemonklasse.)

hier noch die Animationsklasse:

C#-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
 public abstract class Animation
    {
        int frameRows;
        int frameColumn;
        bool isAnimation;
        int timer;
        int animationSpeed;

        int frameWidth;
        int frameHeight;

        protected Rectangle picture_rect;
        Texture2D image;
        SpriteEffects effects;
        Direction direction;

        public Animation(Texture2D image, int frameWidth, int frameHeight, Rectangle poke_rect)
        {
            this.picture_rect = poke_rect;
            this.frameRows = 1;
            this.frameColumn = 3;
            this.effects = SpriteEffects.None;
            this.isAnimation = true;
            this.timer = 0;
            this.animationSpeed = 5;
            this.image = image;
            this.frameWidth = frameWidth;
            this.frameHeight = frameHeight;
        }

        protected virtual void Animate() 
        {
            // frameColumn = Einzelne Spalte des gesamten Atlases
            timer++;
            if (timer == animationSpeed)
            {
                timer = 0;
                if (isAnimation)
                {
                    frameColumn++;

                    if (frameColumn > 3)
                    {
                        frameColumn = 2;
                        isAnimation = false;
                    }
                }

                else
                {
                    frameColumn--;
                    if (frameColumn < 1)
                    {
                        frameColumn = 2;
                        isAnimation = true;
                    }
                }
            }
        }

        protected virtual void PlayerDirection(Direction direction)
        {
            this.direction = direction;
            switch (direction)
            {
                case Direction.W:
                    this.effects = SpriteEffects.None;
                    frameRows = 2;
                    break;

                case Direction.S:
                    this.effects = SpriteEffects.None;
                    frameRows = 1;
                    break;

                case Direction.A:
                    this.effects = SpriteEffects.None;
                    frameRows = 3;
                    break;

                case Direction.D:
                    this.effects = SpriteEffects.FlipHorizontally;
                    frameRows = 3;
                    break;
            }
        }

        protected virtual void ResetAnimation(Keys k1, Keys k2, Keys k3, Keys k4)
        {
            KeyboardState keyboard = Keyboard.GetState();
            if (keyboard.IsKeyUp(k1) && keyboard.IsKeyUp(k2) && keyboard.IsKeyUp(k3) && keyboard.IsKeyUp(k4))
            {
                frameColumn = 2;
                timer = 0;
            }
        }

        public virtual void Draw(SpriteBatch spritebatch)
        {
            spritebatch.Draw(image, picture_rect, new Rectangle((frameColumn - 1) * frameWidth, (frameRows - 1) * frameHeight, frameWidth, frameHeight),
            Color.White, 0f, new Vector2(0, 0), effects, 0f);  
        }
    }
}

Mfg

DeStruktor

Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von »De_Struktor« (09.08.2013, 18:48)


De_Struktor

unregistriert

2

09.08.2013, 18:50

er klappt auch bisher alles so wie ich will, nur jetzt will ich halt die Basisklasse Pokemon implementieren.
Und da komme ich nicht so ganz weiter!! ....

ps. Direction ist eine Enumeration: W, S, A, D

Ich entschuldige mich jetzt schon für die Masse an Code, nur die Sachen hängen miteinander zusammen und ich dachte, sonst ist es nicht verständlch!

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »De_Struktor« (09.08.2013, 18:55)


Nimelrian

Alter Hase

Beiträge: 1 216

Beruf: Softwareentwickler (aktuell Web/Node); Freiberuflicher Google Proxy

  • Private Nachricht senden

3

09.08.2013, 19:21

Ich bezweifle, dass ein Pokemon eine Animation ist.
Ich bin kein UserSideGoogleProxy. Und nein, dieses Forum ist kein UserSideGoogleProxyAbstractFactorySingleton.

De_Struktor

unregistriert

4

09.08.2013, 19:22

Wieso sollte es das nicht sein, im Grunde ist der Hauptbestand die Animation!
Also ist es dann rein theoretisch eine Animation!

Dann kann es auch davon erben, sry, nur mir leuchtet das nicht so wirklich ein :S

Ok, davon unabhängig, das kann ich noch beheben, nur was mir mehr grad an Verständnis raubt ist das korrekte Designen dieser Baisklasse.

Denn z.B: Pikachu

- muss die Position kennen, also protected.
- muss die Geschwindigkeit kennen, also protected.
- muss die breite und Höhe nicht wirklich wissen, also private.
- muss aber die technischen Details, wie timerDurrate und momentane Zeit, Anzahl der Keys und welche Keys, dann noch den Keyboard status kennen, oder etwa nicht?? also nach mir erstmal, wäre es als protected definiert.

Und die Enumeration <<Direction>> der Animation, muss es kennen, da ich in der Updatefunktion sie dann bei allen abgeleiteten Pokemon(Schiggi, Glurak etc...) ja nur die Enumeration aufrufe und somit muss die auch für jede abgeleitete Klasse sichtbar sein, oder nicht?

BlueCobold

Community-Fossil

Beiträge: 10 738

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

5

09.08.2013, 19:26

Ein Pokemon hat eine (oder wohl eher sogar mehrere) Animation(en). Ein Pokemon ist ein merkwürdiges Fantasie-Wesen.
Teamleiter von Rickety Racquet (ehemals das "Foren-Projekt") und von Marble Theory

Willkommen auf SPPRO, auch dir wird man zu Unity oder zur Unreal-Engine raten, ganz bestimmt.[/Sarkasmus]

Dreat

Frischling

Beiträge: 86

Wohnort: Heilbronn

  • Private Nachricht senden

6

09.08.2013, 19:33

Genauso gut könntest du sagen Pokemon bestehen nur aus Angriffen ->

Ich z.B. sehe das so:

Eine Pokemon-Klasse:
Animation,
Angriffe,
Stats,
Texture

So das ist deine Basisklasse, jetzt kannst du für jedes Pokemon eine eigene Instanz erzeugen:

Pokemon xyz = new Pokemon();

und dann kannst du für diese Instanz eigene Werte festlegen, sprich eine eigene Textur eigene Animation usw



An alle erfahreneren verbessert mich wenn ich falsch liege =D

De_Struktor

unregistriert

7

09.08.2013, 19:38

Nein, eine Instanz von eine abstrakten Klasse erstens geht nicht und 2 würde es keinen Sinn machen, ein Objekt daraus zu bauen.

Also, so erblicke ich das, da Pokemon zu allgemein ist.

Und Angriffe besser gesagt, Angreifen, wäre dann eine Methode und kein Member. Ich meine natürlich kein Feld, fail an dieser Stelle^^

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »De_Struktor« (09.08.2013, 19:45)


De_Struktor

unregistriert

8

09.08.2013, 19:50

Anscheinend fällt niemanden dazu was ein, naja muss ich schauen, wie ich das löse, aber trotzdem danke für das Lesen.

Schorsch

Supermoderator

Beiträge: 5 145

Wohnort: Wickede

Beruf: Softwareentwickler

  • Private Nachricht senden

9

09.08.2013, 20:05

Die Klasse soll ja auch nicht abstrakt sein. Oder möchtest du für jedes Pokemon eine Klasse schreiben. Wie schon gesagt, ist ein Pokemon keine Animation. Ein Pokemon hat eine oder mehrere Animationen, einen oder mehrere Angriffe, einen oder mehrere Stats und so weiter. Das alles sind Member. Das was damit passiert wie zum Beispiel die Ausführung eines Angriffs wären dann Methoden. Du erzeugst eine Instanz und legst die Member dann passend fest. Zum Beispiel den passenden Namen mit passenden Animationen etc. Dafür könnte es sich lohnen eine Factory zu implementieren welche dir dann die passenden Instanzen zu deinen Pokemon erstellt. Ansonstne ist Klassendesign etwas was man gut lernt wenn man es versucht. Hinsetzen und Code schreiben ist da wohl am sinnvollsten. Wenn es nicht klappt versuch halt einen anderen Weg.
„Es ist doch so. Zwei und zwei macht irgendwas, und vier und vier macht irgendwas. Leider nicht dasselbe, dann wär's leicht.
Das ist aber auch schon höhere Mathematik.“

De_Struktor

unregistriert

10

09.08.2013, 20:21

schon gelöst, eine Pokemonklasse, von der werden dann nur Objekte erzeugt.

Denn die Daten sind so gesehen bei jedem Pokemon gleich, also macht Vererbung hier kein Sinn!

Bzw, man muss nix neues hinzufügen, denn nach meiner Lösung können sie bislang alles dasselbe^^ daher nur Membermodifikationen per Objekt sinnig.

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »De_Struktor« (09.08.2013, 20:34)


Werbeanzeige