I have my unity project set up with a graph like this:
public class Point
{
public int X { get; set; }
public int Y { get; set; }
public Point(int x, int y)
{
this.X = x;
this.Y = y;
}
public override bool Equals(object obj)
{
if (obj == null)
{
return false;
}
if (obj is Point)
{
Point p = obj as Point;
return this.X == p.X && this.Y == p.Y;
}
return false;
}
public override int GetHashCode()
{
unchecked
{
int hash = 6949;
hash = hash * 7907 + X.GetHashCode();
hash = hash * 7907 + Y.GetHashCode();
return hash;
}
}
public override string ToString()
{
return "P(" + this.X + ", " + this.Y + ")";
}
}
public enum CellType
{
Empty,
Road,
Structure,
SpecialStructure,
None
}
public class Grid
{
public CellType[,] _grid;
private int _width;
public int Width { get { return _width; } }
private int _height;
public int Height { get { return _height; } }
public List<Point> _roadList = new List<Point>();
public List<Point> _specialStructure = new List<Point>();
public List<Point> _houseStructure = new List<Point>();
public Grid(int width, int height)
{
_width = width;
_height = height;
_grid = new CellType[width, height];
}
// Adding index operator to our Grid class so that we can use grid[][] to access specific cell from our grid.
public CellType this[int i, int j]
{
get
{
return _grid[i, j];
}
set
{
if (value == CellType.Road)
{
_roadList.Add(new Point(i, j));
}
if (value == CellType.SpecialStructure)
{
_specialStructure.Add(new Point(i, j));
}
if (value == CellType.Structure)
{
_houseStructure.Add(new Point(i, j));
}
_grid[i, j] = value;
}
}
And I'm instantiating a series of gameobjects using an L-System algorithm and adding their X and Z positions to the graph like this:
public Grid AddToGrid(Vector3Int position, string type)
{
//CellType parsed_enum = (CellType)System.Enum.Parse(typeof(CellType), type);
switch (type)
{
case "Structure":
placementGrid._houseStructure.Add(new Point((int)position.x, (int)position.z));
break;
case "SpecialStructure":
placementGrid._specialStructure.Add(new Point((int)position.x, (int)position.z));
break;
case "Road":
placementGrid._roadList.Add(new Point((int)position.x, (int)position.z));
break;
}
return placementGrid;
}
And then in one of my scripts I'm calling another function:
public List<Point> GetWakableAdjacentCells(int x, int y, bool isAgent)
{
List<Point> adjacentCells = GetAllAdjacentCells(x, y);
Debug.Log("Adjacent Cells"+ adjacentCells.Count);//3
Debug.Log("X"+x); //-1
Debug.Log("Y"+y);//1
for (int i = adjacentCells.Count - 1; i >= 0; i--)
{
Debug.Log(adjacentCells[i].X); //-1
Debug.Log(adjacentCells[i].Y);//2
if (IsCellWakable(_grid[adjacentCells[i].X, adjacentCells[i].Y], isAgent) == false)
{
adjacentCells.RemoveAt(i);
}
}
return adjacentCells;
}
But this says "index was outside the bounds of the array" at if condition. I've commented each relevant value next to the variables for ease.
The function this condition is checking is this:
public static bool IsCellWakable(CellType cellType, bool aiAgent = false)
{
Debug.Log("boo");
if (aiAgent)
{
return cellType == CellType.Road;
}
return cellType == CellType.Empty || cellType == CellType.Road;
}
What am I doing wrong?
is there a way to implement a grid in such a way way that minus values can be accessed?
Well you commented yourself
// -1
-> -1 can not be a valid index in c#.
If you want to have a wrap around you could probably do e.g.
public CellType this[int i, int j]
{
get
{
i = (i % _width) + _width) % _width;
j = (j % _height) + _height) % _height;
return _grid[i, j];
}
set
{
i = (i % _width) + _width) % _width;
j = (j % _height) + _height) % _height;
switch(value)
{
case CellType.Road:
_roadList.Add(new Point(i, j));
break;
case CellType.SpecialStructure:
_specialStructure.Add(new Point(i, j));
break;
case CellType.Structure:
_houseStructure.Add(new Point(i, j));
break;
}
_grid[i, j] = value;
}
}
This means of course that your grid is basically "infinite" and crossing the top boarder you will be at the bottom again etc.
I have done a console game called "Labyrinth", now I want to bring it to Windows Forms, but I have some problems and exceptions and I can't understand how to make it work.
So, here is functional for printing field in console:
Base class Cell(it has children, like Wall, Door,Key,Empty, Player)
abstract class Cell
{
protected ConsoleColor foregroundColor;
protected ConsoleColor backgroundColor;
protected char symbol;
public Cell(ConsoleColor foregroundColor = ConsoleColor.White,
ConsoleColor backgroundColor = ConsoleColor.Black,
char symbol = ' ')
{
this.foregroundColor = foregroundColor;
this.backgroundColor = backgroundColor;
this.symbol = symbol;
}
public virtual void Draw()
{
Console.ForegroundColor = foregroundColor;
Console.BackgroundColor = backgroundColor;
Console.Write(symbol);
}
}
Here is class FileStorer that works with file(reads level from .txt file) and fills the array string[] field
class FileStorer
{
private string path;
public string[] Result;
public FileStorer(string path)
{
this.path = path;
Result = new string[0];
ReadFile();
}
private void Add(string item)
{
string[] newStr = new string[Result.Length + 1];
for (int i = 0; i < Result.Length; i++)
{
newStr[i] = Result[i];
}
newStr[Result.Length] = item;
Result = newStr;
}
public void ReadFile()
{
using (StreamReader sr = new StreamReader(path, System.Text.Encoding.Default))
{
string line;
while ((line = sr.ReadLine()) != null)
{
Add(line);
}
}
}
}
Class Field
class Field
{
private bool toggle_key = false;
private Cell[,] field;
public int Width
{
get { return field.GetLength(1); }
}
public int Height
{
get { return field.GetLength(0); }
}
public Field(int width, int height)
{
field = new Cell[height, width];
}
public Cell this[int x, int y]
{
get { return field[y, x]; }
set { field[y, x] = value; }
}
public void Print()
{
Console.SetCursorPosition(0, 0);
for (int y = 0; y < Height; y++)
{
for (int x = 0; x < Width; x++)
{
this[x, y].Draw();
}
Console.WriteLine();
}
}
public bool NotOutOfField(int x, int y)
{
return x >= 0 && x < Width && y >= 0 && y < Height;
}
public void MakeEmpty(int x, int y)
{
this[x, y] = new Empty();
}
public bool CanMakeStep(int x, int y)
{
if (NotOutOfField(x, y) && this[x, y] is Empty)
return true;
if (NotOutOfField(x, y) && this[x, y] is Key && !toggle_key)
{
toggle_key = true;
Key.count--;
return true;
}
if (NotOutOfField(x, y) && this[x, y] is Door && toggle_key)
{
toggle_key = false;
Door.count--;
return true;
}
return false;
}
}
Here is class LevelLoader that fills array Cell[,] with proper classes (Door,Key etc.)
class LevelLoader
{
private string[] field;
public LevelLoader(int level)
{
field = new FileStorer($"../../Levels/{level}.txt").Result;
}
public void LoadField(out Field cellField, out Player player)
{
cellField = new Field(field[0].Length, field.Length);
player = new Player(0, 0);
for (int y = 0; y < field.Length; y++)
{
for (int x = 0; x < field[y].Length; x++)
{
switch (field[y][x])
{
case '#':
cellField[x, y] = new Wall();
break;
case ' ':
cellField[x, y] = new Empty();
break;
case 'K':
cellField[x, y] = new Key();
break;
case 'D':
cellField[x, y] = new Door();
break;
case 'P':
player = new Player(x, y);
goto case ' ';
default:
break;
}
}
}
}
}
And finally in class Level I have methods that puts characters on field and prints them
private void PutCharactersOnField()
{
for (int y = 0; y < gameField.Height; y++)
{
for (int x = 0; x < gameField.Width; x++)
{
if (!(gameField[x, y] is Wall) && !((gameField[x, y] is Key)) && !((gameField[x, y] is Door)))
{
gameField[x, y] = new Empty();
}
}
}
gameField[player.X, player.Y] = player;
}
public void PrintLevel()
{
gameField.Print();
player.Draw();
LivesMessage();
if (Door.count == 0)
{
Win();
};
}
I have done some changes for winforms, and I got IndexOutOfRanfeExceprion, I can't understand what went wrong, so here are the same classes and functions but changed for Winforms.
Class Cell
public abstract class Cell
{
public string Path;
public Image Image;
public Cell(string path)
{
Path = path;
if (!File.Exists(Path))
{
throw new Exception("File does not exist: " + Path);
}
Image = new Bitmap(Path);
}
public virtual void Draw(Graphics gr, int j, int i, int side, int x, int y)
{
gr.DrawImage(this.Image, j * side + x, i * side + y, new Rectangle(new Point(0, 0), new Size(side, side)), GraphicsUnit.Pixel);
}
}
FileStorer wasn't modified.
Class Player
public class Player:Cell
{
public string path;
protected Direction direction;
public Image SpriteAnimation;
public int X, Y;
public Size Scale;
public int CurrentFrame = 2;
public int CurrentAnimation = 5;
public Image Part;
public int speed;
public Direction CurrentDirection
{
get { return direction; }
}
public Player() : base("D:\\GIT\\maze-game\\MazeGame\\MazeGame\\Resources\\sprite.png") { }
public Player(Size scale, int x, int y, Image spriteAnimation):base("D:\\GIT\\maze-game\\MazeGame\\MazeGame\\Resources\\sprite.png")
{
SpriteAnimation = spriteAnimation;
Scale = scale;
X = x;
Y = y;
speed = 2;
if (!File.Exists(Path))
{
throw new Exception("File does not exist: " + Path);
}
base.Image = new Bitmap(Path);
}
public Player(int x, int y) : base("D:\\GIT\\maze-game\\MazeGame\\MazeGame\\Resources\\sprite.png")
{
X = x;
Y = y;
}
public void Action()
{
switch (direction)
{
case Direction.Left:
CurrentAnimation = 1;
break;
case Direction.Up:
CurrentAnimation = 3;
break;
case Direction.Right:
CurrentAnimation = 0;
break;
case Direction.Down:
CurrentAnimation = 2;
break;
}
}
public void Static()
{
switch (direction)
{
case Direction.Left:
CurrentAnimation = 6;
break;
case Direction.Up:
CurrentAnimation = 8;
break;
case Direction.Right:
CurrentAnimation = 5;
break;
case Direction.Down:
CurrentAnimation = 7;
break;
}
}
public void Rotate(int dx, int dy)
{
if (dx == -speed)
direction = Direction.Left;
else if (dx == speed)
direction = Direction.Right;
else if (dy == -speed)
direction = Direction.Up;
else if (dy == speed)
direction = Direction.Down;
}
public void MakeStep(int dx, int dy)
{
X += dx;
Y += dy;
}
public void DrawAction(Graphics gr, int x, int y)
{
gr.DrawImage(SpriteAnimation, X + x, Y + y, new Rectangle(new Point(75 * CurrentFrame, 170 * CurrentAnimation), new Size(75, 170)), GraphicsUnit.Pixel);
}
public void DrawStatic(Graphics gr, int x, int y)
{
gr.DrawImage(SpriteAnimation, X + x, Y + y, new Rectangle(new Point(75 * CurrentFrame, 170 * (CurrentAnimation - 5)), new Size(75, 170)), GraphicsUnit.Pixel);
}
}
Class LevelLoader was modified juct for player cell
case 'P':
player = new Player(new Size(35, 75), 100, 100,player.Image);
goto case ' ';
Class Field
class Field
{
private bool toggle_key = false;
private readonly Cell[,] field;
public int Width
{
get { return field.GetLength(1); }
}
public int Height
{
get { return field.GetLength(0); }
}
public Field(int width, int height)
{
field = new Cell[height, width];
}
public Cell this[int x, int y]
{
get { return field[y, x]; }
set { field[y, x] = value; }
}
public void Print(Graphics gr, int side, int j, int i)
{
for (int y = 0; y < Height; y++)
{
for (int x = 0; x < Width; x++)
{
this[x, y].Draw(gr, x, y,side, j, i);
}
}
}
public bool NotOutOfField(int x, int y)
{
return x >= 0 && x < Width && y >= 0 && y < Height;
}
public void MakeEmpty(int x, int y)
{
this[x, y] = new Empty();
}
public bool CanMakeStep(int x, int y)
{
if (NotOutOfField(x, y) && this[x, y] is Empty)
return true;
if (NotOutOfField(x, y) && this[x, y] is Key && !toggle_key)
{
toggle_key = true;
Key.count--;
return true;
}
if (NotOutOfField(x, y) && this[x, y] is Door && toggle_key)
{
toggle_key = false;
Door.count--;
return true;
}
return false;
}
}
Here are Level class method PrintLevel,(PutCharactersOnField wasn't modified)
public void PrintLevel(Graphics gr)
{
gameField.Print(gr, mapSide,point.X, point.Y);
player.DrawStatic(gr, point.X,point.Y);
if (Door.count == 0)
{
Win();
};
}
I'm very new in this topic, but I want to deal with this issue.So, I need help, what is wrong, where I made a mistake?
**Exception was called in the stack of calls
I learn programming oriented object, and I want to do this code but I got those problems, I think I don't really know the concept of virtual.
View image 1
Code:
class Joueur
{
private string _nom;
private string _prenom;
private DateTime _dateDeNaissance;
private string _position;
private bool _reserve;
public string nom
{
get { return _nom; }
set { _nom = value; }
}
public string prenom
{
get { return _prenom; }
set { _prenom = value; }
}
public DateTime dateDeNaissance
{
get { return _dateDeNaissance; }
set { _dateDeNaissance = value; }
}
public string position
{
get { return _position; }
set { _position = value; }
}
public bool reserve
{
get { return _reserve; }
set { _reserve = value; }
}
public Joueur()
{
}
public Joueur(string nom, string prenom, DateTime dateDeNaissance, string position, bool reserve)
{
this.nom = nom;
this.prenom = prenom;
this.dateDeNaissance = dateDeNaissance;
this.position = position;
this.reserve = reserve;
}
public double virtual CalculerPrime(int joues, int gagnes)
{
double Prime;
if (reserve == false)
Prime = 10000 * (gagnes / joues);
else
Prime = ((10000 * (gagnes / joues)) / 2);
return Prime;
}
}
You need to do like this in your code:
public virtual double CalculerPrime(int joues, int gagnes)
{
double Prime;
if (reserve == false)
Prime = 10000 * (gagnes / joues);
else
Prime = ((10000 * (gagnes / joues)) / 2);
return Prime;
}
I have 3 types of objects with same baseclass. What is the best way to make an array of object with same base class?
Do I have to create generic type and use Comparer to do this or there is a way to use some arraylist class instead?
I need to sort object by types AND by fields.
Like this: coupe1,coupe2,sedan1, sedan2,sedan3,hatchback1 etc. and by fields of all array elements.
class Program
{
abstract class Car
{
public string Name { get; set; }
public int Maxspeed { get; set; }
public override string ToString() { return Name + " | " + Maxspeed.ToString();}
}
class Coupe : Car
{
public Coupe(string name, int maxspeed){ Name = name; Maxspeed = maxspeed;}
}
class Sedan : Car
{
public Sedan(string name, int maxspeed) { Name = name; Maxspeed = maxspeed;}
}
class Hatchback : Car
{
public Hatchback(string name, int maxspeed){ Name = name; Maxspeed = maxspeed;}
}
class Cars<T>:IComparer<T> where T:Car
{
private T[] cars;
private int length;
public int Length
{
get{ return length;}
}
public Cars(int i)
{
if (i > 0){ cars = new T[i]; length = i;}\
}
public T this[int i]
{
get {return cars[i];}
set{cars[i] = value;}
}
public int Compare(T x, T y)
{
throw new NotImplementedException();
}
}
static void Main(string[] args)
{
Coupe coupe1 = new Coupe("Audi R8", 250);
Sedan sedan1 = new Sedan("Suzuki Ciaz", 180);
Hatchback hatchback1 = new Hatchback("Hyundai Elantra", 170);
Cars<Car> cars = new Cars<Car>(3);
cars[0] = coupe1;
cars[1] = sedan1;
cars[2] = hatchback1;
for (int i = 0; i < cars.Length; i++)
Console.WriteLine(cars[i].Name + " " + cars[i].Maxspeed.ToString());
Console.ReadKey();
}
}
If you just had a List<Car> you can use LINQ OrderBy to order them first by their type then by anything else
Coupe coupe1 = new Coupe("Audi R8", 250);
Sedan sedan1 = new Sedan("Suzuki Ciaz", 180);
Hatchback hatchback1 = new Hatchback("Hyundai Elantra", 170);
List<Car> cars = new List<Car>(3);
cars.Add(coupe1);
cars.Add(sedan1);
cars.Add(hatchback1);
var orderedByTypeThenSpeedDescending = cars.OrderBy(x => x.GetType())
.ThenByDescending(x => x.MaxSpeed);
I am a little lost here.
Basically, I need to access an array item, a string and display it. Here is the code.
namespace Test3_2_Practice
{
public partial class InterfaceImplementation : Form
{
//Array
ICombatant[] combatants = new ICombatant[2];
public InterfaceImplementation()
{
InitializeComponent();
}
private void btnTest_Click(object sender, EventArgs e)
{
combatants[0] = new PlayerCharacter ("Conan" , 500);
combatants[1] = new MonsterCharacter ("Bob" , 5);
combatants[2] = new MonsterCharacter ("Snake" , 15);
string output = "Fighters" + Environment.NewLine;
for (var i = 0; i < combatants.Length; i++)
{
var character = combatants[i];
output += "Character:" + combatants[i].
}
}
}
}
So I have my array, combatants composed of two types of instances. I want to access the name, "Conan" and add it to a string for output. How do I go about doing that? Here is the rest of the code if that helps. Thanks!
namespace Test3_2_Practice
{
//Interface
interface ICombatant
{
int TakeDamage(int damageAmount);
string GetHealthDisplay();
}
class PlayerCharacter : ICombatant
{
private string characterName;
private int currentHealth;
private int maxHealth;
public string CharacterName
{
get { return characterName; }
set { characterName = value; }
}
public int CurrentHealth
{
get { return currentHealth; }
set { currentHealth = value; }
}
public int MaxHealth
{
get { return maxHealth; }
set { maxHealth = value; }
}
public PlayerCharacter(string characterName, int maxHealth)
{
CharacterName = characterName;
CurrentHealth = MaxHealth = maxHealth;
}
//Damage Class
public int TakeDamage(int damageAmount)
{
if (damageAmount > currentHealth)
{
damageAmount = currentHealth;
return damageAmount;
}
else
{
currentHealth = currentHealth - damageAmount;
return damageAmount;
}
}
//Health Class
public string GetHealthDisplay()
{
return ("Health " + CurrentHealth.ToString() + "/" + MaxHealth).ToString();
}
}
class MonsterCharacter : ICombatant
{
private string monsterName;
private int health;
public string MonsterName
{
get { return monsterName; }
set { monsterName = value; }
}
public int Health
{
get { return health; }
set { health = value; }
}
public MonsterCharacter(string monsterName, int health)
{
MonsterName = monsterName;
Health = health;
}
//Damage Class
public int TakeDamage(int damageAmount)
{
if(damageAmount > health)
{
damageAmount = health;
return damageAmount;
}
else
{
health = health - damageAmount;
return damageAmount;
}
}
//Health Class
public string GetHealthDisplay()
{
return "Health " + Health;
}
}
}
Actually, since name is common to all implementer of interface that Name property should be included to interface itself like
interface ICombatant
{
int TakeDamage(int damageAmount);
string GetHealthDisplay();
public string CharacterName
{
get;
set;
}
}
In your current scenario, you will have to cast it specific concrete type before accessing it
var character = combatants[i];
if(character is PlayerCharacter)
output += "Character:" + ((PlayerCharacter)character).CharacterName;
It's better to make a good use of your interface. Create a new method in your interface:
interface ICombatant
{
int TakeDamage(int damageAmount);
string GetHealthDisplay();
string GetCombatantName(); // added this
}
Then implement in both classes which implements it:
class PlayerCharacter : ICombatant
{
// ... a lot of code ...
public string GetCombatantName()
{
return String.Format("Character: {0}", this.CharacterName);
}
}
class MonsterCharacter: ICombatant
{
// ... a lot of code ...
public string GetCombatantName()
{
return String.Format("Monster: {0}", this.MonsterName);
}
}
And use it like this:
private void btnTest_Click(object sender, EventArgs e)
{
combatants[0] = new PlayerCharacter("Conan", 500);
combatants[1] = new MonsterCharacter("Bob", 5);
combatants[2] = new MonsterCharacter("Snake", 15);
string output = "Fighters" + Environment.NewLine;
foreach (var combatant in combatants)
{
output += combatant.GetCombatantName();
}
}
So if one day you get ten distinct types of ICombatant (like AnimalCharacter, VirusCharacter), you don't have to nest a lot of ifs to check and cast types to get the proper property.
Interfaces are meant exactly to avoid this kind of stuff, hiding the implementation details.