Autor Beitrag
avoid
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 230
Erhaltene Danke: 4

MSDos, WinXP32, Win764, Win10, Android, Debian
msl (mIRC edit), html & php & Java (DreamweaverMX), Basic (picaxe PE6), C (Arduino IDE), C# (vs2010,2015,2017,2019,Unity,Android Studio)
BeitragVerfasst: Sa 06.09.14 00:39 
ich stümpre gerade etwas in 2D rum und habe versucht das schießen eines Raumschiffs nach zu stellen.
es wird zur Laufzeit eine PictureBox erzeugt in der später ein Sprite dargestellt werden soll.

weil die box viel zu schnell über das Bild huscht hab ich erst etwas mit Thread.Sleep(1) rum probiert
aber das friert mir ja die Anwendung ein und in einen eigenen Thread hab ich diese Funktion noch nicht ausgelagert.

dann dachte ich an einen Timer und hab versucht diesen zur Laufzeit zu erstellen.
doch wie es scheint kann ich im Tick-Event des Timer nicht mit dem zur Laufzeit erstellten Control arbeiten.

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
private void feuer_add(object sender, KeyEventArgs e)
{
    PictureBox feuer = new PictureBox();
    feuer.Anchor = (AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right);
    feuer.BackColor = Color.Blue;
    feuer.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None;
    feuer.Left = pictureBox_schiff.Location.X + pictureBox_schiff.Height / 2;
    feuer.Top = pictureBox_schiff.Location.Y - pictureBox_schiff.Height;
    pos1 = feuer.Top;
    feuer.Name = "new_feuer";
    feuer.Size = new Size(1010);
    feuer.TabStop = false;
    this.Controls.Add(feuer);
    feuer.Parent.Name = "new_feuer";
    feuer.BringToFront();

    System.Windows.Forms.Timer ftimer = new System.Windows.Forms.Timer();
    ftimer.Tick += new EventHandler(ftimer_Tick);
    ftimer.Interval = 1;
    ftimer.Enabled = true;
}



hat wer eine Idee?

Gruß,
avoid

_________________
Gute Fragen sind wie ein wissenschaftliches Experiment. Sie setzen eine Menge Wissen bereits voraus.
bitcoin:1J5dgQQp8eUy8wkUxyztBUVCkCpo5MQEQs?label=Danke
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4795
Erhaltene Danke: 1059

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: Sa 06.09.14 08:47 
Hallo avoid,

was ist deine eigentliche Frage, d.h. was funktioniert bei deinem Code nicht?
Generell funktioniert ein System.Windows.Forms.Timer schon so, du solltest den Timer aber zum einen als Membervariable der Klasse erstellen und zum anderen die Initialisierung im Konstruktor vornehmen - einzig das Ein- und Ausschalten (Enabled) sollte dann in das Aktivierungsereignis.

Bei deinem Code bisher könnte es sein, daß der GC den Timer wieder entfernt, da er nur als lokale Variable existiert.

PS: Zur Info: dieser Timer hat (unter Windows) ein Mindestintervall von ca. 14-15 ms (d.h. als max. Frequenz ca. 70).

PPS: Du mußt aber bei deinem jetzigen Code noch irgendwo die Verbindung von deinem PictureBox-Objekt (bzw. den Objekten) zum Timer erstellen - oder woher weiß die Timer.Tick-Methode, welches Objekt sie verändern soll? Am besten, du packst die Objekte in eine Collection, z.B. List<Control>.
avoid Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 230
Erhaltene Danke: 4

MSDos, WinXP32, Win764, Win10, Android, Debian
msl (mIRC edit), html & php & Java (DreamweaverMX), Basic (picaxe PE6), C (Arduino IDE), C# (vs2010,2015,2017,2019,Unity,Android Studio)
BeitragVerfasst: Sa 06.09.14 09:01 
oh, sorry ;)
hab echt vergessen ne frage zu formulieren ...

wie kann ich außerhalb von "feuer_add" mit der PictureBox "feuer" arbeiten?
weil das Control erst zur Laufzeit erstellt wird kann ich ja dafür noch keinen Code schreiben der es behandelt.
kann ich das über die List<Control> lösen?

wenn ich es mir genau überlege ist mein Lösungsansatz mehr als komisch.
kennt wer eine bessere Lösung um ein zur Laufzeit erstelltes Control (schießen eines Raumschiff) in einem festen tempo über die form zu bewegen und am Rand des form zu removen als mit Timer oder Thread.Sleep ?

_________________
Gute Fragen sind wie ein wissenschaftliches Experiment. Sie setzen eine Menge Wissen bereits voraus.
bitcoin:1J5dgQQp8eUy8wkUxyztBUVCkCpo5MQEQs?label=Danke
avoid Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 230
Erhaltene Danke: 4

MSDos, WinXP32, Win764, Win10, Android, Debian
msl (mIRC edit), html & php & Java (DreamweaverMX), Basic (picaxe PE6), C (Arduino IDE), C# (vs2010,2015,2017,2019,Unity,Android Studio)
BeitragVerfasst: Sa 06.09.14 10:41 
ich hab in der Vergangenheit mal diesen code verwendet, ich denke mal damit könnte ich es evtl. hin bekommen.

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
private void pictureBox_MouseClickR(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Right) // lösche picturebox
            {
                panel1.Controls.Remove((Control)sender);
                var CountOfMyLovelyPictureBoxes = panel1.Controls.OfType<PictureBox>().Where(x => x.Name.StartsWith("new_")).Count();
                label1.Text = CountOfMyLovelyPictureBoxes.ToString() + " kopien erstellt.";
                boxen = panel1.Controls.OfType<PictureBox>().Where(x => x.Name.StartsWith("new_")).ToArray();
            }
        }


leider hatte ich sie damals einem panel1 untergeordnet, dieses mal liegen sie nur auf der form.
ich sollte wohl wieder ein Panel über die form legen.

_________________
Gute Fragen sind wie ein wissenschaftliches Experiment. Sie setzen eine Menge Wissen bereits voraus.
bitcoin:1J5dgQQp8eUy8wkUxyztBUVCkCpo5MQEQs?label=Danke
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4795
Erhaltene Danke: 1059

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: Sa 06.09.14 11:52 
Hallo,

da ist noch einiges an deinem Code zu verbessern.
Der Vorteil einer eigenen Liste ist es, daß nicht erst in der Controls-Collection nach bestimmten Klassen bzw. Instanzen gesucht werden muß, sondern du sie selber verwaltest.
Außerdem macht es dann auch keinen Unterschied, auf welchem Parent-Control diese Controls liegen (sollte aber generell keinen Unterschied machen).

Beim Hinzufügen und Löschen mußt du dann selbstverständlich sowohl die Controls-Collection als auch die eigene Liste aktualisieren, am besten du schreibst dir dann entsprechende Hilfsmethoden dafür.
C#
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 561
Erhaltene Danke: 65

Windows 10, Kubuntu, Android
Visual Studio 2017, C#, C++/CLI, C++/CX, C++, F#, R, Python
BeitragVerfasst: Sa 06.09.14 18:42 
Also so wie es aussieht willst du ja ein kleines Spiel machen - habe ich recht? Dort mit Controls zu arbeiten könnte schwierig bis problematisch werden. Ein Spiel sollte einen Logikteil und einen Grafikteil haben, der möglichst getrennt ist. Graphics ist hier ein Stichwort, wenn du auf WinForms bleiben willst. Von 1000 Pictureboxen würde ich dir abraten.

_________________
Der längste Typ-Name im .NET-Framework ist: ListViewVirtualItemsSelectionRangeChangedEventHandler
avoid Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 230
Erhaltene Danke: 4

MSDos, WinXP32, Win764, Win10, Android, Debian
msl (mIRC edit), html & php & Java (DreamweaverMX), Basic (picaxe PE6), C (Arduino IDE), C# (vs2010,2015,2017,2019,Unity,Android Studio)
BeitragVerfasst: Sa 06.09.14 20:56 
ein spiel soll es werden wenn es groß ist, ja. ;)
ich teste im Moment nur etwas rum um mir Grundlagen zu erarbeiten.

aktuell geht es wirklich nur um das feuern mittels Leertaste.
weil die Grafik für das Feuer ein Sprite werden wird, bewege ich ein PictureBox Control dafür durch die Gegend.
Problem dabei ist, das sich die PictureBox ohne eine Verzögerung viel zu schnell bewegt so das es nicht gut rüber kommt.

von dieser zur Laufzeit erzeugten PictureBox wird immer nur eine vorhanden sein,
weil ein erneutes feuern erst möglich wird wenn die PictureBox Removed ist.
Das soll bei Kollision mit einem Gegner oder Hindernis bzw. beim erreichen des Rand der Form passieren.
also keine sorge um 1000 Pictureboxen. :)

das verzögern der Bewegung mittels Thread.Sleep(x) friert für diese Zeit leider die Anwendung ein.
später werde ich die Aktualisierung der Darstellung in einen eigenen Thread auslagern.

aber im Grunde muss ich die Bewegung timen weswegen ich an ein Timerelement dachte.

-----------------

da ich nur eine feuer PictureBox, gleichzeitig, zur Laufzeit erzeuge ist deren Name eindeutig.
das bedeutet außerdem, ich brauche nicht für jede feuer PictureBox einen Timer zu Laufzeit erzeugen.
es genügt wohl wenn ich einen Timer dafür erzeuge der dann falls vorhanden die feuer PictureBox bewegt.

Richtung, Position, Lebenszeit und Kollision kann ich in globalen variablen ablegen wodurch ich aus allen Methoden zugriff auf die Infos habe und damit arbeiten kann und somit dem Timer nichts übergeben muss.

ich glaube so versuche ich es mal.
drückt mir die Daumen.

_________________
Gute Fragen sind wie ein wissenschaftliches Experiment. Sie setzen eine Menge Wissen bereits voraus.
bitcoin:1J5dgQQp8eUy8wkUxyztBUVCkCpo5MQEQs?label=Danke
C#
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 561
Erhaltene Danke: 65

Windows 10, Kubuntu, Android
Visual Studio 2017, C#, C++/CLI, C++/CX, C++, F#, R, Python
BeitragVerfasst: Sa 06.09.14 21:44 
In Spielen wird es im Prinzip genau so gemacht. Ein Objekt (in deinem Fall der Schuss) wird erzeugt und auf dem Spielfeld platziert. Ein externer Trigger (z.B. von der Game-Engine) löst in jedem Objekt eine Update-Funktion aus - in der Regel mit 60Hz. Um ein Objekt zu bewegen, wird in der Update-Funktion die Position des Objekts um einen bestimmten Vektor (Geschwindigkeit, velocity) - in Abhängigkeit der Zeit zwischen zwei Update-Aufrufen - verschoben.
Das würde im Konkreten so aussehen:
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
Vector2 velocity = new Vector2(25);

void Update(float deltaTime)
{
  gameObject.Position += velocity * deltaTime;
}


In deinem Fall würde es etwa so aussehen:
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
Point direction = new Point(21);

void Shoot()
{
  pictureBox.Location = ship.Location;
  pictureBox.Visible = true;
  shootTimer.Enabled = true;
}

void ShootTimer_Tick(objects sender, EventArgs e)
{
  pictureBox.Location += new Point(direction.X * shootTimer.Interval, direction.Y * shootTimer.Interval);
  if (/* Deine Kollisionsberechnung */)
  {
    pictureBox.Visible = false;
    shootTimer.Enabled = false;
  }
}

Das Timer-Intervall sollte dann bei >25Hz liegen um eine flüssige Bewegung zu simulieren.

PS: Ich entwickle gerade auch mein eigenes Spiel und ich weis, wie viel Arbeit in so einem Projekt steckt. Also Zähne zusammenbeißen und dran bleiben. So etwas kostet Nerven^^ ;)
Viel Glück

_________________
Der längste Typ-Name im .NET-Framework ist: ListViewVirtualItemsSelectionRangeChangedEventHandler
Palladin007
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1282
Erhaltene Danke: 182

Windows 11 x64 Pro
C# (Visual Studio Preview)
BeitragVerfasst: Sa 06.09.14 23:05 
Ich werfe mal die Methode Task.Delay(int) in den Raum.

Die macht ungefähr das Gleiche, wie Thread.Sleep, jedoch mit dem kleinen feinen Unterschied, dass das in einem anderen Task geschieht.

Im Grund passiert Folgendes:

Der Code befindet sich im GUI-Thread und kommt bei Task.Delay an.
Task.Delay erstellt intern einen Thread, der die angegebene Zeit wartet.
Während der Thread zählt, wird die aktuelle Methode "beiseite gelegt" und der GUI-Thread läuft weiter.
Ist die vorgegebene Zeit abgelaufen, kehrt das Programm wieder in die Methode zurück, wo es vorher unterbrochen hat und läuft weiter.

Der Vorteil zu einem Thread ist, dass man nicht darauf achten muss, dass alle benutzten Objekte MultiThreading-fähig sind.
Der Timer hat das Problem zwar auch nicht, allerdings ist es umfangreicher, das Selbe zu erreichen.


Probiere das mal aus, ich könnte mir vorstellen, dass das dein Ausgangsproblem sehr kurz und knapp behebt.

Für diesen Beitrag haben gedankt: C#
avoid Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 230
Erhaltene Danke: 4

MSDos, WinXP32, Win764, Win10, Android, Debian
msl (mIRC edit), html & php & Java (DreamweaverMX), Basic (picaxe PE6), C (Arduino IDE), C# (vs2010,2015,2017,2019,Unity,Android Studio)
BeitragVerfasst: So 07.09.14 11:07 
C#
sehe ich das richtig, du hast die PictureBox nicht erst zur Laufzeit erzeugt sondern änderst im Grunde immer nur ob sie sichtbar ist und ihre Position?
geile Idee!

Palladin007
ich hab es kurz mal versucht mit Task.Delay(50); aber leider zeigt mir VS2010 an "System.Threading.Tasks.Task" enthält keine Definition für "Delay".

_________________
Gute Fragen sind wie ein wissenschaftliches Experiment. Sie setzen eine Menge Wissen bereits voraus.
bitcoin:1J5dgQQp8eUy8wkUxyztBUVCkCpo5MQEQs?label=Danke
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4795
Erhaltene Danke: 1059

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: So 07.09.14 11:23 
Task.Delay gibt es erst seit .NET 4.5, d.h. im VS 2012.
Ich persönlich halte den Timer hier (immer noch) für die beste Lösung.

Und ich bin bei meinem Vorschlag mit der Liste davon ausgegangen, daß du mehrere Schüsse anzeigen möchtest.
Wenn du dich, so wie der User user profile iconC# nur auf genau ein Objekt festlegst, so müsstest du dann mehr umbauen, wenn du dann doch mehrere Schüsse mal anzeigen möchtest (und sei es für einen Gegner).
C#
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 561
Erhaltene Danke: 65

Windows 10, Kubuntu, Android
Visual Studio 2017, C#, C++/CLI, C++/CX, C++, F#, R, Python
BeitragVerfasst: So 07.09.14 12:00 
Ich dachte mir schon das Task.Delay neu ist...
Was mein Code angeht: user profile iconavoid hat ja gesagt, dass immer nur ein Schuss existiert. Dann kann man sich ja die Liste sparen. Natürlich wird er so Probleme bekommen, wenn mehr Objekte wie Schiffe, Schüsse und Gegner hinzukommen. Aber Controls an sich eignen sich so oder so nicht, wenn das Spiel mal Gestalt annehmen soll. Bei größeren Projekten wird es dann auch mit WinForms schwierig.

PS: Was machst du wenn du z.B. eine Rakete abfeuerst, die auf ein Ziel fliegt, dass sich bewegt? Dann müsstest du ja dein Bild drehen und da ist bei der PictureBox schon schluss. Unter Verwendung von Graphics hast du da schon weniger Probleme.

_________________
Der längste Typ-Name im .NET-Framework ist: ListViewVirtualItemsSelectionRangeChangedEventHandler
avoid Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 230
Erhaltene Danke: 4

MSDos, WinXP32, Win764, Win10, Android, Debian
msl (mIRC edit), html & php & Java (DreamweaverMX), Basic (picaxe PE6), C (Arduino IDE), C# (vs2010,2015,2017,2019,Unity,Android Studio)
BeitragVerfasst: So 07.09.14 15:09 
aktuell bau ich nur was total einfachen wie das hier
gamedevsoc.eusa.ed.ac.uk/?page_id=578

wenn das geklappt hat geh ich einen schritt weiter und versuche warsheep nach zu bauen.

wenn ich danach komplexere Ideen habe kann ich mir ja mal eine 2D-Engine ansehen.

----nachtrag----

ja laut mircosoft kann vc2010 nur max .net4.0
hilft es was wenn ich ".NET Framework 4.5.2 Developer Pack" nach installiere?

Th69
wenn ich die PictureBox nicht zur Laufzeit erzeuge,
kann ich auch mit dem Timer arbeiten weil ich nichts übergeben muss.

----edit----
link angepasst

_________________
Gute Fragen sind wie ein wissenschaftliches Experiment. Sie setzen eine Menge Wissen bereits voraus.
bitcoin:1J5dgQQp8eUy8wkUxyztBUVCkCpo5MQEQs?label=Danke


Zuletzt bearbeitet von avoid am Fr 03.04.15 17:13, insgesamt 1-mal bearbeitet
C#
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 561
Erhaltene Danke: 65

Windows 10, Kubuntu, Android
Visual Studio 2017, C#, C++/CLI, C++/CX, C++, F#, R, Python
BeitragVerfasst: So 07.09.14 17:09 
Also erst mal: Warsheep ist nicht so leicht nachzubauen. Jedenfalls nicht ohne Engine. Das wird dich einiges an Arbeit kosten. Da sind Texturen, Sounds, Animationen, ... die eingebunden werden müssen.
.NET 4.5 läuft nicht mit VS2010, egal ob Developer Pack oder nicht.

Du kannst deine PictureBox auch ohne Probleme zur Laufzeit erzeugen. Wenn du dann wirklich mehrere Schüsse auf dem Feld hast ist das sinnvoller! Wie user profile iconTh69 schon gesagt hat: leg dir eine Liste an.
ausblenden volle Höhe 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:
public partial class Form1 : Form
  {
    List<PictureBox> bullets = new List<PictureBox>();
    Timer timer = new Timer();
    Image shot;
    Random rnd = new Random();

    public Form1()
    {
      InitializeComponent();
      shot = Image.FromFile("Dein Pfad zum Bild");
      timer.Interval = 40;
      timer.Tick += TimerTick;
      timer.Start();
    }    

    void Shoot()
    {
      PictureBox pb = new PictureBox
      {
        Image = shot,
        Location = new Point(4050),
        Tag = new Point(rnd.Next(50150), rnd.Next(50150)),  // in der Tag-Eigenschaft könntest du dann die "Flugrichtung" deiner PictureBox speichern
      };
      bullets.Add(pb);
      Controls.Add(pb);
    }

    void TimerTick(object sender, EventArgs e)
    {
      foreach (PictureBox pb in bullets)
      {
        Point velocity = (Point) pb.Tag;
        pb.Location = new Point((int)(pb.Location.X + velocity.X * timer.Interval / 1000f), (int)(pb.Location.Y + velocity.Y * timer.Interval / 1000f));
        if (pb.Location.X > Width || pb.Location.X < 0 || pb.Location.Y > Height || pb.Location.Y < 0// Die Kollisionsabfrage
        {
          Controls.Remove(pb);
          pb.Dispose();
        }
      }

      bullets = bullets.Where(pb => !pb.IsDisposed).ToList();  // zerstörte PictureBoxen löschen
    }

    private void Form1_KeyDown(object sender, KeyEventArgs e)
    {
      if (e.KeyCode == Keys.Space) Shoot();
    }
  }

Diesen Code kannst du mal kompilieren und sehen was passiert. Ein weiteres Problem ist, dass Control.Location vom Typ Point ist und dieser aus Integer-Variablen, also Ganzzahlen, besteht. Ist nun die Fluggeschwindigkeit oder das Timerintervall sehr niedrig, kommt bei der Positionsberechnung Zahlen wie 0.08 raus. Wird das zu int gecastet, ist der Wert nur noch 0, was bedeutet, dass deine PictureBox einfach auf der Stelle stehen bleibt. Deshalb habe ich bei Tag = new Point(rnd.Next(50150), rnd.Next(50150)) auch so hohe Zahlen genommen.


Was das Thema Engine angeht, könntest du dir mal FlatRedBall anschauen. Das ist eine kleine 2D und 3D Engine für C#.
Falls du gleich mit was großem anfangen willst, guck dir Unity an. Da versuche ich mich gerade dran.

_________________
Der längste Typ-Name im .NET-Framework ist: ListViewVirtualItemsSelectionRangeChangedEventHandler