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

1

19.10.2012, 15:33

C# Problem mit foreach-Schleife

Ich habe eine enemy und eine bullet-Klasse gemacht die beide fast identisch aussehen. Das Ganze läuft auch, jedoch nicht so wie es eigentlich gedacht war.
Jeder Gegner soll in gleichmäßigen Abständen Kugeln schießen. Deshalb habe ich die float Variablen fNextShoot und fShootFreq erstellt. Erst wenn fNextShoot größer als fShootFreq ist soll ein neuer Schuss gestartet werden.
Im Moment ist es aber so dass nur der erste Gegner Kugeln schießen kann. Außerdem fliegen die Kugeln am Anfang diagonal nach unten rechts, einige Zeit später fliegen sie auf einmal nur noch diagonal nach oben links und der zeitliche Abstand zwischen den Kugeln ist auch nicht mehr derselbe wie am Anfang.
Ich gehe davon aus dass der Fehler in der ersten foreach-Schleife der Update-Methode liegt. Ich weiß aber nicht was ich an Schleife ändern soll ?(
Was soll ich an dem Code ändern damit jeder Gegner in gleichmäßigen Abständen schießt?

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
public class map
{
        Texture2D myEnemy, myBullet, hintergrund;
player Player;
List<enemy> enemieslist = new List<enemy>();
List<bullet> bulletslist = new List<bullet>();

        float fNextShoot = 0.0f;float fShootFreq = 1.0f;
float fNextEnemy = 0.0f;
float fEnemyFreq = 2.0f;

        Vector2 Startposition = new Vector2(200, 200);
Vector2 AktuelleGegnerPos;

        GraphicsDeviceManager graphicsDevice; 

    public map(GraphicsDeviceManager device) 
    { 
graphicsDevice = device; 
    } 
 
        public void Load(ContentManager content)
    {
    myEnemy = content.Load<Texture2D>("gegner");
    myBullet = content.Load<Texture2D>("kugel"); 
    hintergrund = content.Load<Texture2D>("background");
    Player = new player(graphicsDevice);
    Player.Load(content);
    }
 
        public void Update(GameTime gameTime)
        {
            this.fNextShoot += (float)gameTime.ElapsedGameTime.TotalSeconds;
            foreach (enemy enemies in enemieslist)
            {
                enemies.Update(gameTime, this.graphicsDevice, Player.spielershape.Position);
                AktuelleGegnerPos = enemies.Kugelstartposition;
                if (this.fNextShoot > fShootFreq)
                {
                    Vector2 vShootMove;
                    vShootMove = Vector2.Normalize(Player.spielershape.Position - AktuelleGegnerPos) * 200f;
                    bullet bullets = new bullet(AktuelleGegnerPos, vShootMove, Player.spielershape.Position);
                    bulletslist.Add(bullets);
                 this.fNextShoot -= fShootFreq; 
                }
            }
        
            List<enemy> tempenemylist = new List<enemy>();

            foreach (enemy enemies in enemieslist)
            {
                if (!enemies.bRemove)
              {
                    tempenemylist.Add(enemies);
                }
            }
 
            enemieslist = tempenemylist;
this.fNextEnemy += (float)gameTime.ElapsedGameTime.TotalSeconds;
            if (this.fNextEnemy > fEnemyFreq)
            {
                Vector2 vShootMove;
                vShootMove = Vector2.Normalize(Player.spielershape.Position - Startposition) * 100f;
enemy enemies = new enemy(Startposition,
vShootMove, Player.spielershape.Position);
               enemieslist.Add(enemies);
                this.fNextEnemy -= fEnemyFreq;
            }

            foreach (bullet bullets in bulletslist)
            {
bullets.Update(gameTime, this.graphicsDevice);
            }

            List<bullet> tempbulletlist = new List<bullet>();
 
            foreach (bullet bullets in bulletslist)
            {
                if (!bullets.bRemove)
                {
                   tempbulletlist.Add(bullets);
                }
            }
 
            bulletslist = tempbulletlist;
        }


Sacaldur

Community-Fossil

Beiträge: 2 301

Wohnort: Berlin

Beruf: FIAE

  • Private Nachricht senden

2

19.10.2012, 15:37

wenn du von jedem Spieler/Gegner/... willst, dass dieser in einer bestimmten Frequenz schießt, dann solltest du auch für jeden Spieler speichern, wann er zuletzt geschossen hat
ansonsten wird einfach nur 1 Schuss für alle Spieler abgegeben und die Häufigkeit hängt von der Anzahl der Spieler/Gegner/... ab

da du die Position des Bulluts anscheinend in der Bullet Klasse aktualisierst, kann ich dazu nichts weiter schreiben... =/
Spieleentwickler in Berlin? (Thema in diesem Forum)
---
Es ist ja keine Schande etwas falsch zu machen, als Programmierer tu ich das täglich, [...].

3

19.10.2012, 16:54

Wie soll ich die Schüsse am besten speichern? Soll ich den unteren Teil der Update-Methode(ab der foreach-bullet-Schleife) der map-Klasse umändern?
Hier noch meine bullet-Klasse:

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
class enemy
 {
        Vector2 vPos;
        Vector2 vMove;
        Vector2 vPlayer;
        public bool bRemove;

        public enemy(Vector2 Pos, Vector2 Move, Vector2 Player)
        {
            this.bRemove = false;
            this.vPos = Pos;
            this.vMove = Move;
            this.vPlayer = Player;
        }
 
        public void Update(GameTime gameTime, GraphicsDeviceManager graphics)
        {
            if (!bRemove)
            {
            float fMoveTime = (float)gameTime.ElapsedGameTime.TotalSeconds;
            this.vPos += this.vMove * fMoveTime;
                if (this.vPos.X > graphics.PreferredBackBufferWidth + 1)
                {
                    this.bRemove = true;
                }
                else
if (this.vPos.X < -20)
                {
                    this.bRemove = true;
                }
 
                if (this.vPos.Y > graphics.PreferredBackBufferHeight + 1)
                {
                    this.bRemove = true;
}
                else
if (this.vPos.Y < -20)
                {
                    this.bRemove = true;
                }
            }
        }

        public void Draw(SpriteBatch spriteBatch, Texture2D myTexture)
        {
         if (!bRemove)
            {
                spriteBatch.Draw(myTexture, this.vPos, Color.White);
            }
        }
 }

Yannic

unregistriert

4

19.10.2012, 19:25

Ich weiß, das ist für das Thema nicht so wichtig, aber wenn du evtl. später mit anderen Leuten zusammen arbeiten möchtest, ein paar Stilregeln für C# :
- Präfix für Variablen...geht gar nicht.
- myClassName, ein my davor schreiben macht man um Anfängern was beizubringen, als Parameter vllt. nicht ganz so toll.
- Klassennamen in Pascal Case(bspw. Enemy anstatt enemy), öffentliche(public) Variablen ebenso.
- Irgendwie ist die Formatierung bei den if-Bedibgungen komisch, so an den Rand gerückt...
- Paramtername in Camel Case(du mixt da auch noch, Konsistenz ist gefragt)

Falls du das jetzt irgendwie schlimm findest, kannst du ja einem Moderator bescheid sagen, ob er das bitte entfernen könnte, in dem Fall entschuldige ich mich.
War aber als konstruktive Kritik gedacht. :thumbup:

Bu1

Frischling

Beiträge: 66

Beruf: Schüler

  • Private Nachricht senden

5

20.10.2012, 14:10

Du speicherst in der enemy Klasse eine Variable

Quellcode

1
float lastShot;


in dieser Speicherst du wie lange es her war, dass der Gegner das letzte mal geschossen hat.

In der Update-Methode verringerst du erhöst du diesen Wert immer um die Vergangene Zeit. Wenn sie größer ist als "fShootFreq", dann setzt du lastShot auf 0 und lässt den Gegner einen Schuss machen.

In der Update der Enemy-Klasse

Quellcode

1
2
3
4
5
6
7
8
lastShot += (float)gameTime.ElapsedGameTime.TotalSeconds;
if(lastShot > fHootFreq)
{
    lastShot = 0;
    Vector2 vShootMove;
    vShootMove = Vector2.Normalize(Player.spielershape.Position - this.vPos) * 200f;
    bullet bullets = new bullet(this.vPos, vShootMove, Player.spielershape.Position);
    bulletslist.Add(bullets);}

Zitat

Sämtliche Rechtschreibfehler in diesem Beitrag sind nicht urheberrechtlich geschützt :!:
Sie können nach belieben kopiert und weiterverwändet werden. :P

hawkeye_de

Frischling

Beiträge: 70

Wohnort: Baden-Württemberg

  • Private Nachricht senden

6

20.10.2012, 14:53

Ich weiß, das ist für das Thema nicht so wichtig, aber wenn du evtl. später mit anderen Leuten zusammen arbeiten möchtest, ein paar Stilregeln für C# :
- Präfix für Variablen...geht gar nicht.
- myClassName, ein my davor schreiben macht man um Anfängern was beizubringen, als Parameter vllt. nicht ganz so toll.
- Klassennamen in Pascal Case(bspw. Enemy anstatt enemy), öffentliche(public) Variablen ebenso.
- Irgendwie ist die Formatierung bei den if-Bedibgungen komisch, so an den Rand gerückt...
- Paramtername in Camel Case(du mixt da auch noch, Konsistenz ist gefragt)
Ich kann Yannic nur zustimmen...der Code ist etw. schwer zu lesen...also wenn jetzt daraus ein 'richtiges' Projekt werden soll, schau einfach mal http://msdn.microsoft.com/de-de/library/…o/ff926074.aspx an.

Sie die Schleifen

C#-Quelltext

1
2
3
4
5
6
7
8
  foreach (enemy enemies in enemieslist)            {
                if (!enemies.bRemove)
              {
                    tempenemylist.Add(enemies);
                }
            }
 
            enemieslist = tempenemylist;


und folgende nicht etw. umständlich, mein warum removest Du nicht einfach das Objekt?
"Große Geister besprechen Ideen; durchschnittliche Geister besprechen Ereignisse; kleine Geister besprechen andere Leute"

-Admiral USN Hyman Rickover, Vater des 1. Atom U-Boots "Nautilus"

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »hawkeye_de« (20.10.2012, 14:59)


Thunetoft

Frischling

Beiträge: 10

Wohnort: Brechen

Beruf: SW-Developer

  • Private Nachricht senden

7

20.10.2012, 20:29

Hallo,
und folgende nicht etw. umständlich, mein warum removest Du nicht einfach das Objekt?
Hallo,
da er an dieser Stelle eine foreach-Schleife verwendet, kann er das Objekt nicht direkt removen, da innerhalb einer foreach-Schleife die Collection über die iteriert wird nicht verändert werden darf (sonst fliegt eine Exception).

Wenn man direkt in der Schleife löschen will, muss man mit einer for-Schleife und dem Index über die Collection laufen. (aber hierbei muss man auf aufpassen, da sich die Indizes durch das löschen auch verändern.

BlueCobold

Community-Fossil

Beiträge: 10 738

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

8

20.10.2012, 21:34

Genau dafür gibt es RemoveAll mit Predicates, da spart man sich den kompletten Aufwand und die Problematik mit concurrent modifications.
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]

hawkeye_de

Frischling

Beiträge: 70

Wohnort: Baden-Württemberg

  • Private Nachricht senden

9

20.10.2012, 22:32

Hallo,
und folgende nicht etw. umständlich, mein warum removest Du nicht einfach das Objekt?
Hallo,
da er an dieser Stelle eine foreach-Schleife verwendet, kann er das Objekt nicht direkt removen, da innerhalb einer foreach-Schleife die Collection über die iteriert wird nicht verändert werden darf (sonst fliegt eine Exception).

Wenn man direkt in der Schleife löschen will, muss man mit einer for-Schleife und dem Index über die Collection laufen. (aber hierbei muss man auf aufpassen, da sich die Indizes durch das löschen auch verändern.
Ja hast recht, die ellegantere Lösung ist, wie von BlueCobold erwähnt, Remove All,

also

C#-Quelltext

1
bulletlist.RemoveAll(bullet=>bullet.bRemove)


und Du hast gleich zig-zeilen überflüssig gemacht.
"Große Geister besprechen Ideen; durchschnittliche Geister besprechen Ereignisse; kleine Geister besprechen andere Leute"

-Admiral USN Hyman Rickover, Vater des 1. Atom U-Boots "Nautilus"

10

22.10.2012, 13:43

Was haltet ihr von den for-Schleifen in der Map-Klasse? Ist das gut so?
Mit RemoveAll habe ich noch nie gearbeitet deshalb weiss ich nicht ob ich das überhaupt in meinem Code brauche und was ich ändern müsste.


Ich habe aber noch ein kleines Probem mit den Kugeln. Jeder Gegner darf erst wieder schießen wenn seine Kugel durch Kollision oder aus dem Bild verschwindet. Jeder Gegner soll unabhängig von den anderen Gegnern schießen. Im Moment ist es aber so dass nur eine Kugel auf dem Bildschirm ist anstatt eine pro Gegner. Bei 3 Gegnern ist also nur eine Kugel auf dem Bildschirm obwohl 3 Kugeln möglich sein müssten. Wie kann ich das Problem lösen?


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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
public class Map{
    Texture2D myEnemy, myBullet;
    Player Player;
    List<Enemy> enemieslist = new List<Enemy>();
    List<Bullet> bulletslist = new List<Bullet>();

    float fNextEnemy = 0.0f;
    float fEnemyFreq = 3.0f;
    int fMaxEnemy = 3;

    Vector2 Startposition = new Vector2(200, 200);
    Vector2 currentEnemyPosition;

    GraphicsDeviceManager graphicsDevice; 

    public Map(GraphicsDeviceManager device) 
    { 
        graphicsDevice = device;

    } 

    public void Load(ContentManager content)
    {
    myEnemy = content.Load<Texture2D>("enemy");
    myBullet = content.Load<Texture2D>("bullet"); 
    Player = new Player(graphicsDevice);
    Player.Load(content);
    }

    public void Update(GameTime gameTime)
    {
        Player.Update(gameTime);
        float delta = (float)gameTime.ElapsedGameTime.TotalSeconds;

         for(int i = enemieslist.Count - 1; i >= 0; i--) 
        {
        // Update Enemy
        Enemy enemy = enemieslist[i];
        enemy.Update(gameTime, this.graphicsDevice, Player.playershape.Position, delta);
        currentEnemyPosition = enemy.Bulletstartposition;
        // Try to remove an enemy
        if (enemy.Remove == true)
        {
            enemieslist.Remove(enemy);
            enemy.Remove = false;
        }

        // Does the enemy shot?
        if ((enemy.Shot == true) && (bulletslist.Count < 1))
        // New bullet
          {
          Vector2 bulletDirection = Vector2.Normalize(Player.playershape.Position - currentEnemyPosition) * 200f;
          bulletslist.Add(new Bullet(currentEnemyPosition, bulletDirection, Player.playershape.Position));
          enemy.Shot = false;
          }
        }

        this.fNextEnemy += delta;
        //New enemy
        if (fMaxEnemy > 0)
        {
        if ((this.fNextEnemy >= fEnemyFreq) && (enemieslist.Count < 3))
        {
            Vector2 enemyDirection = Vector2.Normalize(Player.playershape.Position - Startposition) * 100f;
            enemieslist.Add(new Enemy(Startposition, enemyDirection, Player.playershape.Position));
            fMaxEnemy -= 1;
            fNextEnemy -= fEnemyFreq;
        }
        }

    for(int i = bulletslist.Count - 1; i >= 0; i--) 
    {
        // Update Bullet
        Bullet bullets = bulletslist[i];   
        bullets.Update(gameTime, this.graphicsDevice, delta);

        // Try to remove a bullet... Collision, hit, or outside screen.
        if (bullets.Remove == true)
            bulletslist.Remove(bullets);
        bullets.Remove = false;
    }              
  }

    public void Draw(SpriteBatch batch)
    {

        Player.Draw(batch);
        foreach (Enemy enemies in enemieslist)
        {
            enemies.Draw(batch, myEnemy);
        } 
        foreach (Bullet bullets in bulletslist)
        {
            bullets.Draw(batch, myBullet);
        } 
    }      
}

public class Enemy
{
 private float nextShot = 0;
 private float shotFrequency = 2.0f;  

    Vector2 vPos;
    Vector2 vMove;
    Vector2 vPlayer;
    public Vector2 Bulletstartposition;
    public bool Remove;
    public bool Shot;

    public Enemy(Vector2 Pos, Vector2 Move, Vector2 Player)
    {
        this.vPos = Pos;
        this.vMove = Move;
        this.vPlayer = Player;
        this.Remove = false;
        this.Shot = false;
    }

    public void Update(GameTime gameTime, GraphicsDeviceManager graphics, Vector2 PlayerPos, float delta)
    {           
        nextShot += delta;

        if (nextShot >= shotFrequency)
            {
            this.Shot = true;
            nextShot -= shotFrequency;
            }

        if (!Remove)
        {
            this.vMove = Vector2.Normalize(PlayerPos - this.vPos) * 100f;
            this.vPos += this.vMove * delta;
            Bulletstartposition = this.vPos;

            if (this.vPos.X > graphics.PreferredBackBufferWidth + 1)
            {
                this.Remove = true;
            }

            else if (this.vPos.X < -20)
            {
                this.Remove = true;
            }

            if (this.vPos.Y > graphics.PreferredBackBufferHeight + 1)
            {
                this.Remove = true;
            }

            else if (this.vPos.Y < -20)
            {
                this.Remove = true;
            }
        }
    }

    public void Draw(SpriteBatch spriteBatch, Texture2D myTexture)
    {
        if (!Remove)
        {
            spriteBatch.Draw(myTexture, this.vPos, Color.White);
        }
    }
}

public class Bullet
{
    Vector2 vPos;
    Vector2 vMove;
    Vector2 vPlayer;
    public bool Remove;

    public Bullet(Vector2 Pos, Vector2 Move, Vector2 Player)
    {
        this.Remove = false;
        this.vPos = Pos;
        this.vMove = Move;
        this.vPlayer = Player;
    }

    public void Update(GameTime gameTime, GraphicsDeviceManager graphics, float delta)
    {
            if (!Remove)
            {
                this.vPos += this.vMove * delta;                  

                if (this.vPos.X > graphics.PreferredBackBufferWidth +1)
                {
                    this.Remove = true;
                }

                else if (this.vPos.X < -20)
                {
                    this.Remove = true;
                }

                if (this.vPos.Y > graphics.PreferredBackBufferHeight +1)
                {
                    this.Remove = true;
                }

                else if (this.vPos.Y < -20)
                {
                    this.Remove = true;
                }
            }         
    }

    public void Draw(SpriteBatch spriteBatch, Texture2D myTexture)
    {
        if (!Remove)
        {
            spriteBatch.Draw(myTexture, this.vPos, Color.White);
        }
    }
}

Werbeanzeige