Constructor not working as expected in Unity - c#

I'm trying to create my GridData data in an Update/Awake function as a test. But I can't seem to get my constructor working. I'm new to CSharp and Unity. so, I'm a bit stuck here.
GridData Class
[System.Serializable]
public class GridData {
[System.Serializable]
public struct rowData{
public float[] colum;
}
public static int numRows =30;
public static int numColums =20;
public rowData[] rows = new rowData[numRows];
//
//Constructor
public GridData(int x, int y){
numRows =y;
numColums = x;
rowData[] rows = new rowData[numColums];
}
}
FactalMapData Class
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class FractalMapData : MonoBehaviour {
public int gridWidth =20;
public int gridWHight =20;
public GridData fractalGrid ;
void Update () {
//TEST
fractalGrid =new GridData(gridWidth,gridWHight);
Debug.Log ("row" + fractalGrid.rows.Length); //Object reference not set to an instance of an object
Debug.Log ("colum" + fractalGrid.rows[0].colum.Length);//Object reference not set to an instance of an object
}
}

As suggested in my comment, I advise you to actually learn oop before constructing oop code.
But learning by mistakes isn't all that bad, so here the ones you made:
[System.Serializable] // not a mistake, but do you really need this?
public class GridData {
[System.Serializable]
public struct rowData{
public float[] colum;
}
// why are you using a struct with only one field in it
// do you really need a struct?
// PITFALL: you'll be wondering later on, why the values for numRows and numColums are the same for all instances
// Why? Because they are static! That means there are *not* instantiated
public static int numRows =30;
public static int numColums =20;
// You are initializing your rowData here
// and again in the constructor. What do you actually want?
public rowData[] rows = new rowData[numRows];
//
//Constructor
public GridData(int x, int y){
// As mentioned before:
// you are assigning instantiating values to static fields
numRows =y;
numColums = x;
// you are *defining* a local variable called rows and initializing it with an array of length numColums
// After we leave the constructor this get's lost
rowData[] rows = new rowData[numColums];
}
}
Another thing you should think about: Why are you creating a class
If you find, that you have a good reason, ask yourself what the responsibility of the class is. E.g.: Should it just hold some data, Does it provide any abstraction, Will it manipulate the data it has, should the data be exposed?
I think you have not answered most of these questions.
Here is how it could work
"I need a class that holds some grid data"
"I want the underlying data structure to be a one dimensional array" (for whatever reason)
"The abstraction is, that the class exposes the data as a two dimensional grid"
"I don't need to initialize the class with existing data" (for now)
Then you can implement the class
public class GridData {
// The concrete data doesn't have to be exposed
// let's make it private
private float[] data;
// let's use properties for this (= less code)
// get; means it's accessible as defined at the beginning (public)
// private set; means only the class it self can change these numbers
public int RowCount { get; private set; }
public int ColCount { get; private set; }
// I want to represent the data as a 2D grid so let's make a function
public float GetCell(int x, int y) {
// validate requests!
if(
x >= ColCount || x < 0
||
y >= RowCount || y < 0
) {
// don't be shy to throw exceptions!
// they communicate exceptional circumstances!
throw new ArgumentOutOfRangeException("Requested cell is not on grid");
}
return data[y * RowCount + x];
}
// I want the data to be set from outside
public float SetCell(int x, int y, float value) {
// excercise for you!
}
public GridData(int cols, int rows) {
RowCount = rows;
ColCount = cols;
this.data = new float[rows * cols];
}
}
Note that there are multiple ways to implement a class that conforms to the needs I formulated.

You never initialize public float[] colum; anywhere in your code.
As a result, when you invoke your constructor, although you correctly create an initialized rows array, the colum field of each rowData instance has not been initialized and will throw a null reference exception when trying to access the length of the collection.

public GridData(int x, int y){
numRows =y;
numColums = x;
rowData[] rows = new rowData[numColums]; // BUG HERE
}
Here you are declaring a LOCAL variable rows, with the same name as the instance field named rows. Thus the instance field rows is never assigned.
You mean:
public GridData(int x, int y){
numRows =y;
numColums = x;
rows = new rowData[numColums];
}

Related

Try to display a int through a static field, but return a weird value (C#)

I'm trying to cut down on how much duplication I have on my code, so I decided to make one of my classes a static class since I decided that its data should really be shared with everyone. Here's the static method below:
// A static class, that holds all object's coordinates, and methods to return & update their values.
internal static class Coordinate
{
private static int[,] PlayerCoordinate { get; set; }
public static int[,] GateCoordinate { get; }
public static int[,] FountainCoordinate { get; }
static Coordinate() // FIRST VALUE IS X (column), SECOND VALUE IS Y (row).
{
PlayerCoordinate = new int[,] { { 0, 0 } };
GateCoordinate = PlayerCoordinate; // Just starts off in the same place as player.
FountainCoordinate = new int[,] { { 2, 0 } };
}
// A static method, that sends the data of all object coordinates, deconstructed into seperate ints.
public static int PlayerColumn() { return PlayerCoordinate[0, 0]; }
public static int PlayerRow() { return PlayerCoordinate[0, 1]; }
public static int GateColumn() { return GateCoordinate[0, 0]; }
public static int GateRow() { return GateCoordinate[0, 1]; }
public static int FountainColumn() { return FountainCoordinate[0, 0]; }
public static int FountainRow() { return FountainCoordinate[0, 1]; }
// Updates the coordinates of the player.
public static void UpdatePlayerCoordinate(int column, int row) { PlayerCoordinate = new int[,] { { column, row } }; }
}
The main issue comes in from my GameManager class. On the console, the beginning section should print out "You are the room at (Column=0, Row=0), but it prints this instead:
Here is the code for my GameManager class:
internal class GameManager
{
private bool IsGameOver;
private Player Player;
private Updater Updater;
// Don't need to call Fountain or Coordinate since they're static
public GameManager()
{
IsGameOver = false;
Player = new();
Updater = new();
}
public void RunGame()
{
while (!IsGameOver)
{
Console.WriteLine("----------------------------------------------------------");
Updater.DisplayPlayerPosition(); // This is the main line that I'm having issues with as of right now. All other functions past this are another problem.
Updater.DisplayPlayerSenses();
string playerInput = Player.GetInput();
Updater.MovePlayer(playerInput);
IsGameOver = Updater.CheckForWin();
}
}
}
And just to make sure, here is the code from my updater class, with the specific method that I'm having issues with:
internal class Updater
{
// No fields
// Default constructor
// Gets the text to show the player his current position.
public void DisplayPlayerPosition() // This is the method that I'm having issues with.
{
Console.WriteLine($"You are in the room at (Column={Coordinate.PlayerColumn}, Row={Coordinate.PlayerRow})");
}
...
I'm fairly new to the static keyword so I believe that I may be missing smth. I personally believe that it's because the class itself hasn't been initialized (like I haven't called the constructor for the Coordinate class, and apparently you can't call a static constructor anyways), but that's just me. If I could get any help, I'd greatly appreciate it!
PlayerColumn() and PlayerRow() are methods, but you are accesing them in the WriteLine statement as if they are properties.
Update your WriteLine to:
Console.WriteLine($"You are in the room at (Column={Coordinate.PlayerColumn()}, Row={Coordinate.PlayerRow()})");

Unsafe structs in C#

I wanted to try c#'s unsafe 'feature' by creating simple structs (Vector, Particle).
SITUATION
I have this 2 structs and want to inject position and velocity vectors into my Particle struct.
As a test I wanted to print out position's X value, but somehow I'm getting random values.
I have the following code here
Vector
public readonly struct Vector
{
public int X { get; }
public int Y { get; }
public Vector(int x, int y)
{
X = x;
Y = y;
}
}
Particle
public unsafe struct Particle
{
private Vector* mPosition;
private Vector* mVelocity;
public Particle(Vector position, Vector velocity = default)
{
mPosition = &position; // here is x 10
mVelocity = &velocity;
}
public int GetPosX()
{
return mPosition->X; // but here not
}
}
Program
public class Program
{
private static void Main(string[] args)
{
var pos = new Vector(10, 5);
var obj = new Particle(pos);
Console.WriteLine(obj.GetPosX()); // prints random value
}
}
PROBLEM
It prints a random value instead of 10.
class Program {
static void Main (string [ ] args) {
unsafe {
Vector pos = new Vector(10, 5);
Particle obj = new Particle(&pos);
// &pos is at position 0xabcdef00 here.
// obj.mPosition has a different value here. It points to a different address? Or am I misunderstanding something
Console.WriteLine(obj.GetPosX( ));
}
}
}
public struct Vector {
public int X;
public int Y;
public Vector (int x, int y) {
X = x;
Y = y;
}
}
public unsafe struct Particle {
private Vector* mPosition;
public Particle (Vector *position) {
mPosition = position; // here is x 10
}
public int GetPosX ( ) {
return mPosition->X; // still 10 here
}
}
This works for me.
Please ... do not ask me why it does. You will notice that I didn't change that much. Just calling Particle with *pos instead of pos. For some reason that fixes the problem. You have to wrap the code with unsafe then and change the constructor for Particle obviously.
I could speculate about why it works, but I'd rather not. Maybe the pointer changes when you pass pos as a parameter for some reason?
You could not take the ref with right value.
Create a variable like int posX = 10;
And you can take the reference with variable. You take the compile time reference and read the runtime reference.
Don't use pointers without fixed. C# stack performance ise very good. You dont need this.
Usually pointers use with linking (C/Cpp dynamic library linking etc). If you have large structs (30 bytes and greater) then you can use the ref parameter tag.

Why does a C# linked list class variable not retain its value after it's assigned?

I am creating a crossword puzzle generator and seem to have an issue with a simple variable assignment of co-ordinates in the grid system.
I have a very simple structure to hold discrete coordinate values as seen below. I have stripped encapsulation to make it easier to read.
public struct vec2
{
public int x, y;
public vec2(int x, int y)
{
this.x = x;
this.y = y;
}
}
This Vec2 Structure is maintained inside a class to hold word values
public struct WordClass
{
string svalue;
bool flag;
public vec2 position;
public WordClass(string sarg, bool barg)
{
this.svalue = sarg;
this.flag = barg;
position = new vec2(0,0);
}
public string StringVal
{
get { return svalue; }
}
public bool FlagVal
{
get { return flag; }
}
public void DisableWord()
{
if (this.flipflop == false)
{
this.flipflop = true;
}
}
public void SetPos(int xa, int ya)
{
this.position.x = xa;
this.position.y = ya;
}
}
This should basically maintain a list of permanent words with a flag for usage, and a variable position as the system calculates optimal locations for the word.
I have a dynamic linked list of words
List<WordClass> WordList = new List<WordClass>();
and to change the coordinates of a word in the wordlist
//Arbitrary values
WordList[0].SetPos(Position_X, Position_Y);
Now my issue is that when I try to use the position of the word, no matter what I set it too prior, it maintains a default value of 0, 0. I have been scratching my head while doing other functionality, and it's left me wondering if I'm missing something important.
Problem seems to be related to the fact that vec2 is a ValueObject and you're trying to change it. The problematic lines are concretely those two:
this.position.x = xa;
this.position.y = ya;
Why? Because vec2 is a a struct each time you read it you get a temporary copy, then modify that copy, then the copy is thrown away, while you're still reading the original, unmodified one. That's one reason why value objects should be immutable as much as possible, unless you've got a strong reason.
The first step should be to make a proper immutable vec2 structure:
public struct vec2
{
public int x { get; private set; }
public int y { get; private set; }
public vec2(int x, int y)
{
this.x = x;
this.y = y;
}
}
Once you've got that, you need to take care of the modification in the SetPos method. Since the structure is immutable you can no longer read it, but instead each time you need to change it you'll throw the current instance away and create a new one:
public void SetPos(int xa, int ya)
{
this.position = new vec2(xa, ya);
}
This creates a brand-new structure and assings it to the internal field, containing the new values. As this doesn't really attempts to modify the structure, but instead change the structure for a new one it won't be subject to the same subtle bug.

How to avoid assignments of multiple arguments passed to constructor

If i have a class in c# containing many variables that needs to be initialised in a constructor e.g.
public class AnyClass
{
private int Var1;
private int Var2;
...
private int varN;
public AnyClass(int InVar1,int InVar2,...,InVarN)
{
Var1=InVar1;
Var2=InVar2;
...
VarN=InVarN;
//
//Code
//
}
}
Is there a way to avoid the intermediate variables InVar1, InVar2 etc in such a way that the arguments passed to the constructor are automatically mapped to the variables contained in the class.
Not at present, C# 6 may include it.
This is what is may look like
Before
public class Point {
private int x, y;
public Point(int x, int y)
this.x = x;
this.y = y;
}
}
After
public class Point(private int x, private int y) {
}
If you don’t mind having properties with a public setter, you can use Object initializers. E.g.
Cat cat = new Cat { Age = 10, Name = "Fluffy" };

Creating a generic list of objects in C#

By way of an intro, I'm creating a basic Quadtree engine for personal learning purposes. I'm wanting this engine to have the capability of working with many different types of shapes (at the moment I'm going with circles and squares) that will all move around in a window and perform some sort of action when collision occurs.
Here are my shape objects as I have them so far:
public class QShape {
public int x { get; set; }
public int y { get; set; }
public string colour { get; set; }
}
public class QCircle : QShape {
public int radius;
public QCircle(int theRadius, int theX, int theY, string theColour) {
this.radius = theRadius;
this.x = theX;
this.y = theY;
this.colour = theColour;
}
}
public class QSquare : QShape {
public int sideLength;
public QSquare(int theSideLength, int theX, int theY, string theColour) {
this.sideLength = theSideLength;
this.x = theX;
this.y = theY;
this.colour = theColour;
}
}
Now my question is, how do I create a generic list (List<T> QObjectList = new List<T>();) in C# so I can have one list containing all these various shapes that may have different properties (e.g., QCircle has the "radius" property while QSquare has the "sideLength" property)? An example of implementation would be helpful as well.
I just know that there is a stupidly obvious answer to this question but I'd appreciate any help anyway. I'm trying to get back into C#; it has obviously been a while...
You need to use downcasting
Store the objects in a list with the base class
List<QShape> shapes = new List<QShape>
You can then upcast the object safely if you know what it is e.g.
if(shapes[0] is QSquare)
{
QSquare square = (QSquare)shapes[0]
}
You can also implicitly downcast objects
QSquare square = new Square(5,0,0,"Blue");
QShape shape = square
For more information read the Upcasting and Downcasting sections here
You should implement an Interface. For example
public interface IHasLength
{
int Length;
}
Then in the implementation you can do
public class QSquare : QShape, IHasLength {
public int sideLength;
public QSquare(int theSideLength, int theX, int theY, string theColour) {
this.sideLength = theSideLength;
this.x = theX;
this.y = theY;
this.colour = theColour;
}
public int Length { get { return sideLength; } }
}
public class QCircle : QShape, IHasLength {
public int radius;
public QSquare(int theSideLength, int theX, int theY, string theColour) {
this.sideLength = theSideLength;
this.x = theX;
this.y = theY;
this.colour = theColour;
}
public int Length { get { return radius; } }
}
FInally, in your list:
List<IHasLength> shapesWithSomeLength = new List<IHasLength>();
Now your list can hold ANYTHING that implements IHasLength whether it's a QCircle, QShape, or even a QDuck if you want as long as it implements IHasLength.
Is this what you want?
public class QShape
{
protected QShape() { }
public int x { get; set; }
public int y { get; set; }
public string colour { get; set; }
}
public class QCircle : QShape
{
public int radius;
public QCircle(int theRadius, int theX, int theY, string theColour)
{
this.radius = theRadius;
this.x = theX;
this.y = theY;
this.colour = theColour;
}
}
public class QSquare : QShape
{
public int sideLength;
public QSquare(int theSideLength, int theX, int theY, string theColour)
{
this.sideLength = theSideLength;
this.x = theX;
this.y = theY;
this.colour = theColour;
}
}
class Program
{
static void Main(string[] args)
{
List<QShape> list = new List<QShape>();
list.Add(new QCircle(100, 50, 50, "Red"));
list.Add(new QCircle(100, 400, 400, "Red"));
list.Add(new QSquare(50, 300, 100, "Blue"));
foreach (var item in list.OfType<QCircle>())
{
item.radius += 10;
}
foreach (var item in list.OfType<QSquare>())
{
item.sideLength += 10;
}
}
}
You could store them in a List<QShape> but this would mean that you could not access type-specific properties.
Generally, you might approach this by providing a common interface in your base class, and overriding behaviour in subclasses. In this way, a common interface can hide a diverse bunch of behaviours. For instance a Grow method could hide the complexities of growing items of different shape and could be called without explicit knowlege of the shape upon which it is operating.
public abstract class QShape {
public abstract void Grow(int amt);
}
public class QSquare : QShape {
private int sideLength;
public override void Grow(int amt)
{
sideLength+=amt;
}
}
public class QCircle : QShape {
private int radius;
public override void Grow(int amt)
{
radius+=amt;
}
}
I feel like i'm missing something but...
List<QCircle> circleObjects = new List<QCircle>();
and
List<QSquare> squareObjects = new List<QSquare>();
will work perfectly well.
EDIT:
Ah, I didn't understand what was being asked.
Yes, as your QCircle and QSquare classes inherit from QShape, you can just do.
List<QShape> shapes= new List<QShape>();
It's worth noting that if you want to access the radius property of all the QCircle's in that list, then you are going to have to filter the list based on type.
You can use Ian Mercer's comment List<QShape>
And here's how you would fill it:
List<QShape> shapes = new List<QShape>();
QCircle circle = new QCircle();
shapes.Add(circle);
To unbox it:
QCircle circle = (QCircle) shapes[0];
If you need to call a method off the base class, no need to unbox, just use it.
Storing
You're already on the right track with your class definitions. What you have to do is make a List of the superclass (in this case, QShape), which will be able to hold all of your shapes.
Here's an example of how you would make it:
List<QShape> objects = new List<QShape>();
objects.add(new QCircle(...));
objects.add(new QSquare(...));
Accessing
The problem here is differentiating what is what once everything is in the list. That's done with the getType() and typeof() methods of C#. (Jon Skeet has an excellent answer about how to do this). Basically, it looks like this:
if(objects.get(some_position).getType() == typeof(QCircle))
QCircle circle = objects.get(some_position);
else if(/* like above with QSquare */)
QSquare square = objects.get(some_position);
After you do this, you can resume using your objects like normal. But if you try accessing them from the list, you can only use the methods and variables that QShape has, as every object put in the list will be cast to it.
public Class abstract Base<T>
{
public abstract List<T>GetList();
}
then do this
public class className:Base<ObjectName>
{
public override List<T>GetList()
{
//do work here
}
}

Categories

Resources