Welcome, Guest. Please login or register.

Login with username, password and session length

 
Advanced search

1411574 Posts in 69386 Topics- by 58444 Members - Latest Member: darkcitien

May 04, 2024, 04:49:39 PM

Need hosting? Check out Digital Ocean
(more details in this thread)
TIGSource ForumsDeveloperTechnical (Moderator: ThemsAllTook)C# + SDL.NET: Creating instances (In a way.. ?)
Pages: 1 [2]
Print
Author Topic: C# + SDL.NET: Creating instances (In a way.. ?)  (Read 7377 times)
Gold Cray
Level 10
*****


Gold Cray


View Profile WWW
« Reply #20 on: May 08, 2009, 08:20:02 PM »

The other thing to keep in mind with XNA is that it doesn't even work consistently on Windows machines, so you're not just limiting yourself to Windows; you're limiting yourself to Windows machines that are capable of running XNA games.
Logged
Skirvir
Level 0
**

As below so above.


View Profile WWW
« Reply #21 on: May 08, 2009, 09:22:28 PM »

Really? I have not heard of or encountered that myself, you sure it's not an issue of targeting the right .NET framework, VS 2005 targets .NET 2.0 and VS 2008 targets .NET 3.5 and VS 2010 is right around the corner (and thankfully will take care of these versioning issues).

Microsoft is pretty good about supporting their major products and since XNA is the conduit to the Xbox, I'd be suprised if things just don't work.
Logged

muku
Level 10
*****


View Profile
« Reply #22 on: May 09, 2009, 03:44:39 AM »

For one, XNA doesn't work on Win2k, which excludes my old gaming machine (which can run HL2 just fine). Besides, it requires some shader model support, which not everyone is going to have. If you're making a low-spec 2D game, using XNA definitely excludes a non-trivial part of your potential audience.

Just look what happened to that Dead or Alive demake we had in the Bootleg Demakes compo (what was it called, Sexy Seaside Beachball I think?), there was much griefing from people who wanted to play it, but couldn't.
Logged
Skirvir
Level 0
**

As below so above.


View Profile WWW
« Reply #23 on: May 09, 2009, 06:36:16 AM »

Oh well yeah, new technology also requires new technology, I think XNA works with Windows XP+, and again as long as your running .NET 2.0+ and yes shaders are in heavy use, like I said, I think XNA is very cool technology but quite overboard for any 2D applications, your far better off with SDL or Silverlight or Flash in that case. It's all about knowing the requirements and limits of your chosen technology before embarking on actually using it.
Logged

Noel Berry
Level 4
****


Yarr!


View Profile WWW
« Reply #24 on: May 09, 2009, 01:27:41 PM »

EDIT: Nevermind, I fixed this. I now have tilesets and floors working. You can move, jump, and place floors Smiley

Original Post

I got a chance to mess around with C# and SDL.NET today, and I'm making some progress Smiley I currently have a little guy who can move left/right, has gravity, and can jump. (Currently the only 'floor' is the bottom of the screen).

However, I'm having a lot of trouble with making a tileset-like thing. I was hoping I'd be able to simply make an array, and depending on what the array equals, it would open a tile file, split the tile into a 32x32 piece that I need, and display it.

For example:
int[,] map;

map[0,0] = 1;
map[0,1] = 32;

for(int x=0;x< Video.Screen.Width / 32;x++)
{
   for(int y=0;y< Video.Screen.Height / 32; y++)
   {
      //Open tileset.png, cut out the right part, display it
   }
}

Of course, I have no idea how to do the hardest part Tongue

My main problem, more then displaying that image is how to slice a larger image into several smaller images...

Displaying the images shouldn't be too hard, although the only way I currently know is to do:

Sprite ball = new Sprite(new Surface("ball.png"));
ball.X = 3;
ball.Y = 42;


Would anyone know how to do that?

Here's my current script (Block.cs):

Code:
using System;
using System.IO;
using System.Drawing;

using SdlDotNet;
using SdlDotNet.Graphics;
using SdlDotNet.Graphics.Sprites;
using SdlDotNet.Core;
using SdlDotNet.Input;

namespace BlockGame
{

    public class Block
    {
        //Create the ball sprite
        Sprite ball = new Sprite(new Surface("ball.png"));
        //Set its current movement speed
        int ballSpeedX = 0;
        int ballSpeedY = 0;
        int ballJumpHeight = 12;

        public Block()
        {

            //Set up the main stuff
            Video.SetVideoMode(300, 200);
            Video.WindowCaption = "Jump Away!";
            Events.Tick += new EventHandler<TickEventArgs>(Events_Tick);
            Events.KeyboardDown += new EventHandler<KeyboardEventArgs>(this.KeyboardDown);
            Events.KeyboardUp += new EventHandler<KeyboardEventArgs>(this.KeyboardUp);
        }

        public void Go()
        {
            Events.Run();
        }

        [STAThread]
        public static void Main()
        {
            Block Block = new Block();
            Block.Go();
        }
        private void Events_Tick(object sender, TickEventArgs e)
        {
            ball.X += ballSpeedX;

            //Check each each pixel below to make sure you don't fall through the floor...
            if(ballSpeedY > 0) {
                int num = ballSpeedY;
                while (num > 0)
                {
                    num -= 1;
                    if (ball.Y + 1 > Video.Screen.Height - ball.Size.Height)
                    {
                        ballSpeedY = 0;
                        break;
                    }
                    else
                    {
                        ball.Y += 1;
                    }
                }
            } else {
                ball.Y += ballSpeedY;
            }
            if (ball.Y < Video.Screen.Height - ball.Size.Height)
            {
                ballSpeedY += 1;
            }
            if (ball.Y > Video.Screen.Height - ball.Size.Height)
            {
                ballSpeedY = 0;
                ball.Y = Video.Screen.Height - ball.Size.Height;
            }

            Video.Screen.Fill(Color.Black);
            // Draw the ball
            Video.Screen.Blit(ball);

            // Update the screen
            Video.Screen.Update();

        }
        private void Events_Quit(object sender, QuitEventArgs e)
        {
            Events.QuitApplication();
        }
        private void KeyboardDown(object sender, KeyboardEventArgs e)
        {
            if (e.Key == Key.Escape)
            {
                 Events.QuitApplication();
            }
            if (e.Key == Key.RightArrow)
            {
               ballSpeedX = 2;
            }
            if (e.Key == Key.LeftArrow)
            {
                ballSpeedX = -2;
            }
            if (e.Key == Key.UpArrow)
            {
                if (ball.Y == Video.Screen.Height - ball.Size.Height)
                {
                    ballSpeedY = -ballJumpHeight;
                }
            }
        }
        private void KeyboardUp(object sender, KeyboardEventArgs e)
        {
            if (e.Key == Key.RightArrow)
            {
                ballSpeedX = 0;
            }
            if (e.Key == Key.LeftArrow)
            {
                ballSpeedX = 0;
            }
            if (ballSpeedY < 0) { ballSpeedY = 0; }
        }
    }
}


Cheers.
« Last Edit: May 09, 2009, 04:17:52 PM by Drazzke » Logged

Skirvir
Level 0
**

As below so above.


View Profile WWW
« Reply #25 on: May 09, 2009, 04:59:00 PM »

Just a quick tip, unless you've already worked around this as well:

Code:
for(int x=0;x< Video.Screen.Width / 32;x++)
{
   for(int y=0;y< Video.Screen.Height / 32; y++)
   {
      //Open tileset.png, cut out the right part, display it
   }
}

I would suggest doing it like this:

Code:
// Open tileset.png, cut out the right parts and store them in an array, etc.

for(int x=0;x< Video.Screen.Width / 32;x++)
{
   for(int y=0;y< Video.Screen.Height / 32; y++)
   {
      // Render appropriate sprite
   }
}

This would just optimize your rendering, in your rendering routines you want to pretty much focus ONLY on rendering stuff, that way you are getting the maximum speed possible. Glad you were able to figure out your other issues, didn't even take long, I like that about SDL Smiley
Logged

Noel Berry
Level 4
****


Yarr!


View Profile WWW
« Reply #26 on: May 09, 2009, 07:18:24 PM »

Thanks, yes, I am basically doing that now.

Here's my code as it is now... The variable SolidPos is an array that holds all of the Solid pixels. I wasn't sure how else to do collisions...

There's a small bug where you can still sometimes walk 1 pixel left/right into the wall.

It's pretty simple, and I'm sure it's not the best way to do it, but, I'm pretty happy with what I've got... Tongue
Code:
using System;
using System.IO;
using System.Drawing;

using SdlDotNet;
using SdlDotNet.Graphics;
using SdlDotNet.Graphics.Sprites;
using SdlDotNet.Core;
using SdlDotNet.Input;
using Tao.Sdl;

namespace BlockGame
{

    public class Block
    {
        //Create the ball sprite
        Sprite ball = new Sprite(new Surface("data/ball.png"));
        //Set its current movement speed
        int ballSpeedX = 0;
        int ballSpeedY = 0;
        int ballJumpHeight = 12;
        public static int[,] map = new int[10000,10000];
        public static bool[,] SolidPos = new bool[10000, 10000];

            //Tileset
            public static Surface tileset = new Surface("data/tileset.png");
            public static SurfaceCollection tile_main = new SurfaceCollection();


        public Block()
        {
            //Set up the main stuff
            int roomWidth = 10;
            int roomHeight = 6;
            Video.SetVideoMode(roomWidth*32, roomHeight*32);
            Video.WindowCaption = "Jump Away!";
            Events.Tick += new EventHandler<TickEventArgs>(Events_Tick);
            Events.KeyboardDown += new EventHandler<KeyboardEventArgs>(this.KeyboardDown);
            Events.KeyboardUp += new EventHandler<KeyboardEventArgs>(this.KeyboardUp);


        }

        public void Go()
        {
            Events.Run();
        }

        [STAThread]
        public static void Main()
        {
            Block Block = new Block();
            Block.Go();
        }
        //Draw everything + update player position
        private void Events_Tick(object sender, TickEventArgs e)
        {
            //PLAYER STUFF...............................................................................
            ball.X += ballSpeedX;
            if(ball.X < 0) { ball.X = 0; }
            if (ball.Y < 2) { ball.Y = 2; }
            //Check the LEFT/RIGHT movement

            int XX = Math.Abs(ballSpeedX);
            while (XX > 0)
            {
                XX -= 1;
                bool hit = false;
                //Add sprite height if moving right...
                int addWidth = 0;
                if (ballSpeedX > 0) { addWidth = ball.Size.Width; }

                for (int y = 0; y < ball.Size.Height+1; y++)
                {
                    if (SolidPos[Convert.ToInt32(ball.X + sign(ballSpeedX) + addWidth), Convert.ToInt32(ball.Y+y)] == true)
                    {
                        ballSpeedX = 0;
                        hit = true;
                        break;
                    }

                }
                if (hit == false)
                {
                    ball.X += sign(ballSpeedX);
                    if (ball.X < 0) { ball.X = 0; }
                }
            }

            //Check each each pixel below to make sure you don't fall through the floor...
            int YY =  Math.Abs(ballSpeedY);
            while (YY > 0)
            {
                YY -= 1;
                bool hit = false;
                //Add sprite height if moving down...
                int addHeight = 0;
                if(ballSpeedY > 0) { addHeight = ball.Size.Height;}

                for (int x = 0; x < ball.Size.Width+1; x++)
                {
                    if (SolidPos[Convert.ToInt32(ball.X + x), Convert.ToInt32(ball.Y + sign(ballSpeedY) + addHeight)] == true)
                    {
                        ballSpeedY = 0;
                        hit = true;
                        break;
                    }
                               
                }
                if(hit == false) {
                    ball.Y += sign(ballSpeedY);
                    if (ball.Y < 2) { ball.Y = 2; }
                }
             }
           
            //Gravity
            if (ball.Y < Video.Screen.Height - ball.Size.Height)
            {
                ballSpeedY += 1;
            }
            //Don't fall out of the room!
            if (ball.Y > Video.Screen.Height - ball.Size.Height)
            {
                ballSpeedY = 0;
                ball.Y = Video.Screen.Height - ball.Size.Height;
            }
            //Fill background
            Video.Screen.Fill(Color.Black);

            //TILESET STUFF.......................................................................................
            tile_main.Add(tileset, new Size(32, 32), 0);
            map[0, 0] = 0;
            map[1, 0] = 0;
            map[6, 5] = 1;
            map[5, 5] = 1;
            map[5, 4] = 1;
            map[4, 5] = 1;
            map[6, 4] = 1;
            map[6, 3] = 1;
            map[0, 5] = 1;
            map[0, 3] = 1;
            for (int x = 0; x < Video.Screen.Width / 32; x++)
            {
                for (int y = 0; y < Video.Screen.Height / 32; y++)
                {
                    Video.Screen.Blit(tile_main[map[x, y]], new Point(x * 32, y * 32));
                    SolidPos[x, y] = false;
                    if (map[x, y] == 1)
                    {
                        for (int i = 0; i < 32; i++)
                        {
                            for (int j = 0; j < 32; j++)
                            {
                                SolidPos[x * 32 + i, y * 32+1 + j] = true;
                            }
                        }
                    }
                }
            }
            // Draw the ball
            Video.Screen.Blit(ball);
            // Update the screen
            Video.Screen.Update();

        }
        //Quit game
        private void Events_Quit(object sender, QuitEventArgs e)
        {
            Events.QuitApplication();
        }
        //Down Pressed
        private void KeyboardDown(object sender, KeyboardEventArgs e)
        {
            //Escape
            if (e.Key == Key.Escape)
            {
                 Events.QuitApplication();
            }
            //Right
            if (e.Key == Key.RightArrow)
            {
               ballSpeedX = 2;
            }
            //Left
            if (e.Key == Key.LeftArrow)
            {
                ballSpeedX = -2;
            }
            //Up (jump)
            if (e.Key == Key.UpArrow)
            {
                if (ball.Y == Video.Screen.Height - ball.Size.Height )
                {
                    ballSpeedY = -ballJumpHeight;
                }
                for (int x = 0; x < 32; x++)
                {
                    if (SolidPos[Convert.ToInt32(ball.X + x), Convert.ToInt32(ball.Y + ball.Size.Height + 1)] == true)
                    {
                        ballSpeedY = 0;
                        ballSpeedY = -ballJumpHeight;
                        break;
                    }


                }
            }
        }
        //Release Key
        private void KeyboardUp(object sender, KeyboardEventArgs e)
        {
            //Stop moving right
            if (e.Key == Key.RightArrow)
            {
                ballSpeedX = 0;
            }
            //Stop moving left
            if (e.Key == Key.LeftArrow)
            {
                ballSpeedX = 0;
            }
            //Simple variable jumping
            if (ballSpeedY < 0) { ballSpeedY = 0; }
        }

        //Rounds down
        public static double RoundDown(double valueToRound)
        {
            double floorValue = Math.Floor(valueToRound);
            if ((valueToRound - floorValue) > .5)
            {
                return (floorValue + 1);
            }
            else
            {
                return (floorValue);
            }
        }
        //Returns the sign
        public static int sign(int val)
        {
            if (val < 0) { return -1; }
            if (val > 0) { return 1; }
            if (val == 0) { return 0; }
            return 0;
        }
    }
}

The only problem with this is that when the room is about 20x16 tiles large, it has to go through quite a few loops...

For the player collisions, it's about 200 for X and Y, and then another 320 for all the tiles (when the room is 20x16), which is a total of 720 loops... It starts to run a bit slow, But I don't know how to decrease the loops...

Edit:
Actually, after testing some things, it's not actually running slowly from the loop statements... It might just be my computer, but I don't really know.

EDIT: It seems to be that the slowness is caused from the window just being too large... I'm wondering if I could still make a larger 'room', but have only a certain size of view in the room while maintaining reasonably high Frame rate?
« Last Edit: May 11, 2009, 04:49:56 AM by Drazzke » Logged

Guillaume
Level 7
**



View Profile
« Reply #27 on: May 10, 2009, 03:32:32 PM »

Just a quick tip, unless you've already worked around this as well:

Code:
for(int x=0;x< Video.Screen.Width / 32;x++)
{
   for(int y=0;y< Video.Screen.Height / 32; y++)
   {
      //Open tileset.png, cut out the right part, display it
   }
}

I would suggest doing it like this:

Code:
// Open tileset.png, cut out the right parts and store them in an array, etc.

for(int x=0;x< Video.Screen.Width / 32;x++)
{
   for(int y=0;y< Video.Screen.Height / 32; y++)
   {
      // Render appropriate sprite
   }
}

This would just optimize your rendering, in your rendering routines you want to pretty much focus ONLY on rendering stuff, that way you are getting the maximum speed possible. Glad you were able to figure out your other issues, didn't even take long, I like that about SDL Smiley

Implementing a sprite batch manager + renderer the same way XNA does would be a good idea Smiley
Logged
Noel Berry
Level 4
****


Yarr!


View Profile WWW
« Reply #28 on: May 11, 2009, 05:20:40 PM »

For those of you who know stuff about SDL.NET, I have a question Smiley

Basically, I have Menu.CS, Game.CS, and Main.CS. Main.CS just loads up Menu.CS like so:
Code:

        public static void Main()
        {
            Menu Menu = new Menu();
            Menu.Go();

        }

Now, menu contains, well, a menu WITH a ticker event. Now, when you hit enter and the menu has selected "Start", then it SHOULD end the Menu.CS and start the Game.CS

This is what I am currently doing:
Code:
                if (select == 0)
                {
                    Game Game = new Game();
                    Game.Go();
                    Events.QuitApplication();

                }

What that actually does it open the Game.CS, and then it seems to quickly flash between the menu and the game... (like, flicker between the two). I was hoping by adding the quit application it would simply quit it, but this does not seem to be the case...

I would appreciate any kind of help.

Cheers!
Logged

Guillaume
Level 7
**



View Profile
« Reply #29 on: May 12, 2009, 12:51:40 AM »

In any cases, Events.QuitApplication(); will be called only after Game.Go(); exits.

What I usually do in my engines is something more like:


Main.cs:

        public static void Main()
        {
            Menu Menu = new Menu();
            Menu.Go();

            Game Game = new Game();
            Game.Go();

        }


With, in Menu.cs:

                if (select == 0)
                {
                    Events.QuitApplication();
                }

That way, your menu manages all that is menu related (credits, options, high scores, etc.) but the management of the game object is made by the main loop (which makes more sense to me).
Logged
Alex May
...is probably drunk right now.
Level 10
*


hen hao wan


View Profile WWW
« Reply #30 on: May 12, 2009, 12:55:35 AM »

What are Game and Menu derived from?

I would suggest having only one object like your Menu, and having your menu and game handled inside that.

e.g.
Code:
class MyProgram : WhateverSDLBaseClass
{
  Menu menu = new Menu();
  Game game = new Game();

  bool isInMenu = true;

  public override void Go()
  {
    Events.OnTick += this.OnTick; // or whatever SDL thing it is I can't remember
  }

  public void OnTick(OnTickEventArgs etc)
  {
      Update();
      Draw();
  }

  public void Update()
  {
    if (isInMenu) menu.Update();
    else game.Update();
  }

  public void Draw()
  {
    if (isInMenu) menu.Draw();
    else game.Draw();
  }
}

This way, you can go back to your menu later by switching isInMenu back to true somehow (possibly by some return value from Menu.Update()).
Logged

Noel Berry
Level 4
****


Yarr!


View Profile WWW
« Reply #31 on: May 12, 2009, 01:32:05 PM »

OK, thanks guys. I think I'll go with what Alex May said, as that way it also fixes another small bug I was having.

Thank again! I really appreciate it Smiley

EDIT:
OK.. next question... Tongue

I'm basically trying to get a small SHMUP like game working (where you fly around and shoot other stuff that comes at you). My problem is creating the bullets... I have everything working completely functional, but I only know how to create one bullet at a time.

I have a PlayerBullet.cs file that has two things in it
public static void PositionSelf() {
 // Position self relative to player
}
public static void Update() {
  //Move up + draw self using SDL
}

Now, as Alex advised, I'm doing a method similar to what he says. But, my problem is I have no idea how to make it so that Main will run EACH of the PlayerBullet.cs's Update() script (or whatever). Right now, I just use
PlayerBullet.Update(); in the Main ticker event/script. But, this ONLY seems to update the most recent one (or maybe when I try creating a new one by doing
PlayerBullet n = new PlayerBullet();
n.PositionSelf();
it resets just one of them, and doesn't even create more than one?)

To fix this, I had tried to use an array:
n[totalbullets] = new PlayerBullet();
n.PositionSelf();

But this just lead to more problems... Epileptic

Any help would, as always, be appreciated  Smiley

« Last Edit: May 12, 2009, 05:27:35 PM by Drazzke » Logged

Alex May
...is probably drunk right now.
Level 10
*


hen hao wan


View Profile WWW
« Reply #32 on: May 13, 2009, 01:27:48 AM »

So, a couple of fundamental concepts here.

When you do
Code:
// in the class member list
PlayerBullet n = new PlayerBullet();
You create a new instance of PlayerBullet, and store a reference to it in the variable n. You can then update and draw that bullet or whatever you want by calling the appropriate methods via that reference e.g.
Code:
// e.g. in Player.Update()
n.PositionSelf();
However, when you want to make a second bullet, and you again call
Code:
// e.g. in Player.Shoot()
n = new PlayerBullet();
what you are actually doing is creating a new instance of PlayerBullet() - which is fine, you now have two - but you are replacing the reference to the first bullet with a reference to the second bullet. Your reference to the first bullet is lost now, since you didn't store it elsewhere. Since nothing else knows about that reference any more, it will be collected by the garbage collector soon and your bullet will be destroyed.

What you need to do is keep a record of all the bullets you create.

Essentially you are heading in the right direction - you need a collection of references to instances of your PlayerBullet class. How exactly you go about it is up to you, but here are a couple of suggestions.

1) The Array
This is very simple, but quite inflexible. It is the kind of code you might do if working in C or on a system where resources are tight and you know exactly how much memory you can spare for the job.

You declare an array of bullets
Code:
// in the class definition
const int maxPlayerBullets = 100;
PlayerBullet[] bullets = new PlayerBullet[maxPlayerBullets];

This just makes empty references to 100 bullets. You need to actually make the bullets, so in your constructor you might do this:
Code:
// e.g. in Player.Player()
for (int i = 0; i < maxPlayerBullets; i++) bullets[i] = new PlayerBullet();

Now when you update, you can reference all of your 100 bullets at once:
Code:
// e.g. in Player.Update()
for (int i = 0; i < maxPlayerBullets; i++) bullets[i].PositionSelf();

This is okay, but all the bullets will always update. You might want to make each bullet aware of whether it is in play or not:
Code:
// e.g. in Player.Update()
for (int i = 0; i < maxPlayerBullets; i++)
{
  if (bullets[i].InPlay) bullets[i].PositionSelf();
}

Then when shooting the player could examine the list of bullets and pull one of the inactive ones into play:
Code:
// e.g. in Player.Shoot()
for (int i = 0; i < maxPlayerBullets; i++)
{
  if (!bullets[i].InPlay)
  {
    bullets[i].Activate();
    MakeShootingSound();
    return;
  }
}

No memory allocation will then have to go on while you're playing, which traditionally is a good thing although it is totally irrelevant for a small shmup on modern PCs.

2) Use a List

A List is a standard collection that can grow in size.

Here's how you might define your list of bullets:
Code:
List<PlayerBullet> bullets = new List<PlayerBullet>();

Now you can add bullets to it at any time by doing:
Code:
// e.g. in Player.Shoot()
bullets.Add(new PlayerBullet());

And iterate over it by going:
Code:
foreach (PlayerBullet bullet in bullets)
{
  bullet.DoSomething();
}

But what happens when a bullet goes out of play?
Code:
foreach (PlayerBullet bullet in bullets)
{
  if (!bullet.InPlay) bullets.Remove(bullet);
}

This will actually throw an exception at run time, because you're not allowed to modify a collection while you are iterating over it. There are lots of ways around this - one way would be to modify your shooting code:
Code:
// find an inactive bullet
foreach (PlayerBullet bullet in bullets)
{
  if (!bullet.InPlay)
  {
    bullet.Activate();
    return;
  }
}
// couldn't find a bullet
bullets.Add(new PlayerBullet()); // so add a new one

or you could prune out inactive bullets at the end of each update:
Code:
List<PlayerBullet> inactiveBullets = new List<PlayerBullet>();
foreach (PlayerBullet bullet in bullets)
{
  if (!bullet.InPlay) inactiveBullets.Add(bullet);
}
foreach (PlayerBullet bullet in inactiveBullets)
{
  bullets.Remove(bullet);
}

Or, you could hold two lists of bullets, one for active ones and one for inactive ones, and just move inactive ones over to the active list when the player shoots, and move them back when they go out of play. At the start of play, you fill the inactive list with your maxPlayerBullets, and use that as a pool of ammunition for the player to fire. This latter solution also avoids the runtime memory allocation, but again, that shouldn't bother you so much at this point, if ever.
Logged

Noel Berry
Level 4
****


Yarr!


View Profile WWW
« Reply #33 on: May 13, 2009, 09:11:27 AM »

Ah, I see. That should work very well. I think I will try using the latter option, rather then the array as I had an array system set up basically the same as you, but it was giving me problems due to some things...

I won't be able to try this out until at least Friday, but I'll give it a go as soon as I can.

Thanks for the support Smiley
Logged

Alex May
...is probably drunk right now.
Level 10
*


hen hao wan


View Profile WWW
« Reply #34 on: May 14, 2009, 12:51:04 AM »

One other benefit of the latter-most solution, holding two lists, is that iterating over the currently-active list is quicker than iterating over the list of all possible bullets and testing to see whether each one is active or not, unless all of your bullets are in play of course.

I wrote a class or two to handle this, which I'll list below, although I encourage you to experiment a bit with these data structures and programming principles before simply going ahead and using some code that already exists so that you understand what's happening. It might be too much to take in, so just go at your own pace.

The following class is an extension of the standard List which can mark entries to be removed later. When you want to clear them out, you call ProcessDeferred() and the entries are removed.
Code:
    public class DeferredList<T> : List<T>
    {
        List<T> mDeferredAdds;
        List<T> mDeferredRemoves;

        public DeferredList()
            : base()
        {
            mDeferredAdds = new List<T>();
            mDeferredRemoves = new List<T>();
        }

        public DeferredList(int reserve)
            : base(reserve)
        {
            mDeferredAdds = new List<T>(reserve);
            mDeferredRemoves = new List<T>(reserve);
        }

        public DeferredList(DeferredList<T> deferredList)
            : base(deferredList)
        {
            mDeferredAdds = new List<T>(deferredList.mDeferredAdds);
            mDeferredRemoves = new List<T>(deferredList.mDeferredRemoves);
        }

        public void AddDeferred(T obj)
        {
            mDeferredAdds.Add(obj);
        }
        public void RemoveDeferred(T obj)
        {
            mDeferredRemoves.Add(obj);
        }

        public void ProcessDeferred()
        {
            foreach (T obj in mDeferredRemoves)
            {
                Remove(obj);
            }
            mDeferredRemoves.Clear();

            foreach (T obj in mDeferredAdds)
            {
                Add(obj);
            }
            mDeferredAdds.Clear();
        }
    }

The following class holds a set of entities which are created at instantiation time, and can deliver an inactive entity on demand, moving it to the active list when it is requested. IGameEntity is an interface which declares an update method and boolean active query. The new() in the definition there informs the class that the Entity template can be instantiated with the new keyword.
Code:
    class Pool<Entity> where Entity : class, IGameEntity, new()
    {

        public Pool(int size)
        {
            // Create a fixed pool of whatever type of entity was requested.
            for (int i = 0; i < size; i++)
            {
                mInactives.Add(new Entity());
            }
        }

        DeferredList<Entity> mActives = new DeferredList<Entity>();
        DeferredList<Entity> mInactives = new DeferredList<Entity>();

        public Entity Get(Attributes a)
        {
            // Cannot give an entity when none are left, as the pool is fixed-size.
            // Alternatively, increase the size of the pool dynamically.
            if (mInactives.Count == 0) return null;

            // Return the first entity in the list of inactive entities.
            Entity entity = mInactives[0];
            // Move it to the appropriate list.
            mActives.Add(entity);
            mInactives.Remove(entity);

            // Activate the entity.
            entity.Activate(a);

            return entity;
        }

        public int NumActives { get { return mActives.Count; } }

        public void Update(float time)
        {
            for (int i = 0; i < mActives.Count; i++)
            {
                mActives[i].Update(time);
                // If the entity is no longer active, move it to the inactive list.
                if (!mActives[i].Active)
                {
                    mActives.RemoveDeferred(mActives[i]);
                    mInactives.Add(mActives[i]);
                }
            }
            mActives.ProcessDeferred();
        }
    }
Logged

Noel Berry
Level 4
****


Yarr!


View Profile WWW
« Reply #35 on: May 14, 2009, 09:55:46 AM »

Yeah, that's a pretty good idea, and I'll definitely experiment with that.

However, for such a small game, where there will most likely never be more then around 50 bullets, at the very most, I don't see a need to get into the complication of having two lists, but rather a bool variable that's true or false on activity.

If I get to the point where I may need something like hundreds of enemies and bullets and the like, then I'll probably use a two-list method.

I will, however (like I said above), look into the two list method as it could come in handy the next time I have hundreds of 'objects' at a time. I see the advantage of doing so.

Speaking of which, as I will need to know this very soon, what's the best way to do collisions in C#? I could just say that when the bullet is within a certain distance of an enemy using it's sprite size and the bullets sprite size aswell, it starts a collision event.

In my platform game I actually made an array for every pixel on the screen. Each pixel would be either solid or not solid. The player couldn't walk/fall/jump through an pixel that was marked as solid... This worked, but there must be better ways of doing this.
(I never finished the game, but it was a good learning experience getting into C#)

Thanks.
Logged

Noel Berry
Level 4
****


Yarr!


View Profile WWW
« Reply #36 on: May 15, 2009, 03:57:11 PM »

Well, I've run into a bit of a problem. Your code worked perfectly, and it kept working until I needed to define it as a public static variable, in which case it blew up on me.

Basically, in the Game.CS file I have this:

Code:
using System;
using System.IO;
using System.Drawing;
using System.Text;

using SdlDotNet;
using SdlDotNet.Graphics;
using SdlDotNet.Graphics.Sprites;
using SdlDotNet.Core;
using SdlDotNet.Input;
using System.Collections.Generic; 

namespace LightFall
{
    public class Game
    {
        public static Sprite Player = new Sprite(new Surface("data/Player.png"));
        public static Sprite BG1_1 = new Sprite(new Surface("data/background.png"));
        public static Sprite BG1_2 = new Sprite(new Surface("data/background.png"));
        public static List<PBullet> PBullets = new List<PBullet>();

        static int PlayerSpeedX = 0;
        static int PlayerSpeedY = 0;
        static int PlayerSpeedMax = 8;
        static bool UpKeyHeld = false;
        static bool RightKeyHeld = false;
        static bool LeftKeyHeld = false;
        static bool DownKeyHeld = false;
        static int PlayerSpeedInc = 2;

        public static void InitGame()
        {
            Player.X = Video.Screen.Width / 2 - Player.Size.Width / 2;
            Player.Y = Video.Screen.Height - Video.Screen.Height / 3 + Player.Size.Height / 2;
            BG1_1.Y = 0;
            BG1_2.Y = -300;

        }


        //Draw the game
        public static void Update()
        {
            //Update the player
            PlayerUpdate();

            //Update the background
            BG1_1.Y += 3;
            BG1_2.Y += 3;

            if (BG1_1.Y > 300) { BG1_1.Y = -300; }
            if (BG1_2.Y > 300) { BG1_2.Y = -300; }

            Video.Screen.Blit(BG1_1);
            Video.Screen.Blit(BG1_2);
            //Draw the bullets... We don't have invisible bullets (That would be SOOOO cheap)
            foreach (PBullet bullet in PBullets)
            {
                if (bullet.InPlay == true)
                {
                    bullet.Update();
                }
            }

            Video.Screen.Blit(Player);
            // Update the screen
            Video.Screen.Update();
        }
        //Key Pressed...
        public static void KeyDown(KeyboardEventArgs e)
        {
            if (e.Key == Key.Escape)
            {
                Events.QuitApplication();
            }
            if (e.Key == Key.UpArrow)
            {
                UpKeyHeld = true;
            }
            if (e.Key == Key.RightArrow)
            {
                RightKeyHeld = true;
            }
            if (e.Key == Key.LeftArrow)
            {
                LeftKeyHeld = true;
            }
            if (e.Key == Key.DownArrow)
            {
                DownKeyHeld = true;
            }
            if (e.Key == Key.Z)
            {
                PBullets.Add(new PBullet(10, 300));
            }


        }
        //Key Pressed...
        public static void KeyUp(KeyboardEventArgs e)
        {
            if (e.Key == Key.UpArrow)
            {
                UpKeyHeld = false;
            }
            if (e.Key == Key.RightArrow)
            {
                RightKeyHeld = false;
            }
            if (e.Key == Key.LeftArrow)
            {
                LeftKeyHeld = false;
            }
            if (e.Key == Key.DownArrow)
            {
                DownKeyHeld = false;
            }
        }
        public static void PlayerUpdate()
        {
            //Update the players position...
            Player.X += PlayerSpeedX;
            Player.Y += PlayerSpeedY;

            //Update the Players speed...
            //Increase
            if (UpKeyHeld == true && PlayerSpeedY > -PlayerSpeedMax) { PlayerSpeedY -= PlayerSpeedInc; }
            if (RightKeyHeld == true && PlayerSpeedX < PlayerSpeedMax) { PlayerSpeedX += PlayerSpeedInc; }
            if (LeftKeyHeld == true && PlayerSpeedX > -PlayerSpeedMax) { PlayerSpeedX -= PlayerSpeedInc; }
            if (DownKeyHeld == true && PlayerSpeedY < PlayerSpeedMax) { PlayerSpeedY += PlayerSpeedInc; }
            //Decrease (When key dropped)
            if (UpKeyHeld == false && DownKeyHeld == false && PlayerSpeedY != 0)
            {
                PlayerSpeedY += Math.Sign(PlayerSpeedY) * (-PlayerSpeedInc);
            }
            if (RightKeyHeld == false && LeftKeyHeld == false && PlayerSpeedX != 0)
            {
                PlayerSpeedX += Math.Sign(PlayerSpeedX) * (-PlayerSpeedInc);
            }

            //Don't allow the player outa the room...
            if (Player.X < 0) { Player.X = 0; if (PlayerSpeedX < 0) { PlayerSpeedX = -PlayerSpeedX; } }
            if (Player.X > Video.Screen.Width - Player.Size.Width)
            {
                Player.X = Video.Screen.Width - Player.Size.Width;
                if (PlayerSpeedX > 0) { PlayerSpeedX = -PlayerSpeedX; }
            }
            if (Player.Y < 0) { Player.Y = 0; if (PlayerSpeedY < 0) { PlayerSpeedY = -PlayerSpeedY; } }
            if (Player.Y > Video.Screen.Height - Player.Size.Height)
            {
                Player.Y = Video.Screen.Height - Player.Size.Height;
                if (PlayerSpeedY > 0) { PlayerSpeedY = -PlayerSpeedY; }
            }
        }
    }
}

(The only part that matters really is where it defines the variable...)

And then the Bullet code is like so:
Code:
using System;
using System.IO;
using System.Drawing;
using System.Text;

using SdlDotNet;
using SdlDotNet.Graphics;
using SdlDotNet.Graphics.Sprites;
using SdlDotNet.Core;
using SdlDotNet.Input;
using System.Collections.Generic; 

namespace LightFall
{
    class PBullet
    {
        //Create a new SPRITE! (I can see you... ... ..)
        Sprite Self = new Sprite("data/player_Bullet.png");
        int SpeedY = 10;
        public bool InPlay = true;
        public PBullet(int x, int y) {
            Self.X = x;
            Self.Y = y;
        }


        public void Update()
        {
            Self.Y -= SpeedY;
            if (Self.Y < 0)
            {
                InPlay = false;
            }
            Video.Screen.Blit(Self);
        }
    }
}

Now, here's the error I get when I define PBullet in Game.cs:

Error   1   Inconsistent accessibility: field type 'System.Collections.Generic.List<LightFall.PBullet>' is less accessible than field 'LightFall.Game.PBullets'


I've tried changing it around, making the variable just public, just static, etc, but neither work as I need it to be public static since the Program.cs (The main thing) calls to it constantly (the different game.cs events)..

In case this helps, here's the the Program.cs:
Code:
using System;
using System.IO;
using System.Drawing;
using System.Text;

using SdlDotNet;
using SdlDotNet.Graphics;
using SdlDotNet.Graphics.Sprites;
using SdlDotNet.Core;
using SdlDotNet.Input;
using System.Collections.Generic; 

namespace LightFall
{
    public class Program
    {
        //The Main Variables!... We Need 'em... :P
        public static int currentScreen = 0;      //The Current Screen (Menu, Gameplay, Help, etc)
       


        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        public static void Main()
        {
            //Startup the program...
            Program Program = new Program();
            Program.Start();

            //Startup the Game and Menu window. Without them, the game would be kind of boring
            Menu Menu = new Menu();
        }

        public void Start() {
            //START everything/setup
            Video.SetVideoMode(440, 300);
            Video.WindowCaption = "Lightfalling";

            Events.Tick += new EventHandler<TickEventArgs>(Events_Tick);
            Events.KeyboardDown += new EventHandler<KeyboardEventArgs>(this.KeyboardDown);
            Events.KeyboardUp += new EventHandler<KeyboardEventArgs>(this.KeyboardUp);
            Events.Quit += new EventHandler<QuitEventArgs>(this.Quit);

            Events.Run();
        }

        //The TICK Event. Draws + moves stuff
        private void Events_Tick(object sender, TickEventArgs e)
        {
            Video.Screen.Fill(Color.Black);

            //Draw the menu and game screen.
            switch (currentScreen)
            {
                case 0: Menu.Update(); break;
                case 1: Game.Update(); break;
            }



            // Update the screen
            Video.Screen.Update();
        }
        //Key Pressed...
        private void KeyboardDown(object sender, KeyboardEventArgs e)
        {


            //Hit keys for menu + game
            switch (currentScreen)
            {
                case 0: Menu.KeyDown(e); break;
                case 1: Game.KeyDown(e); break;
            }
        }
        //Key Released...
        private void KeyboardUp(object sender, KeyboardEventArgs e)
        {
        }
        //End the game... Like, right now. END IT :)
        private void Quit(object sender, QuitEventArgs e)
        {
            Events.QuitApplication();
        }
    }
}

I'm totally lost now Tongue It's mostly because of my little knowledge with C#.

Any help is appreciated Smiley

Logged

Alex May
...is probably drunk right now.
Level 10
*


hen hao wan


View Profile WWW
« Reply #37 on: May 15, 2009, 10:03:45 PM »

You probably need to decalre the PBullet class as public.

public class PBullet
{
...
}
Logged

Noel Berry
Level 4
****


Yarr!


View Profile WWW
« Reply #38 on: May 16, 2009, 06:24:13 AM »

That worked, thank you!

I had tried that earlier, but then the error didn't go away (or leave the little error messages at the bottom), so I figured it wasn't the solution. But, when I put it, and then ran the game, it just went away... Tongue

Logged

Pages: 1 [2]
Print
Jump to:  

Theme orange-lt created by panic