I have foreach loop that goes through an array of a class and has an if statement that uses one of the class' properties, however it doesn't work. I get this error:
Board.Boat.length cannot be accessed with an instance reference; qualify it with a type name instead.
How do you solve that here's the code. Keep in mind it still isn't finished.
using System;
using System.Collections.Generic;
using System.Numerics;
namespace BattleShip
{
class Board
{
class Boat
{
// This class is made for storing the meta-data of each individual boat
// Determines the start point
static int[,] pos = new int[xBoardSize, yBoardSize];
// Determines the direction of the boat (0 = horizontal, 1 = vertical)
static int direction = 0;
// Keeps track of the boat's size
static int length = 1;
// Keeps track if tile is hit or untouched
static int[] stateList;
// Searches fora oat object and
static Boat SearchForBoat (Vector2 coords, Boat[] database)
{
foreach (Boat boat in database)
{
for (int i = 0; i < boat.length; i++)
}
}
}
// These variables determine the size of the board
static int xBoardSize = 10;
static int yBoardSize = 10;
}
}
It's because length property is static. Such properties are rather class properites, while others are instance properties, i.e. static field are use with type (and the other with instantiated object of a class). In your case it should be Boat.length instead of boat.length.
Remark: you should consider those static properties, as length seems to me like it should depend on particular object, thus should not be static.
There error is telling you that you are trying to access a static property from an object instance.
foreach (Boat boat in database) // give me each real boat from database
{
for (int i = 0; i < boat.length; i++) // access an individual boat length
However, because length is static, technically the boat instance doesn't have a property called length.
I have taken the liberty to SRP (single responsibility principle) and normalize your code
The single responsibility principle is a computer programming
principle that states that every module, class, or function1 should
have responsibility over a single part of the functionality provided
by the software, and that responsibility should be entirely
encapsulated by the class, module or function.
As such it removed all your static guff
Use the static modifier to declare a static member, which belongs to
the type itself rather than to a specific object.
public class Board
{
// These variables determine the size of the board
public const int XBoardSize = 10;
public const int YBoardSize = 10;
// a board has an array of boats, seems logical
public Boat[] Boats { get; set; }
// a board can find boats on it
public Boat SearchForBoat(Vector2 coords )
{
foreach (var boat in Boats)
{
for (int i = 0; i < boat.Length; i++)
/// do stuff here
}
}
}
// concrete boat class, which you can make instances from
public class Boat
{
// notice not static, we are saying an individual "boat" can have these properties
public int[,] Pos = new int[Board.XBoardSize, Board.YBoardSize];
public int Direction { get; set; }
public int Length { get; set; } = 1;
public int[] StateList { get; set; }
}
The static member is callable on a class even when no instance of the class has been created. The static member is always accessed by the class name, not the instance name.
for (int i = 0; i < boat.length; i++) //wrong access static from an instance
for (int i = 0; i < Boat.length; i++) //correct access static from the type itself (class itlsef)
read here for more information
I've got multiple comments for your code:
1st static is to be considered as something unique. It is something like a global value shared by all object instances
From Microsoft documentation on static
The static member is callable on a class even when no instance of the class has been created. The static member is always accessed by the class name, not the instance name. Only one copy of a static member exists, regardless of how many instances of the class are created.
With that in mind your Boat class will become:
public class Boat
{
// This class is made for storing the meta-data of each individual boat
// Determines the start point
public int[,] pos = new int[xBoardSize, yBoardSize];
// Determines the direction of the boat (0 = horizontal, 1 = vertical)
public int direction = 0;
// Keeps track of the boat's size
public int length = 1;
// Keeps track if tile is hit or untouched
public int[] stateList;
}
Your boats should now be made part of your Board with a Has-A relationship:
public class Board
{
private Boat[] boats;
public Board(Boat[] boats) {
// initialize th boats for the specific game
this.boats = boats
}
Boat SearchForBoat (Vector2 coords)
{
foreach (Boat boat in boats)
{
for (int i = 0; i < boat.length; i++)
}
}
// These variables determine the size of the board
int xBoardSize = 10;
int yBoardSize = 10;
}
Then you need to initialize via a constructor and use the specific instances
Related
I am developing a little console game where you go through a dungeon. I'm trying to make a potion system for it, the idea is that when you use a potion, it changes a specific stat of the player.
The stats of the player are stored in a static class called Stats. I want to create different potions from the same class, and change the stat the potion acts on using its constructor method. The way I want this to work is that, when a new potion instance is created, I pass to the constructor a reference to the stat variable, and the constructor will store that reference in a variable, to use it when the potion is used.
I tried using delegates with getters and setters, but it didn't work because they only work with functions. I can solve this problem making a potion id system, or learning to proper use pointers, but I prefer to use only safe code.
My question is: There is a way in c# to store a reference to a variable in another variable?
The Stats class:
static class Stats{
public static int health = 10,
strenght = 5,
defense = 20;
}
The potion class:
class Potion {
int statRef; //This is the "reference holder" variable I was asking about.
int magnitude;
public Potion(ref int stat, int _magnitude)
{
magnitude = _magnitude;
statRef = stat; //Here I want to save the reference to the stat to the "reference holder"
}
public void UsePotion()
{
statRef += magnitude; //Here I want to change the referenced variable's value.
}
}
The main program:
class Program{
static class Main(string[] args)
{
Potion lifePotion = new Potion(Stats.life, 5);
Potion strenghtPotion = new Potion(Stats.strenght, 5);
Potion defensePotion = new Potion(Stats.defense, 10);
lifePotion.UsePotion();
strenghtPotion.UsePotion();
defensePotion.UsePotion();
Console.WriteLine(Stats.health);
Console.WriteLine(Stats.strenght);
Console.WriteLine(Stats.defense);
}
}
Note that a class is a reference type. So, variables of a class type automatically contain references and you can assign the same reference to another variable. You can only create an object (i.e., an instance of a class) if the class is not static. Then you can assign it to a variable.
The fields or properties must not be static. Non static members are called instance members. Each instance (object) has its own copy of the fields and properties that must be accessed through a variable name. Static members, in contrast, are shared among all objects of this type and must be accesses through the class name.
Stats stats1 = new Stats();
Stats stats2 = stats1;
now both variables reference the same Stats. If you make the change
stats1.health = 5;
then stats2.health is also 5 since both reference the same object. But of course, you can create independent Stats objects:
Stats stats1 = new Stats();
Stats stats2 = new Stats();
Now changes to stats1 do not affect stats2.
Note that an important idea of Object-Oriented Programming (OOP) is that objects should hide their internal state, i.e., their fields. From outside the state should only be accessible through methods. These methods ensure that the state is manipulated in an adequate manner. E.g., it could be ensured that the health stays within a valid range.
Properties are specialized methods allowing to manipulate the state of fields. They usually consist of a pair of get and set methods and can be accessed like a field.
Example:
class Stats
{
private int _health = 10;
public int Health
{
get { // called when reading the value: int h = stats1.Health;
return _health;
}
set { // called when setting the value: stats1.Health = 5;
if (value < 0) {
_health = 0;
} else if (value > 100) {
_health = 100;
} else {
_health = value;
}
}
}
}
If a property has no such logic, you can use an auto implemented property. It automatically creates an invisible backing field (like _health) and returns and sets its value.
public int Health { get; set; }
Let us put the things together. Simple example of Stats class:
class Stats
{
public int Health { get; set; } = 10;
public int Strength { get; set; } = 5;
public int Defense { get; set; } = 20;
}
Now you can reference a Stats object in the Potion class.
Because you want to have different kinds of potions, you can use inheritance (another important concept of OOP) to achieve this.
You can declare an abstract base class, i.e., a class that cannot be instantiated and can itself contain abstract members, i.e., members that have still to be defined in derived classes.
abstract class Potion
{
// This is the "reference holder" variable you were asking about.
protected Stats _stats;
// Protected means private and visible to derived classes.
protected int _magnitude;
public Potion(Stats stats, int magnitude)
{
_stats = stats; // Save the reference to the stat to the "reference holder"
_magnitude = magnitude;
}
public abstract void UsePotion();
}
Now the derived LifePotion class as an example
class LifePotion : Potion // Inherits Potion.
{
public LifePotion(Stats stats, int magnitude)
: base(stats, magnitude) // Calls the base constructor.
{
}
public override void UsePotion()
{
_stats.Health += _magnitude; // Change a property of the referenced variable.
}
}
Repeat the same for StrenghtPotion and DefensePotion classes with UsePotion setting the Strength and Defense properties.
The adapted main program
class Program{
static class Main(string[] args)
{
var stats = new Stats();
Potion lifePotion = new LifePotion(stats, 5);
Potion strenghtPotion = new StrengthPotion(stats, 5);
Potion defensePotion = new DefensePotion(stats, 10);
lifePotion.UsePotion();
strenghtPotion.UsePotion();
defensePotion.UsePotion();
Console.WriteLine(stats.Health);
Console.WriteLine(stats.Strength);
Console.WriteLine(stats.Defense);
}
}
Note that you can override ToString in a class and provide your own implementation. Add this to the Stats class:
public override string ToString()
{
return $"Health = {Health}, Strength = {Strength}, Defense = {Defense}";
}
Then you can print the health like this in the main routine:
Console.WriteLine(stats); // Prints: Health = 15, Strength = 10, Defense = 30
C# is an object-oriented programming language. That means it is designed to use “objects”, or in-memory instances of classes, that are responsible for maintaining their own state. Now you don't have to do this, but the more you stray from this design the less the language supports you, and the more work you have to do yourself.
Your design is not object-oriented. There probably isn't a “stats” that wanders around in your game, statting things. It probably isn't static either. Static classes are for concepts that can't change. For example, Math.Sin is static; its meaning can't change and my Math.Sin is your Math.Sin.
Instead of static Stats wandering around, your game probably has characters or Mooks. So make a class for them:
public class Mook
{
public string Name { get; }
public int Strength { get; private set; }
public Mook(string name, int strength)
{
Name = string.IsNullOrWhiteSpace(name) ? throw new ArgumentNullException(nameof(name)) : name;
Strength = strength;
}
}
Now you can create instances of Mooks:
var player = new Mook("Link", 10);
var monster = new Mook("Orc", 11);
Mooks can do things, like attack or drink potions. Potions can do things, like modifying your strength. Each class is responsible only for its own internal state; you don't have potions changing Mooks, only the Mook themselves can do that. Classes do things that change themselves through methods. If you want a Mook to drink a potion you have to create a method inside your Mook class to do that:
public void Drink(Potion potion)
{
switch (potion.Sipped())
{
case PotionEffect.ModifyStrength:
Strength += potion.Modifier;
break;
}
}
Potions don't decide what happens outside themselves, only the class using the potion does. To track the possible effects of a potion, create an enum:
public enum PotionEffect
{
Nothing,
ModifyStrength
}
Potions are other objects, so you need to create another class. Remember, each class is responsible for maintaining its own state:
public class Potion
{
public PotionEffect Effect { get; }
public int Modifier { get; }
public int Doses { get; private set; }
public Potion(PotionEffect defaultEffect, int modifier, int doses)
{
Effect = defaultEffect;
Modifier = modifier;
Doses = doses;
}
public PotionEffect Sipped()
{
if (Doses <= 0)
return PotionEffect.Nothing;
Doses--;
return Effect;
}
}
Now you can create potions:
var strengthPotion = new Potion(PotionEffect.ModifyStrength, +1, 10);
And have mooks drink them:
player.Drink(strengthPotion);
monster.Drink(strengthPotion);
Here's my Class:
public class Mark {
public GameObject InstanciatedObject;
public Vector3 ControllerPosition;
public Quaternion ControllerRotation;
public void CreateMark(Mark m, GameObject o, Vector3 p, Quaternion r)
{
m.InstanciatedObject= o;
m.ControllerPosition= p;
m.ControllerRotation = r;
}
}
And I want to use the following lines in another script:
Mark m = new Mark();
m.CreateMark(m, ControllerObject, GetControllerPosition(), GetControllerRotation());
The problem here is that I don't want to create the name of the object manually. I want to create, for instance, m1, m2, m3, etc.
You cannot create variable names at runtime, if that is possible that would not be a basic situation suitable for your level.
Best would be to consider an array:
MarksArray [] m = new MarksArray[size];
for(int i = 0; i < size ; i ++){
m[i] = new Mark();
m[i].CreateMark(param1, param2,...);
}
then you can use the variable like this:
m[0].member = value;
As a side note, you should start complying with C# coding convention, classes and methods use Cap letter on the front.
If are you doing this so you can have something such as a list of multiple unique objects of the same type, such as multiple enemies on the screen you may be better served by using the following:
public class Mark {
public GameObject InstantiatedGameObject;
public Vector3 ControllerPosition;
public Quaternion ControllerRotation;
public Mark(GameObject o, Vector3 p, Quaternion r)
{
InstantiatedGameObject = o;
ControllerPosition = p;
ControllerRotation = r;
}
Then, you would use the following code:
using System.Collections.Generic;
public class Main {
public List<Mark> MarkList = new List<Mark>()
public void Main() {
// do stuff to get the needed variables
MarkList.Add(new Mark(ControllerObject, GetControllerPosition(), GetControllerRotation()));
}
}
This will keep adding new, unique instances of the aMark class objects into an easily accessible list. The benefit to using this method over using an array is that you don't need to determine the maximum size ahead of time, you can dynamically add and remove objects as needed.
Basically I created this skill class:
public class skill
{
public int level { get; set; } //Level of the skill (average of sub-skills' levels)
public int arrayCount { get; set; } //Number of skill/levels in the below arrays
public string[] sub_skills { get; set; } //Names of sub-skills ([0] connect's to levels' [0], etc.)
public int[] sub_levels { get; set; } //Levels of sub-skills ([0] connect's to names' [0], etc.)
void set(int l, int a, string[] sub_s, int[] sub_l)
{
this.level = l; //Sets the skill's level to the input'd l value
this.arrayCount = a; //Sets the skill's array count to the input'd a value
for (int i = 0; i < arrayCount; i++) //For loop to assign each value in both arrays
{
this.sub_skills[i] = sub_s[i]; //Assigns each input'd sub_s array value to each sub_skills value
this.sub_levels[i] = sub_l[i]; //Assigns each input'd sub_l array value to each sub_levels value
}
}
}
Now I have created another class, player:
public class Player
{
public string name { get; set; } //Name of Player
public int level { get; set; } //Player's combat level (average of combat-related skills' levels)
//Start Thievery skill block
string[] thief_s = { "lockpicking", "looting", "pickpocketing", "sneaking" }; //Array for thievery's sub-skill names
int[] thief_i = { 1, 1, 1, 1 }; //Array for thievery's sub-levels
skill thievery = new skill(); //Creates the skill of Thievery (stealing items / passing unnoticed)
//Start Melee skill block
skill melee = new skill(); //Creates the skill of Melee (close-range, strong combat)
//Start Archery skill block
skill archery = new skill(); //Creates the skill of Archery (long-range, weak combat)
//Start Magicka skill block
skill magicka = new skill(); //Creates the skill of Magicka (medium-range, medium combat)
//Start Craftship skill block
skill craftship = new skill(); //Creates the skill of Craftship (retreivement then creation of items from materials)
}
How can I use the set() method from the skill class inside the player class, for a specific skill created inside the player class? For example you can see how I have the skill thievery created there, already with its arrays for it's sub-level's names and levels (variables in the skill class). How can I access thievery's set() function and also use the arrays in it to set thievery's variables? I've tried the line thievery.set(// insertvarshere) but my IDE keeps throwing errors. (I'm using Microsoft Visual Studio Ultimate 2010)
EDIT: Thanks everyone. For some reason setting the set() function to public didn't change anything. When I call thievery.set() my IDE throws red lines under thievery. I'm going to take Charles advice and make the sub-skills skills, and then, if it's possible, apply some sort of tag to them to mark them as part of the major skill. Is that possible, or must I create my own class/function etc. for a tag?
On the face of it, you need to make it public:
public void set(int l, int a, string[] sub_s, int[] sub_l) {
...
Then, for each skill instance, you can call it:
thievery.set( ... );
Where you want to call it, and with what parameter arguments, is up to you.
Unless I'm missing something here you'd need to make the set method visible by either making it public or building a new public method that called it. It's possible that you need an abstracted method that calls set the way you want it called so that it's used properly by consumers.
Where are you trying to call the set method in the Player class. You can only call the set method in another method or constructor of Player class. May be that is why you are getting errors.
Edit: You also need to add public for the method of course.
I come from Java and I'm picking up C# scripting, I've had this issue for around two days now looking for solutions, I've tried setting the class to an instance and everything. This is for a miniature game project that I am working on with some friends.
Either way, I have StatHandler.cs which handles all of our statpoints... then I have HealthManager.cs which is supposed to handle all of the Health Related stuff.
The problem is, I can't for the life of me figure out how to call the variables such as
public int stamina, strength, agility, dexterity, wisdom;
from StatHandler.cs
I know that in Java it would be as easy as
maxHealth = StatHandler.stamina * 10;
Although, you cannot do that with C#, when creating an instance the code looks like this
maxHealth = StatHandler.instance.stamina * 10;
which provides me with the error
NullReferenceException: Object reference not set to an instance of an object
I've also tried inherriting, by doing this
public class HealthHandler : StatHandler {
but it sets all the values to 0 in the HealthHandler class, it doesn't read anything.
I really just need to figure out how to pull the variable from the other C# files, because this is slowing me way down.
It's actually same as in Java. For non-static variables you need a class instance:
StatHandler sh = new StatHandler();
maxHealth = sh.stamina * 10;
or you can declare variables as static in the class like
public static string stamina = 10;
and then access it
maxHealth = StatHandler.stamina * 10;
In C#, you can't use a value type variable without initialize it.
Looks like StatHandler.instance is static method. You can't use your int variables without any assigned. Assign some values to them.
For example
public int stamina = 1, strength = 2, agility = 3, dexterity = 4, wisdom = 5;
NullReferenceException: Object reference not set to an instance of an object
You need to initialize properly. Seems like StatHandler.instance is static and not initialized.
You can initialize it in static constructor
class StatHandler
{
static StatHandler()
{
instance = new Instance(); // Replace Instance with type of instance
}
}
You have two ways to go here.
Full Static Class
public static class StatHandler
{
public static Int32 Stamina = 10;
public static Int32 Strength = 5;
}
And then:
maxHealth = StatHandler.Stamina * 10; // get the value and use it
StatHandler.Stamina = 19; // change the value
Singleton Instance
public class StatHandler
{
public static StatHandler Instance;
public Int32 Stamina = 10;
public Int32 Strength = 5;
// this is called only the first time you invoke the class
static StatHandler()
{
m_Instance = new Instance(); // Replace Instance with type of instance
}
}
And then:
maxHealth = StatHandler.Instance.Stamina * 10; // get the value and use it
StatHandler.Instance.Stamina = 19; // change the value
// replace the current instance:
StatHandler.Instance = new StatHandler();
StatHandler.Instance.Stamina = 19; // change the value
I think the first one is always the best choice, same result, less complexity.
For my own personal amusement, I'm writing what I hope will be the foundation of a game to come later. At current, I'm working on the game "board". Please consider the following:
class Board
{
private Cube[,,] gameBoard;
public Cube[, ,] GameBoard { get; }
private Random rnd;
private Person person;
public Person _Person { get; }
//default constructor
public Board()
{
person = new Person(this);
rnd = new Random();
gameBoard = new Cube[10, 10, 10];
gameBoard.Initialize();
int xAxis = rnd.Next(11);
int yAxis = rnd.Next(11);
int zAxis = rnd.Next(11);
gameBoard[xAxis, yAxis, zAxis].AddContents(person);
}
}
And this:
class Person : IObject
{
public Board GameBoard {get; set;}
public int Size { get; set; }
public void Move()
{
throw new NotImplementedException();
}
public void Move(Cube startLocation, Cube endLocation)
{
startLocation.RemoveContents(this);
endLocation.AddContents(this);
}
public Person(Board gameBoard)
{
Size = 1;
GameBoard = gameBoard;
}
public int[] GetLocation()
{
int[] currentLocation;
var location =
from cubes in GameBoard.GameBoard
where cubes.GetContents.Contains(this)
select cubes;
}
}
I know this is so wrong it's probably not even funny, but this is the roughest of rough cuts.
I'm trying to get GetLocation to return the specific index of the Cube in which the Person is located. So that if the person is in Board.GameBoard[1, 2, 10] I'll be able to retrieve that location (probably as an int[] as listed above). However, at current, I'm unable to compile due to the following error:
Could not find an implementation of the query pattern for source type 'Cubes.Cube[*,*,*]'. 'Where' not found.'
I was pretty sure that LINQ should be able to query multi-dimensional arrays, but I haven't found any documentation on how to do it.
Any suggestions, or am I on the completly wrong track here?
LINQ does not see multidimential arrays as you want it to because they do not implement IEnumerable<T> (although single index arrays do, which is what surprises people). There are several workarounds: you can avoid LINQ for searching the cube or you can write an extension method of your own that does the more traditional walks.
This is a case where I wouldn't use LINQ do to the search, but more than that I probably would keep some references to the various playing pieces in a simple structure (probably a dictionary) that is easier to update and manage. As an idea, your piece object would know where it is on the board itself and could update the cube as it moved by removing itself from one cell and adding itself to another.
It would be important to know if a single cell can contain more than one piece: if so, each cell would need to be a list of some type as well (it appears that way in your code). And once you get to this point, if there are vastly fewer playing pieces than cells, I probably would never actually create the "cube" itself as a datastructure. It would be drawn and the pieces displayed via some Z order drawing algorithm that pulled directly from the piece list, rather than an array. This would depend on the style of game though: if the pieces have attributes and are small in number this would work. If the game is more like 3D Go or similar, then your original cube would make sense... it really depends on how much "personality" (and thus data) your pieces have.
Makes a lot more sense to me to move the int[] currentLocation declaration to the top level inside your Person class, and provide getter/setter methods. Then each Person stores its own location.
For the memory cost of 3 ints, you save yourself from having to query 1000 database entries every time you want to retrieve the person's location.
I think the Person should tell the board where he is, not ask the board. In otherwords, I would create a Location3D class (x,y,z), use that in a GamePiece class that all other things on the board inherit from. That stores location, then each peice knows it's location.
public class Location3D
{
public Location3D(int x, int y, int z) { X = x; Y = y; Z = z; }
public int X { get; set; }
public int Y { get; set; }
public int Z { get; set; }
}
public abstract GamePiece
{
public Location3d { get; set; }
public class Person: GamePiece // inherit GamePiece
{
// everything else about Person
}
public class Board
{
public Board()
{
person = new Person(this);
rnd = new Random();
gameBoard = new Cube[10, 10, 10];
gameBoard.Initialize();
int xAxis = rnd.Next(11);
int yAxis = rnd.Next(11);
int zAxis = rnd.Next(11);
var location = new Location3D(xAxis, yAxis, zAxis);
person.Location = location;
GetCubeAt(location).AddContents(person);
}
public Cube GetCubeAt(Location3D location)
{
return gameBoard[location.X, location.Y, location.Z];
}
public Cube GetCubeAt(int x, int y, int z)
{
return GetCubeAt(new Location3D(x,y,z));
}
}