Advertisement

How can my robots "see" what is next to them?

Started by December 06, 2005 01:53 PM
35 comments, last by GameDev.net 18 years, 11 months ago
Please take a look at the code I have posted. I am trying to write a simple "Robot" simulation in a C# Windows Form. I have a "World" object which hosts a 10 x 10 array of "Robot" objects. Can someone make recommendations on how to code my "Robots" so they can look around their "World" and identify other objects? Notice that I have all of these "Robots" in a 10 x 10 array but I don't know how to make them "aware" of each other and what is around them. I want to use OOP, and I want to write the code in a very understandable and intuitive fashion (as much as I can)
[source lange="cpp"]
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;

namespace TestAI
{
	/// <summary>
	/// Summary description for Form1.
	/// </summary>
	public class Form1 : System.Windows.Forms.Form
	{
		private System.Windows.Forms.TextBox textBoxWorld;
		private System.Windows.Forms.PictureBox pictureBoxWorld;
		private System.Windows.Forms.Button button1;

		private World _new_world = new World();

		/// <summary>
		/// Required designer variable.
		/// </summary>
		private System.ComponentModel.Container components = null;

		public Form1()
		{
			//
			// Required for Windows Form Designer support
			//
			InitializeComponent();

			//
			// TODO: Add any constructor code after InitializeComponent call
			//
		}

		/// <summary>
		/// Clean up any resources being used.
		/// </summary>
		protected override void Dispose( bool disposing )
		{
			if( disposing )
			{
				if (components != null) 
				{
					components.Dispose();
				}
			}
			base.Dispose( disposing );
		}

		#region Windows Form Designer generated code
		/// <summary>
		/// Required method for Designer support - do not modify
		/// the contents of this method with the code editor.
		/// </summary>
		private void InitializeComponent()
		{
			this.textBoxWorld = new System.Windows.Forms.TextBox();
			this.pictureBoxWorld = new System.Windows.Forms.PictureBox();
			this.button1 = new System.Windows.Forms.Button();
			this.SuspendLayout();
			// 
			// textBoxWorld
			// 
			this.textBoxWorld.Location = new System.Drawing.Point(16, 32);
			this.textBoxWorld.Multiline = true;
			this.textBoxWorld.Name = "textBoxWorld";
			this.textBoxWorld.Size = new System.Drawing.Size(384, 400);
			this.textBoxWorld.TabIndex = 0;
			this.textBoxWorld.Text = "";
			// 
			// pictureBoxWorld
			// 
			this.pictureBoxWorld.Borderstyle = System.Windows.Forms.Borderstyle.FixedSingle;
			this.pictureBoxWorld.Location = new System.Drawing.Point(472, 40);
			this.pictureBoxWorld.Name = "pictureBoxWorld";
			this.pictureBoxWorld.Size = new System.Drawing.Size(408, 392);
			this.pictureBoxWorld.TabIndex = 1;
			this.pictureBoxWorld.TabStop = false;
			this.pictureBoxWorld.Click += new System.EventHandler(this.pictureBoxWorld_Click);
			this.pictureBoxWorld.Paint += new System.Windows.Forms.PaintEventHandler(this.pictureBoxWorld_Paint);
			// 
			// button1
			// 
			this.button1.Location = new System.Drawing.Point(720, 472);
			this.button1.Name = "button1";
			this.button1.TabIndex = 2;
			this.button1.Text = "button1";
			this.button1.Click += new System.EventHandler(this.button1_Click);
			// 
			// Form1
			// 
			this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
			this.ClientSize = new System.Drawing.Size(960, 606);
			this.Controls.Add(this.button1);
			this.Controls.Add(this.pictureBoxWorld);
			this.Controls.Add(this.textBoxWorld);
			this.Name = "Form1";
			this.Text = "Form1";
			this.Load += new System.EventHandler(this.Form1_Load);
			this.ResumeLayout(false);

		}
		#endregion

		/// <summary>
		/// The main entry point for the application.
		/// </summary>
		[STAThread]
		static void Main() 
		{			
			Application.Run(new Form1());
		}

		private void pictureBoxWorld_Click(object sender, System.EventArgs e)
		{
		
		}

		private void Form1_Load(object sender, System.EventArgs e)
		{			
			_new_world.CreateRobots();
		}

		private void pictureBoxWorld_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
		{
				try
				{
					_new_world.DisplayWorld(e.Graphics);
				}
				catch(Exception ee)
				{
					System.Diagnostics.Debug.WriteLine(ee.ToString());
				}

		}

		private void button1_Click(object sender, System.EventArgs e)
		{			
			this.pictureBoxWorld.Refresh();
		}
	}

	public class World
	{
		private const int _MIN_ROW = 0;
		private const int _MAX_ROW = 9;
		private const int _MIN_COL = 0;
		private const int _MAX_COL = 9;

		public Graphics world_graphics;

		public Image img;

		
		private Robot[,] robo = new Robot[10,10];

		public World()
		{
		}

		public void CreateRobots()
		{
			for(int i=0;i<10;i++)
			{
				for(int j=0;j<10;j++)
				{
					robo[i,j] = new Robot();
					robo[i,j].RobotStatus = Image.FromFile("images\\none.bmp");
					robo[i,j].Name = "";
				}
			}
			
			robo[0,0].Name = "Tom";
			robo[0,0].RobotStatus = Image.FromFile("images\\searcher.bmp");

			robo[9,9].Name = "Bob";
			robo[9,9].RobotStatus = Image.FromFile("images\\searcher.bmp");
		}


		public void DisplayWorld(Graphics gr)
		{
			for(int x=0;x<10;x++)
			{
				for(int y=0;y<10;y++)
				{
					gr.DrawImage(robo[x,y].RobotStatus,x*32,y*32);                         
				}
			}
		}

		
	}
	public class Robot
	{
		private Image _robotStatus;
		private const string _IMAGE_DIR = "images";
		private const string _DIR_DELIMETER = "\\";
		private const string _FULL_IMAGE_DIR = _IMAGE_DIR + _DIR_DELIMETER;
		private const string _ATTACKER = "attacker.bmp";
		private const string _SEARCHER = "searcher.bmp";
		private const string _NONE = "none.bmp";

		private string _name;

		private int _row;
		private int _col;

		public Image RobotStatus
		{
			get{ return _robotStatus;}
			set{_robotStatus = value;}
		}

		public int Row
		{
			get{ return _row;}
			set{
				_row = value;
			}
		}
		
		public string Name
		{
			get{ return _name;}
			set{_name = value;}
		}
		

		public Robot()
		{
		}

	}

}


If ur talking about a fair approach where the Bots have to be smart you its complicated!

If ur talking about a regular game ai then it is simple, u already know where everything is --> its all in the memory banks.

EAch robot takes a look at all the data that ur game handles (ie positions of other robots) and then simple make a decision on what to do.
----------------------------

http://djoubert.co.uk
Advertisement
I didn't read your code, but something as simple as querying the world to know what's around a given position would give you the foundations to build your vision system.

Something like :

World->GetObjectsAround(MyPosition, MySightRadius);

Then you can remove objects that are out of your "view cone" (simply dot your facing with a vector from you to the object/other robot)

With all the remaining objects, within your view cone, you can then test if there's a direct line of sight (to remove objects behind other objects / walls).

This should give you what you're looking for.

Hope this helps

Eric
Quote: Original post by xEricx
I didn't read your code, but something as simple as querying the world to know what's around a given position would give you the foundations to build your vision system.

Something like :

World->GetObjectsAround(MyPosition, MySightRadius);

Then you can remove objects that are out of your "view cone" (simply dot your facing with a vector from you to the object/other robot)

With all the remaining objects, within your view cone, you can then test if there's a direct line of sight (to remove objects behind other objects / walls).

This should give you what you're looking for.

Hope this helps

Eric



I think I see what you are saying from a "40,000" foot view of things.

But how would I code it...and will my code even work under such a system (I know you said you didn't look at it)


For example...and just to keep things simple (for me)... let's say our world consists of 4 cells:

Legend:
CG - CANNOT GO
BB - ROBOT BB
EE - EMPTY
AA - ROBOT AA

CG,CG,CG,CG
CG,BB,EE,CG --- "THE WORLD" as my little robots know it
CG,BB,AA,CG
CG,CG,CG,CG

When Robot "AA" is dropped into the world, the first thing I want it to do is Look Around. From Looking around I want it to gather information:

NORTH: EMPTY
NE: CANNOT GO
E: CANNOT GO
SE: CANNOT GO
S: CANNOT GO
SW: CANNOT GO
W: EMPTY
NW: ROBOT BB IS THERE


Given my current code, here is how the robots get INTO the World:

public void CreateRobots()
{
for(int i=0;i<4;i++)
{
for(int j=0;j<4;j++)
{
robo[i,j] = new Robot();
robo[i,j].RobotStatus = Image.FromFile("images\\none.bmp");
robo[i,j].Name = "";
}
}

robo[0,0].Name = "Tom";
robo[0,0].RobotStatus = Image.FromFile("images\\searcher.bmp");
robo[3,3].Name = "Bob";
robo[3,3].RobotStatus = Image.FromFile("images\\searcher.bmp");
}



========================



Now, there is something about putting a bunch of "Robots" into a 2 dimensional array that bugs me. I don't know quite how to put my finger on it.

I guess it just seems like it will take a lot of work for the Robots to find out the following:

Where am I?
Who is around me?


I want to set things up more INTUITIVELY.......I just don't know how.


I am just wondering if an ARRAY is the storage mechanism I should be using to represent the WORLD.
Like the one guy said something like World.LookAround(Point RobotPosition, int ViewSize)

and in the LookAround function, take the robot position and go out ViewSize grid locations in each 'direction'

So your robot at 4,5 with a view of 1, looks at the following coordinates

3,4 4,4 5,4
3,5 [4,5] 5,5
3,6 4,6 5,6

You could also handle to code as to what the robot should do after look around in the same fucntion and return it as a string like 'Move' or an object or whatever. Or preferably to be better object oriented return the results as locations associated with the contents in maybe an array or something.

Oh well, that might not have been what you were looking for.
Quote: Original post by Anonymous Poster
Like the one guy said something like World.LookAround(Point RobotPosition, int ViewSize)

and in the LookAround function, take the robot position and go out ViewSize grid locations in each 'direction'

So your robot at 4,5 with a view of 1, looks at the following coordinates

3,4 4,4 5,4
3,5 [4,5] 5,5
3,6 4,6 5,6

You could also handle to code as to what the robot should do after look around in the same fucntion and return it as a string like 'Move' or an object or whatever. Or preferably to be better object oriented return the results as locations associated with the contents in maybe an array or something.

Oh well, that might not have been what you were looking for.



Let me think on it some....


I'll come back with more questions.
Advertisement
Well, if your world is a grid, a 2D array is the way to store it.

If you want to have continuous (I'm not sure how to say it, but it should make sense...) space defined by a width and height, you might want to simply give coordinates to your objects and make sure these objects stay within the map.

Then, what you can do is make the world return you a list of objects around your robot. This will remain the same wether you use a continuous world or grid positions. You iterate through your list and test wether or not you see the items.

I don't mean to sound rude, but I guess you might need more coding experience rather than AI help.

(I did read your code this time, and fail to see why every cell in your 2D array is a Robot. You should have cells that can contain robots, and move these robots items over your map.)

Hope this helps

Eric
Basicaly, I would give each robot an x and a y value which would be indices into the 2d array. Each frame, make a decision on what to do. For example, if you want to know where you can move, test each square around the robot's x and y values. Example:

X - Can't go
O - Can go
R - You the robot

XXXXXXXXXX
XOOOOOOOOX
XOROOOOOOX
XOOOOOOOOX
XXXXXXXXXX

A map like this would have an array like this:

int map_array[10][5];

You could also set up some defines in your code to make it easier:
#define CAN_GO 0
#define CANT_GO 1

Then your map ( and array ) would be filled with 1's and 0's, making it easy to distinguish what is what. Your array for the above map would look like this:

1111111111
1000000001
1000000001
1000000001
1111111111

Then for movement, check each square around you.
If you wanted to move up, check like this:

if( map_array[robot_x][robot_y-1] == CAN_GO )
{
Move();
}
else
{
DontMove();
}

Then just do the same for the other directions. This would be for moving right:

if( map_array[robot_x+1][robot_y] == CAN_GO )
{
Move();
}
else
{
DontMove();
}

This way you can easily see where you want to move. If you want to do it with multiple robots that are solid, simply update the map everytime you move. So if you move to square 2,2 from 3,2 on the map then change the map array to unmoveable at 2,2 and moveable at 3,2.

Example, RobotA moved from 3,2 to 2,2
Map Before Move:
1111111111
1000000001
1001000001
1000000001
1111111111

Map After Move:
1111111111
1000000001
1010000001
1000000001
1111111111

By doing it this way the robots will automaticaly not be able to move into each other, because they will think that the space they are moving to is a solid wall.
Mike Popoloski | Journal | SlimDX
What about cheating?
If I wanted to write a "robot battle", where people send in their robot source or script files to fight each other, then how could those robots be prevented from seeing more than they "physically" could?

Define "physically could"

Depending on the "scale" of the simulation, you should use a "radius" within which you can see other items, which should try to resemble a common distance to which you could see in real life (ok, this has to be tweaked for gameplay, so its not really representing real life values, but you get my point).

This topic is closed to new replies.

Advertisement