Laden...

[erledigt] Stocken bei Shooter-Spiel

Erstellt von Häni vor 14 Jahren Letzter Beitrag vor 14 Jahren 3.426 Views
H
Häni Themenstarter:in
5 Beiträge seit 2009
vor 14 Jahren
[erledigt] Stocken bei Shooter-Spiel

Hi zusammen...

Habe mal mit so einem kleines shooter Programm begonnen, bei welchem man vorerst einmal auf Ballone schiessen kann...

Die Ballone sind im eindimensionalen Array "Ballone[]" gespeichert und fliegen dann in einem zeitlichen abstand vom rechten zum linken rand...

Das ganze habe ich mit einem Timer realisiert, und sobald ein Ballon durchfliegt, kommt nach ca 3 sekunden der nächste...

Beim ersten Ballon ist das kein Problem, doch wenn dann der zweite dazu kommt, beginnt das ganze zu stocken und wird dann pro ballon immer schlimmer....

Ich kann mir schlecht vorstellen dass dies am rechner liegt, sondern denke ehner dass es einen besseren Weg gibt, das zu programmieren, damit es "flüssig" läuft.

Hier wäre der essenzielle Code dazu:
(wobei das array xyBallon[] die coords der einzelnen Ballone sind... --> xyBallon[1].X = 783 und wird Ballone[1] zugeordnet..)



void ballon_pink()
        {
            xyz++;
            Ballone[xyz].Visible = true;
            xyBallon[xyz].X = xyBallon[xyz].X - 5;
            Ballone[xyz].Location = xyBallon[xyz];
        }

        void t_ballon_Tick(object sender, EventArgs e)
        {
            xyz = 0;
            abstand++;

            Ballone[xyz].Visible = true;
            xyBallon[xyz].X = xyBallon[xyz].X - 5;
            Ballone[xyz].Location = xyBallon[xyz];

            if(abstand >= 40)
            {
                ballon_pink();

                if (abstand >= 80)
                {
                    ballon_pink();

                    if (abstand >= 120)
                    {
                        ballon_pink();

                        if (abstand >= 160)
                        {
                            ballon_pink();

                            if (abstand >= 200)
                            {
                                ballon_pink();

                                if (abstand >= 240)
                                {
                                    ballon_pink();

                                    if (abstand >= 280)
                                    {
                                        ballon_pink();
                                    }
                                }
                            }
                        }
                    }
                }
            }

        }

Ich bedanke mich schon im voraus für Eure Hilfe

A
746 Beiträge seit 2007
vor 14 Jahren

Hi Häni,

also erst mal zu deinem if-Konstrukt. Sowas löst du besser mit einem Switch und oder einer Schleife.

Zeig doch mal deine Klasse Ballon.

Und die Mehrzahl von Ballon ist m.E. Ballons. [EDIT=herbivore]Mein Wörterbuch sagt: Ballons/Ballone geht beides[/EDIT]

Gruß, Alf

T
177 Beiträge seit 2007
vor 14 Jahren

Hallo Häni und herzlich willkommen auf myCsharp.de,

Erste Unschönheit:
Falls du die void ballon_pink() nur aus der t_ballon_Tick aufrufst, kannst du


Ballone[xyz].Visible = true;

weglassen, da du das schon in t_ballon_Tick() setzt.

Zweite Unschönheit:
Statt so viel verschachtelten if Abfragen würde ich eine einzige if, else if... machen und der void ballon_pink() einen int übergeben. Das würde dann wie folgt aussehen:


        	void ballon_pink(int count)
		{
			xyz++;
			//Damit der Ballon sich noch flüssig bewegt
			for (int i = 0; i < count; i++)
			{
				xyBallon[xyz].X = xyBallon[xyz].X - 5;
			}
			Ballone[xyz].Location = xyBallon[xyz];
		}

		void t_ballon_Tick(object sender, EventArgs e)
		{
			xyz = 0;
			abstand++;

			Ballone[xyz].Visible = true;
			xyBallon[xyz].X = xyBallon[xyz].X - 5;
			Ballone[xyz].Location = xyBallon[xyz];

			if(abstand >= 280)
			{
				ballon_pink(7);
			}
			else if (abstand >= 240)
			{
				ballon_pink(6);
			}
			else if (abstand >= 200)
			{
				ballon_pink(5);
			}
			else if (abstand >= 160)
			{
				ballon_pink(4);
			}
			else if (abstand >= 120)
			{
				ballon_pink(3);
			}
			else if (abstand >= 80)
			{
				ballon_pink(2);
			}
			else if (abstand >= 40)
			{
				ballon_pink(1);
			}
		}

Weiss aber nicht wieviel Performance dass das wirklich bringt....

Mit freundlichen Grüssen,
Tobias

3.511 Beiträge seit 2005
vor 14 Jahren

Das Problem wird eher sein, das GDI einfach zu langsam ist mehrere sich bewegende Objekte flüssig darzustellen. Gerade wenn du ein Spiel entwickeln willst, sollte man eher zu XNA wechseln.

"Jedes Ding hat drei Seiten, eine positive, eine negative und eine komische." (Karl Valentin)

Gelöschter Account
vor 14 Jahren

sowas löst man auch nciht mit controls sondern mit grfischen objekten usw... siehe auch:

	[[Tutorial] Gezeichnete Objekte mit der Maus verschieben ](http://www.mycsharp.de/wbb2/thread.php?threadid=29081)  

und dieses if-cascade hat sogar einen eigenen antipattern-namen....

@TmikeB
deine else-if cascade ist flasch rum. er würde in jedem fall nur in die erste bedingung hüpfen aber niemals in die anderen.

edit: @khalid:
prinzipiell hast du recht aber für sowas reicht gdi+ vollkomen aus.

T
177 Beiträge seit 2007
vor 14 Jahren

@ JAck30lena

Bereits angepasst, war zu hastig =)

MfG,
Tobias

3.971 Beiträge seit 2006
vor 14 Jahren

Ich würde sogar hingehen, dass jeder Ballon sich selbst zeichnet, quasi die Ballon-Klasse bekommt ne Funktion Paint und im Timer iterierst du alle Ballons durch und rufst jweils Paint auf.

Der Vorteil ist, das ganze ist Objektorientiert und nicht star prozedural. Du kannst später hingehen und die Funktion Paint überschreiben, um einen Ballon zu erstellen, der beispielsweise Texturen, statt einfach nur eine Hintergrundfarbe verwendet. Weiterhin ist das Lesen und das Verständnis des Quellcodes einfacher, da zwischen Steuerung der Ballons und dem Zeichen unterschieden wird

Es gibt 3 Arten von Menschen, die die bis 3 zählen können und die, die es nicht können...

Gelöschter Account
vor 14 Jahren

Ballons durch und rufst jweils Paint auf.

das halte ich für nciht richtig, da das zeichnen immer von außerhalb aufgerufen werden sollte (daher die onpaint methode)

der tick sollte nur die position der ballons versetzen lassen (also nciht selbst machen sondern ine bl aufrufen die das macht) und das neuzeichnen veranlassen.

warum macht ihr eigendlich diese komische berechung in 40er schritten? warum macht ihr nciht einfach ein "variable / 40 = anzahl der sprünge" und begrenzt das ergebniss auf maximal 7 ?

3.971 Beiträge seit 2006
vor 14 Jahren

das halte ich für nciht richtig, da das zeichnen immer von außerhalb aufgerufen werden sollte

Das Zeichnen wird doch von Außerhalb gerufen, nämlich von Tick. eventuell reden wir aber aneinander vorbei. Ich meine nicht eine Ballon-Klasse, die von einem WinForm-Control abeleitet wurde, wo nur ein Bild gesetzt wurde, sondern eine eigeneständige Ballon-(Daten)-Klasse für beispielsweise XNA.

Es gibt 3 Arten von Menschen, die die bis 3 zählen können und die, die es nicht können...

H
Häni Themenstarter:in
5 Beiträge seit 2009
vor 14 Jahren

Puhh, kamen ja reichlich Beiträge zu meiner Frage

Erstmal danke euch allen für die Hilfe.

zuerstmal @TmikeB:

Danke für den Code, der is wirklich besser und strukturierter als meiner... 😉 hab ihn so angepasst dass er dann auch wirklich funktioniert wie ich es will. Nun löst er mein Problem nicht, da dieses "stocken" halt immer noch vorhanden ist.

dann ans eichhoernchen:

hört sich interessant an deine idee, nun leider bin ich noch nicht wirklich vertraut mit der objektorientierten programmierung und habe es nicht ganz begriffen, und so logischerweise die verbesserungsvorschläge von Jack auch ned zu 100%...
wäre froh wenn du mir dies noch ein bisschen genauer erläuterns könntest 😉

Gelöschter Account
vor 14 Jahren

meine kernaussage ist, das du keine controls für deine grafischen objekte nehmen sollst, sondern eine klasse erstellen sollst, die dieses objekt repräsentiert.

das malen musst du dann natürlich selbst übernehmen.

2.891 Beiträge seit 2004
vor 14 Jahren

Nebenbei:

if(abstand >= 280)  
   ballon_pink(7);  
else if (abstand >= 240)  
   ballon_pink(6);  
else if (abstand >= 200)  
   ballon_pink(5);  
else if (abstand >= 160)  
   ballon_pink(4);  
else if (abstand >= 120)  
   ballon_pink(3);  
else if (abstand >= 80)  
   ballon_pink(2);  
else if (abstand >= 40)  
   ballon_pink(1);  

Das ganze kann man doch sicherlich auch durch ein einziges

ballon_pink(abstand/40);

ersetzt werden, oder?

H
Häni Themenstarter:in
5 Beiträge seit 2009
vor 14 Jahren

denke nicht dass das mit dem ersetzen geht, da der int "abstand" ja nicht nur genau die zahlen 40,80,120 sondern auch alle dazwischen 41,42,43 usw. annimmt und das /40 eine kommazahl geben würde...

K
593 Beiträge seit 2007
vor 14 Jahren

Klar geht das. Du kannst doch auf/abrunden 😉

3.971 Beiträge seit 2006
vor 14 Jahren

Wichtig bei Division mit Ganzzahlen, einen der Operanden vorher zu Float oder Double wandeln.

Es gibt 3 Arten von Menschen, die die bis 3 zählen können und die, die es nicht können...

2.891 Beiträge seit 2004
vor 14 Jahren

und das /40 eine kommazahl geben würde...

Wenn "abstand" ein Integer ist, kommt eben keine Kommazahl raus, sondern es wird die Ganzzahldivision durchgeführt. "41/40" und "79/40" ergeben dann auch "1".

Gruß
dN!3L

EDIT: Jaja, 40/40 ist 1, nicht 4...

925 Beiträge seit 2004
vor 14 Jahren

und das /40 eine kommazahl geben würde...
Wenn "abstand" ein Integer ist, kommt eben keine Kommazahl raus, sondern es wird die Ganzzahldivision durchgeführt. "41/40" und "79/40" ergeben dann auch "4".

Gruß
dN!3L

👍 getestet und bestätigt. Dachte gerade, da käme eigentlich 0 raus.

C
1 Beiträge seit 2009
vor 14 Jahren
Stocken bei Shooter-Spiel

um keine verzögerunge zu erhalten wegen dem runden da du ja int's definiert hast.. nimmst du doch einfach von anfang an floats 😄 dann wandern die ballone wieder flüssig von einer zu andern ecke

90% aller pc probleme sitzen vor dem Computer! that's it!

A
746 Beiträge seit 2007
vor 14 Jahren

Imho wird beim Teilen von ints nicht gerundet, sondern einfach nur der Nachkommateil abgeschnitten. Das ist dann wahrscheinlich auch schneller, als viel mit floats rumzurechnen.

Edith: 41/40 & 79/40 ergibt somit übrigens 1 (und nicht 3) =P

V
2 Beiträge seit 2009
vor 14 Jahren

@codebreaker

ich denke nicht dass du in irgendeiner weise eine ahnung von hänis problem, geschweige dann von c# hast. dir empfehle ich ersteinmal http://openbook.galileocomputing.de/csharp/ durchzulesen und zwar am besten 2 mal, weil beim ersten durchlesen viel "verloren" geht....

das mit den 41/40 in einen float packen ist zwar richtig, jedoch absolut sinnlos und sie werden nicht etwa ab 1,5 auf 2 aufgerundet, sondern wie Alf richtig gesagt hat wird der hintere teil "abgeschnitten"..

ich könnte mir vorstellen, dass es am überganswinkel der elemente im verhältnis zu den koordinaten liegen könnte. Das heisst wenn du das objekt mit einem irreellen logarithmus der koordinaten gleichstellen könntest, würde der übergang die konsistenz von wasser ab 0° celsius, also flüssig, erhalten.

wie wäre es wenn du dir einmal ein buch über c# durchlesen würdest häni? an deinem "unschönen" code an denke ich nämlich dass du auch nicht besonders viel ahnung dieser programmiersprache hast...

und diesen "if-else" teil würde ich auch mit einem switch, wie alf es gesagt hat, lösen, weil die switch funktion noch einmal weniger rechnerleistung benötigt als die if abfrage.

Weisst du einmal nicht weiter, frag nicht mich sondern werde gescheiter...

Gelöschter Account
vor 14 Jahren

ganz ruhig bitte.....

weil die switch funktion noch einmal weniger rechnerleistung benötigt als die if abfrage.

unbedeutend und auch nur in ganz bestimmten fällen wahr.

übrigens... schön das ihr meine idee übernimmt und als eigene verkauft 😉

wie dem auch sei. all das war vermutlich nciht die ursache des grundproblems. Daher die frage an den threadersteller: was hast du bis jetzt geändert und besteht das problem immer noch?

B
1 Beiträge seit 2009
vor 14 Jahren

Hallo zusammen, bin zwar ganz neu hier, hätte aber auch einen Vorschlag. Was haltet ihr davon ?



if(abstand % 40 == 0 ) // Abstand ohne Rest durch 40 teilbar
    AnzahlBallons ++ // Hier wird die Variable erhöht oder verringert


Gruss

V
2 Beiträge seit 2009
vor 14 Jahren

Ich will nicht behaupten, dass es falsch ist, löst aber das Problem nicht...

Um diese "Verzögerungen" oder "Stockungen" wegzubringen ist es essenziell, die Koordinaten "verschmelzend" aufzubauen, was soviel heisst wie diesen genannten Logarithm anzuwenden, und das Objekt (Ballon), wie Jack gesagt hat, anstatt mit einem "control" zu lösen mit einer Klasse zu "zeichnen"...

Des weiteren würde ich dir empfehlen, das ganze Programm objektorientert aufzubauen, da es gerade bei "Spielen" die Kunst ist, mit dieser Codeverschachtelung erstens redundante Codeteile zu vermeiden und den Ablauf strukturgemäss zu planen.

Bei Spielen allgemein empfehle ich, eine saubere Planung, für Anfänger mit PAP, zu erstellen, da man sonst schnell die Übersicht verliert und der Code unsauber wird, wie die Rechtschreibung von Jack...

Weisst du einmal nicht weiter, frag nicht mich sondern werde gescheiter...

458 Beiträge seit 2007
vor 14 Jahren

...da man sonst schnell die Übersicht verliert und der Code unsauber wird, wie die Rechtschreibung von Jack...

Sowas kannst du dir auch sparen.

be the hammer, not the nail!

42 Beiträge seit 2006
vor 14 Jahren

Ich würde auf jeden Fall zur GDI raten, Controls zu animieren ist wirklich nicht gerade der elegante Weg.
Das objektorientierte Programmieren gehört aber nunmal dazu (und eigentlich zu allem was irgendwie .net ist).

Von daher kann ich auch die von V0ruhm_Lu$€r 87 und JAck30lena geposten Links empfehlen:
http://openbook.galileocomputing.de/csharp/
[Artikel] Flackernde Controls und flackerndes Zeichnen vermeiden
(inkl. Links des ersten Beitrages).

PS. Irgendwie hat es mich nicht halten können und ich hab ein kleines Beispiel als Anregung erstellt, wie man sowas in der Art lösen könnte:

Eine Art klassischer Bildschirmschoner:
3 Bälle oder was auch immer, die immer an den Kanten abprallen.

Vielleicht läuft das ganze noch flüssiger, wenn man Integer-Werte benutzen würde, ist aber meiner Meinung nach schon recht flüssig.
Und man sollte das ganze über ne generische List<Ballon> laufen lassen, aber ist ja nur nen Beispiel.

Klasse Ballon

    public class Ballon
    {
      private float _x = 0f;
      private float _y = 0f;
      private float _width = 40f;
      private float _height = 40f;
      private float _movDirectionX;
      private float _movDirectionY;
      private float _speed = 3f;
      private Pen _penForeground = new Pen(Color.Black, 2f);
      private SolidBrush _brushBackground = new SolidBrush(Color.Red);

      public float Speed
      {
        get { return _speed; }
      }

      public float MovDirectionX
      {
        get { return _movDirectionX; }
        set { _movDirectionX = value; }
      }

      public float MovDirectionY
      {
        get { return _movDirectionY; }
        set { _movDirectionY = value; }
      }

      public float X
      {
        get { return _x; }
      }

      public float Y
      {
        get { return _y; }
      }

      public float Width
      {
        get { return _width; }
      }

      public float Height
      {
        get { return _height; }
      }

      // Das Umschließende Rechteck zurückgeben, damit nicht die
      // ganze PictureBox neugezeichnet werden soll.
      // Wegen der Rahmenstärke wird das Rechteck um 2px erweitert
      public RectangleF Bounds
      {
        get
        {
          RectangleF recCurr = new RectangleF(_x, _y, _width, _height);
          recCurr.Inflate(3f, 3f);
          return recCurr;
        }
      }

      // Konstruktoren
      public Ballon()
      {
      }

      public Ballon(float StartX, float StartY, SolidBrush Background, float Speed)
      {
        _x = StartX;
        _y = StartY;
        _brushBackground = Background;
        _speed = Speed;
        _movDirectionX = Speed;
        _movDirectionY = Speed;
      }

      /// <summary>
      /// Bewegt das Objekt um die übergebenen Koordinaten
      /// </summary>
      /// <param name="x"></param>
      /// <param name="y"></param>
      public void Move()
      {
        this._x += _movDirectionX;
        this._y += _movDirectionY;
      }

      /// <summary>
      /// Zeichnet das Objekt auf das übergebene Graphics-Objekt
      /// </summary>
      /// <param name="g"></param>
      public void Paint(Graphics g)
      {
        // Vereinfachter Ballon -> Ellipse ;)
        g.FillEllipse(_brushBackground, new RectangleF(_x, _y, _width, _height));
        g.DrawEllipse(_penForeground, new RectangleF(_x, _y, _width, _height));
      }
    }

Beispiel Form (kann in eine leere Form kopiert werden, da die Controls alle zur Laufzeit erzeugt werden. Die Klasse oben muss aber auch noch rein).

  public partial class Form1 : Form
  {
    //+---------------------------------------------------------------------------
    //| Eigenschaften
    //+---------------------------------------------------------------------------
    private Timer _timer;
    private Ballon _ballon1;
    private Ballon _ballon2;
    private Ballon _ballon3;
    private PictureBox _pbx;


    //+---------------------------------------------------------------------------
    //| Konstruktor
    //+---------------------------------------------------------------------------
    public Form1()
    {
      InitializeComponent();

      this.Width = 840;
      this.Height = 655;

      // PictureBox erstellen
      _pbx = new PictureBox()
      {
        Width = 800,
        Height = 600,
        Location = new Point(10, 10),
        BorderStyle = BorderStyle.FixedSingle,
        BackColor = Color.PeachPuff        
      };

      _pbx.Paint += new PaintEventHandler(pbx_Paint); // Paint EventHandler
      this.Controls.Add(_pbx);

      // Timer initialisieren
      _timer = new Timer()
      {
        Enabled = true,
        Interval = 30
      };
      _timer.Tick += new EventHandler(_timer_Tick);

      // 3 Ballons referenzieren
      _ballon1 = new Ballon(0f, 0f, new SolidBrush(Color.Red), 5f);
      _ballon2 = new Ballon(450f, 240f, new SolidBrush(Color.Blue), 8.4f);
      _ballon3 = new Ballon(320f, 520f, new SolidBrush(Color.Yellow), 6f);
    }


    void pbx_Paint(object sender, PaintEventArgs e)
    {
      e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
      // Immer im Paint-Ereignis zeichnen!
      _ballon1.Paint(e.Graphics);
      _ballon2.Paint(e.Graphics);
      _ballon3.Paint(e.Graphics);
    }


    void _timer_Tick(object sender, EventArgs e)
    {
      // Den Bereich in dem die Ballons WAREN neuzeichnen
      _pbx.Invalidate(Rectangle.Round(_ballon1.Bounds));
      _pbx.Invalidate(Rectangle.Round(_ballon2.Bounds));
      _pbx.Invalidate(Rectangle.Round(_ballon3.Bounds));

      MovingDirection(_ballon1);
      MovingDirection(_ballon2);
      MovingDirection(_ballon3);

      // Ballons bewegen
      _ballon1.Move();
      _ballon2.Move();
      _ballon3.Move();

      // Den Bereich in dem die Ballons jetzt SIND neuzeichnen
      _pbx.Invalidate(Rectangle.Round(_ballon1.Bounds));
      _pbx.Invalidate(Rectangle.Round(_ballon2.Bounds));
      _pbx.Invalidate(Rectangle.Round(_ballon3.Bounds));
    }

    // Bestimmt die Richtung, in die Bewegt wird
    private void MovingDirection(Ballon Ballon)
    {
      if (Ballon.X + Ballon.Width >= _pbx.Width) Ballon.MovDirectionX = -Ballon.Speed;
      if (Ballon.X <= 0) Ballon.MovDirectionX = Ballon.Speed;
      if (Ballon.Y + Ballon.Height >= _pbx.Height) Ballon.MovDirectionY = -Ballon.Speed;
      if (Ballon.Y <= 0) Ballon.MovDirectionY = Ballon.Speed;
    }
}

~ There's no knowledge that is not power~

H
Häni Themenstarter:in
5 Beiträge seit 2009
vor 14 Jahren

Ich möchte mich für meine Abwesenheit entschuldigen, ich habe mir eine Woche Spanien gegönnt 😁
unwichtiger kram beiseite...

danke andreas für deine ausführliche und hilfreiche antwort, bin jetzt dran es umzusetzen aber wie ich das sehe funktioniert es wirklich flüssig!

Ein herzliches danke von meiner seite und ich bin der meinung dass dieser thread geschlossen werden sollte, bevor fer V0ruhm_lo$€r noch mehr mit seinen logarithem und weiss ich was kommt o.O