PDA

View Full Version : C# Help



CiNiMoDZA
10-10-2007, 12:26 AM
A friend of mine is trying to teach me C#, we came across a problem when trying to make multiple instances of one object! For example, in Space Invaders, we could only have on bullet, as soon as we tried to shoot again, it would just move the first bullet back to the start and act as if it were shot again! How do you create an instance so that every tie you create it, it has a different name, but still acts and reacts the same as the original?

dislekcia
10-10-2007, 12:44 AM
If you're using the new keyword, you are creating a new instance of a class. Your problem is more likely an issue with losing the object you had before you created the new one: That original object isn't getting drawn or updated anymore because nothing is telling it to. In C# the garbage collector finds it eventually and kills it, because as soon as you lose that pointer to the object, you can't find it again yourself. In C++ you'd have a memory leak and eventually your game would crash.

I'm guessing that you are doing something like this:

myBullet = new Bullet(...);

myBullet.Render();
myBullet.Update();
etc...

That's not going to work because you can only ever have one handle on a bullet at a time. You need to store all your objects in a data structure of some kind, making sure that they're all rendered and updated as needed. I wrote about data structures in games two and three months ago in NAG. If you can't find those, the internet has all sorts of wisdom about linked lists, hashtables and the like. Thankfully C# gives you a ton of data structures for free, so you won't have to write your own :)

-D

Evil_Toaster
10-10-2007, 12:47 AM
Sounds odd... I would assume you're creating the bullet on startup, and that your firing code merely positions it?

What you need to do is create a new bullet object instance each time the ship fires. These can be stored in an array, or a list. Lists are better for these purposes. Delphi provides a linked list class, which is used something like this:



Procedure Fire;
// Create a new bullet and add it to the bullets list

var
oBullet : TobjBullet;

Begin
oBullet := TobjBullet.Create(X,Y);
oBulletList.Add(oBullet);
End;

Procedure CleanupBullets;
// Free all bullets off the screen, and remove them from the bullets list

Var
Cnt : Integer;
oBullet : TobjBullet;

Begin
For Cnt := 0 to oBulletList.Count-1 do Begin
oBullet := oBulletList.Items[Cnt];
oBullet.Move;
If (oBullet.OutsideScreen = True) Then Begin
oBulletList[Cnt] := nil;
oBullet.Free;
End;
End;
// Remove all nil references
oBulletList.Pack;
End;


I'm sure C# has an equivalent list class to do things like this.

Fengol
10-10-2007, 08:12 AM
yip, putting the stuff in an array or list is the answer!

@ Evil_Toaster: I suppose the "official" linked list would be an ArrayList but there are far more juicer collects to work with. One question about your code though; if you're iterating through your list of objects and you delete one in scope aren't you going to lose your cursor anyway?

CiNiMoDZA
10-10-2007, 12:03 PM
Thanks guys, makes sense, just Im still new to learning so I wasnt sure how or what to do!!!

Fengol
10-10-2007, 12:30 PM
I'm sure Dislekcia won't mind me plugging the fact that you can post on the SA Developer .NET (http://sadeveloper.net) forums any .NET questions you might have.

BlackHawk
10-10-2007, 01:31 PM
yip, putting the stuff in an array or list is the answer!

@ Evil_Toaster: I suppose the "official" linked list would be an ArrayList but there are far more juicer collects to work with. One question about your code though; if you're iterating through your list of objects and you delete one in scope aren't you going to lose your cursor anyway?

No, he won't. If he called Delete on the object list with the index of the object, he would have invalidated his count. Since he nil's the pointer to the object (equivalent to null in C#) he doesn't modify the list count. At the end he Packs the list: essentially creating a new LinkedList object, copying over the valid references and destroying the old list. Much faster.

dislekcia
10-10-2007, 01:38 PM
Nice line of questioning there. Interesting implementation that Delphi does with the nil elements and packing... I would personally iterate through the linked list manually though, using a while loop and checking for the end of the list instead of relying on a count. Of course, that could simply be because I moved over to C-variants with weaker data structures before Delphi hit.

Instinct says that you should be able to combine both those list traverses into a single pass (the update/delete and pack) but I'm never keen on arguing for efficiency ;)

-D

kurtkz
10-10-2007, 01:51 PM
Alternatively you could just iterate from the back to the front of the list and delete objects like that...assuming ur using a Vector or similar data structure...

Zen
11-10-2007, 07:39 PM
Well I just started C# the other day, and I'm a bit confused as why my controls won't respond. That is I'm experimenting with input via a keyboard to move a sprite around.

The code shall follow



public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
ContentManager content;

KeyboardState oldState;

public Game1()
{
graphics = new GraphicsDeviceManager(this);
content = new ContentManager(Services);

oldState = Keyboard.GetState();
}


protected override void Initialize()
{
base.Initialize();
}

Texture2D Ball;

Vector2 BallPos = Vector2.Zero;

SpriteBatch spBatch;

protected override void LoadGraphicsContent(bool loadAllContent)
{
if (loadAllContent)
{
Ball = content.Load<Texture2D>("Green Ball");
spBatch = new SpriteBatch(graphics.GraphicsDevice);
}


}



protected override void UnloadGraphicsContent(bool unloadAllContent)
{
if (unloadAllContent == true)
{
content.Unload();
}
}


Vector2 BallSpeed = new Vector2(50.0f, 50.0f);

protected override void Update(GameTime gameTime)
{
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();

// Custom method used to update the sprite
UpdateSprite(gameTime);

base.Update(gameTime);
}

void UpdateSprite(GameTime gameTime)
{
KeyboardState newState = Keyboard.GetState();

BallPos += BallSpeed * (float)gameTime.ElapsedGameTime.TotalSeconds;

if (newState.IsKeyDown(Keys.Down))
{
BallPos.Y -= 50.0f;
}

}


/// <summary>
/// This is called when the game should draw itself.
/// </summary>
/// <param name="gameTime">Provides a snapshot of timing values.</param>
protected override void Draw(GameTime gameTime)
{
graphics.GraphicsDevice.Clear(Color.Goldenrod);

spBatch.Begin(SpriteBlendMode.AlphaBlend);
spBatch.Draw(Ball, Vector2.Zero, Color.White);
spBatch.End();

base.Draw(gameTime);
}
}
}

Tr00jg
11-10-2007, 09:20 PM
I see the problem. The sprite's position that it is supposed to draw at gets updated, but you are drawing it at the wrong spot.

The draw code you currently have draws it at Vector2.Zero (which is (0,0)).

It should be the following:

spBatch.Draw(Ball, BallPos, Color.White);

dislekcia
11-10-2007, 11:31 PM
And put all your class variables above your methods please! I physically recoiled when I saw a floating variable declaration between two methods... ;)

Didn't see the logic error until Tr00jg pointed it out, was sitting here wondering why that wasn't working, as it looked fine.

-D

Zen
12-10-2007, 12:10 AM
And put all your class variables above your methods please! I physically recoiled when I saw a floating variable declaration between two methods... ;)


I'm physically recoiling right now just reading that. When you say method I presume you mean the procedure looking parts of code? Therefore what do you mean? Must I put it right at the top underneath this code:



public Game1
{
// insert variables here
}
....

Evil_Toaster
12-10-2007, 12:32 AM
Nooo! ;p

You've got a class there. All class variables should be declared at the top of the class before method declarations.



public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
ContentManager content;

KeyboardState oldState;
// All other class variables

// All methods

// If you put class variables here, the coder god shall strike thee down. (Or maybe dislekcia, if he finds you. Don't get found.)

// More all methods
}


And yes, method = procedure. If you're thinking in Delphi tems, then method = function too.

Chippit
12-10-2007, 11:59 AM
Nooo! ;p

You've got a class there. All class variables should be declared at the top of the class before method declarations.



public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
ContentManager content;

KeyboardState oldState;
// All other class variables

// All methods

// If you put class variables here, the coder god shall strike thee down. (Or maybe dislekcia, if he finds you. Don't get found.)

// More all methods
}


And yes, method = procedure. If you're thinking in Delphi tems, then method = function too.
http://imgs.xkcd.com/comics/goto.png
Good practice is goood

Korax
12-10-2007, 02:44 PM
In classic C you would use a linked list.
You can see it as a "chain" almost.

And like referred to earlier, rather store your head pointer and loop until you reach the list tail.
With each struct you can store a pointer to the previous link and another pointer to the next link, then you have your head (first element) with a null previous and your tail (last element) with a null next.

So, all you do really is loop until you reach a next null.
You can go get complex with this and store your heads (multiple link lists) in yet another linked list. ;)
This can typically be used when you have multiple models with their data stored in a linked list of uniquely allocated models and have another linked list which stores actual entity (object) information, like position, direction etc, then you can have a pointer for your model object stored in your entity linked list.

Dont use fixed size list methods like normal arrays, especially when you allocate memory, its not very optimal, espcially on very large, intense and varying operations in your game/engine.

Like mentioned earlier, if you are using C#, Lists (like dynamically allocated arrays) you get the same dynamic sized arrays, and add new elements by simply making use of .Add() in your code.

I didnt do testing to see how efficient it is yet.

Structured Lists is what you are looking for. :)

Zen
13-10-2007, 02:47 PM
Um was that mean't for me Korax? Cause if it was, you just confused the hell out of me.

dislekcia
13-10-2007, 07:55 PM
Um was that mean't for me Korax? Cause if it was, you just confused the hell out of me.

No, I think it was meant for Cinimod. His problem can be solved by using data structures like linked lists to store objects in, instead of simply having a single "slot" for an object of a specific type ;)

-D

Korax
15-10-2007, 12:59 PM
Yes, I was responding to CiNiMoDZA.
Sorry about that XennoX.

If you use C#, you could use Lists to store data, I didnt do testing yet to see how optimal its use is, but you can get this kind of thing fairly quickly functional, before you go into linked lists, which might mean you need to code in unsafe mode. (unless C# contains a class for this)

If you are interested in some source code, send me a message to korax at sagamedev dot com and I'll reply with a CS class i worked on some time ago loading the 3DS model format, it shows how to make use of Lists without a fixed size, using structures to save data.

In short, heres how Ive done it showing here 3 core pieces of code you can build on:

public struct material
{
public String Name;
public materialcolor ColorAmbient;
public materialcolor ColorDiffuse;
public materialcolor ColorSpecular;
public String File;
public Single ScaleU;
public Single ScaleV;
public Single OffsetU;
public Single OffsetV;
public Single Rotate;
}

private Model3DS.material _currentMaterial;

...
add some information to "_currentMaterial".
...

public List<material> _Materials = new List<material>();
_Materials.Add(_currentMaterial);

dislekcia
15-10-2007, 01:54 PM
Korax, I don't think that's going to help much ;)

Remember that Cinimod is still coming to grips with the idea of dynamic storage of objects instead of single variables. Lists are new to him, header code isn't exactly going to illuminate things all of a sardine...

-D

DrDeth
16-10-2007, 11:05 PM
Oh boy... seems I need to get my C# column in Dev.Mag going sooner than I thought! :)