Jump to content

how do i communicate arrays to another form?

- - - - -

  • Please log in to reply
4 replies to this topic

#1
justanothernoob

justanothernoob

    Newbie

  • Members
  • PipPip
  • 22 posts
I am trying to make a game where you have a certain amount of soldiers under your command. In one form(form1) you will upgrade them and buy additional soldiers, but on another form(form2), you will use them to fight.

I have a Soldier Class with values such as health, experience, accuracy, damage

In form1, I have declared an array
Soldier soldiers[] = new Soldier[200];

In form2, I need to get the data from the array soldiers[] (which would be each soldier and its individual attributes (health, exp, etc...)

I have tried many things, but can't figure out the correct way to do this. Any help would be appreciated. If I need to elaborate on something let me know. Thanks.

#2
mark123

mark123

    Newbie

  • Members
  • Pip
  • 1 posts
What about doing something like this:
List<Soldier> soldier = new List<Soldier>();

soldier.Add(new Soldier { Accuracy = 11, Damage = 0, Experience = 10, Health = 100 });

... etc.
Is that acceptable?

#3
sam_coder

sam_coder

    Programming Expert

  • Members
  • PipPipPipPipPipPip
  • 372 posts
I agree with Mark. Collection is the better way to go.
And while a List is very similar to an Array in terms of interaction, for example
list[0].Health is valid, I think you need to recognize some of the differences here.

An array is static in length. So when you initialize an array, you say
int MAX_SOLDIERS = 10;
Soldier[] soldiers = new Soldier[MAX_SOLDIERS];
for (int i = 0; i < soldiers.Length; i++) {
  soldiers[i] = new Soldier();
}

A list is not really the same, once you initialize it, it starts off 0 - length, and it expands or collapses as you use it.
int MAX_SOLDIERS = 10;
List<Soldier> soldiers = new List<Soldier>();
for (int i = 0; i < int MAX_SOLDIERS = 10;; i++) {
  soldiers[i] = new Soldier();
}

There are clear advantages to both. Obviously you have a lot less to take care of in the second. It's clearly more convenient.
And this convenience comes at the cost of some performance. Though don't kid yourself, trying to manage the static nature of the
array will come at a cost of performance too, and in all likelihood, the List collection will be better coded, and result in less overhead.

But how does standard interaction compare?

with an array, you can access it via index.
Soldier soldier_to_kill = soldiers[x];
soldier_to_kill.Health =  0;

you can do the same with the list
Soldier soldier_to_kill = soldiers[x];
soldier_to_kill.Health =  0;

but what if you want to remove a soldier, with the array:
soldiers[x] = null;
//And now I have a gaping hole in my array..
//yes I could just check for null and ignore them, but that array will continue to grow, and become increasingly inefficient.
//so maybe you can reconstruct the array..

Soldier[] new_soldiers = new Soldier[soldiers.Length - 1];
int k = 0;
for (int i = 0; i < soldiers.Length; i++) {
  if (soldiers[i] != null) {
    new_soldiers[k++] = soldiers[i];
  }
}
soldiers = new_soldiers;
//something like that?

consider this in the list:
soldiers.Remove(soldiers[x]);

so while portions of your code can remain, some parts will likely change.

#4
sam_coder

sam_coder

    Programming Expert

  • Members
  • PipPipPipPipPipPip
  • 372 posts

justanothernoob said:

In form2, I need to get the data from the array soldiers[] (which would be each soldier and its individual attributes (health, exp, etc...)

I have tried many things, but can't figure out the correct way to do this. Any help would be appreciated. If I need to elaborate on something let me know. Thanks.

There are a few options you have, I personally would model it. Give context to what a player is.
for example, you have a Players Class
public class Players {
     public static Dictionary<string, Player> CurrentPlayers { get; set; }
     static Players() {
          CurrentPlayers = new Dictionary<string, Player>();
          CurrentPlayers["Player1"] = new Player();
          CurrentPlayers["Player2"] = new Player();
     }
}

lets assume that the Player Class has the soldiers collection
public class Player {
     public List<Soldier> Soldiers { get; set; }
     
}

from either form, you could access the soldiers like this

Players.CurrentPlayers["Player1"].Soldiers[x].Health = 1; //or whatever
//obviously, you could also access player 2's soldiers too
Players.CurrentPlayers["Player2"].Soldiers[x].Health = 1; //or whatever

and you can stick whatever else players need context too, in that player class

#5
Matt Ellen

Matt Ellen

    Newbie

  • Members
  • PipPip
  • 14 posts
This looks like a good candidate for two patterns: MVC and MVVM

I would structure my code in an MVC way for the main game (e.g. your form 2), and use MVVM for the resource management screens (e.g your form1).

The M (model) for both would be the same.

The V (views) would be different, because you're displaying the game in one form and a resource management screen in the other.

The C (controller) and VM (ViewModel) would be very different.

The controller would direct the flow of the game.

The view model essentially allows you to plug your model into the view in a clean fashion.

I'll try and give an example, taking a vertical slice of your game. It'll use Winforms, rather than WPF, but the ideas can be applied to either, and the only difference is in the view layer.

Starting with a VM:
using ExampleModel;

namespace ViewModels
{
    public class ArmyViewModel
    {
        private ArmyModel model;

        public ArmyViewModel(ArmyModel model)
        {
            this.model = model;
        }

        public void UpgradeSoldiers()
        {
            foreach (SoldierModel soldier in model.Soldiers)
            {
                soldier.Upgrade();
            }
        }
    }
}
This is a VM for the ArmyModel, which models an army in your game. (I'm only modelling the ability to upgrade your soldiers, there would be far more code in the final version - whatever logic you need to make your game make sense.) As you can see the VM has a method that allows your army to upgrade each of its soldiers. This works by iterating over the soldiers in the model that the VM contains and calling the Upgrade method on each soldier.

In the layer above the VM (the view) you would have a class that looks something like this:

using System;
using System.Windows.Forms;
using ExampleModel;
using ViewModels;

namespace ExampleApp
{
    public partial class Form1 : Form
    {
        private ArmyViewModel viewModel;

        public Form1(GameModel model)
        {
            viewModel = new ArmyViewModel(model.PlayerArmy);
            InitializeComponent();
        }

        private void btnUpgrade_Click(object sender, EventArgs e)
        {
            viewModel.UpgradeSoldiers();
        }
    }
}
This represents the form that will allow the player to upgrade her soldiers. You can see in the constructor that you need to pass in an instance of the GameModel class, so that the form can instantiate its ArmyViewModel. (I'm not 100% sure this is the best way to do this, but it is sufficient for this example.)

The form also has an event handler, that handles when the "Upgrade the soldiers" button is clicked. As you can see, this calls the UpgradeSoldiers method that the ArmyModel has.

For actually playing the game, you have the controller class, which might look like this:

using ExampleModel;

namespace ExampleControllers
{
    public enum GameState { stopped, paused, running };

    public class GameController
    {
        GameModel model;
        GameState currentState = GameState.stopped;

        public GameController(GameModel model)
        {
            this.model = model;
        }

        /*
         * methods for controlling the flow of the game would go below
         */
    }
}
As you can see in the constructor, the GameController constructor take a game model, and stores it for future reference (in all the flow control methods, etc.).

Then in your form2, you would have code like this:

using System.Windows.Forms;
using ExampleControllers;
using ExampleModel;

namespace ExampleApp
{
    public partial class Form2 : Form
    {
        GameController controller;
        public Form2(GameModel model )
        {
            controller = new GameController(model);
            InitializeComponent();
        }

        /*
         * code to handle whatever events take place on this form (e.g. menu clicks) should go below here
         */
    }
}
So you can see that creating this form creates the controller using an already created model of the game.

Tying the two forms together is the Program class, which you'll find in the main project. It kicks off the application.

The one I have looks like this:

using System;
using System.Windows.Forms;
using ExampleModel;

namespace ExampleApp
{
    static class Program
    {
        static private GameModel model = new GameModel();
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new Form1(model));
        }
    }
}
Ass you can see the class creates an instance of Form1 and displays it. Most of this code is generated by visual studio, but I added in the GameModel private member, and the passing of it into the constructor for Form1.

To get the same set of soldiers that are held in the model into Form2 you can make Form2 be a sort of singleton, so you would change the class like this:

using System;
using System.Windows.Forms;
using ExampleModel;

namespace ExampleApp
{
    static class Program
    {
        static private GameModel model = new GameModel();
        static private private Form2 form2;
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            form2 = new Form(model);
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new Form1(model));
        }
    }
}
In the above I've added in 2 lines of code, one declaring form2 and the other instantiating it, passing in the model as it does. this means that forms2 and the instance of Form1 have the same model, so the soldiers are the same. so anything you do to the soldiers in form2 will apply to the soldiers in the instance of Form1.

For completeness I'll show you the skeletons of the model classes:

namespace ExampleModel
{
    public class GameModel
    {
        public ArmyModel PlayerArmy
        {
            get;
            private set;
        }

        public GameModel()
        {
            PlayerArmy = new ArmyModel();
        }
    }
}
using System.Collections.Generic;

namespace ExampleModel
{
    public class ArmyModel
    {
        private readonly List<SoldierModel> soldiers = new List<SoldierModel>();

        public IEnumerable<SoldierModel> Soldiers
        {
            get{return soldiers;}
        }
    }
}
namespace ExampleModel
{
    public class SoldierModel
    {
        public void Upgrade()
        {
            //whatever this does
        }
    }
}
The interesting part is in the ArmyModel: it is using a List<SoldierModel> to hold hall the soldiers in an army. The List<T> generic class implements the IEnumerable<T> generic interface which allows developers to iterate over the structure in a foreach loop and use it in other fun things like Linq statements. You'll notice that the Soldiers property only exposes the IEnumerable<T> interface. This is so that someone accessing the list of soldiers can only iterate over it. It is important to know how much functionality you want to expose to others when designing your classes.

For example you could change the above to look like this:

        public List<SoldierModel> Soldiers
        {
            get{return soldiers;}
        }
and that would allow anyone accessing the property to have full access to the list, which would allow adding and removing elements, as well as all the other public methods of the List<T> class. This can be undesirable if you want strict control over how soldiers are added and removed from the army.

So, the short answer to your question is to store the soldiers for your player in a list of soldiers that is passed to both forms.

Edited by Matt Ellen, 27 December 2010 - 05:19 PM.





1 user(s) are reading this topic

0 members, 1 guests, 0 anonymous users