I began setting up my system by taking the Grid system supplied by Pack publishing (). This is how it's initialized:
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
{
private CellType[,] _grid;
private int _width;
public int Width { get { return _width; } }
private int _height;
public int Height { get { return _height; } }
private List<Point> _roadList = new List<Point>();
private List<Point> _specialStructure = new List<Point>();
private List<Point> _houseStructure = new List<Point>();
public Grid(int width, int height)
{
_width = width;
_height = height;
_grid = new CellType[width, height];
}
public enum CellType
{
Empty,
Road,
Structure,
SpecialStructure,
None
}
public class Grid
{
private CellType[,] _grid;
private int _width;
public int Width { get { return _width; } }
private int _height;
public int Height { get { return _height; } }
private List<Point> _roadList = new List<Point>();
private List<Point> _specialStructure = new List<Point>();
private List<Point> _houseStructure = new List<Point>();
public Grid(int width, int height)
{
_width = width;
_height = height;
_grid = new CellType[width, height];
}
public void Update()
{
Console.Write("GRID IS RUNNING");
}
// 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;
}
}
After I initialized it, I called it from another function like this.
public int width, height;
Grid placementGrid;
private void Start()
{
placementGrid = new Grid(width, height);
Debug.Log(placementGrid.GetRandomRoadPoint());
}
It seems to initialize perfectly. But when I call the functions inside it, I'm returned a null value. I tried calling this function for example:
public Point GetRandomRoadPoint()
{
if (_roadList.Count == 0)
{
return null;
}
return _roadList[UnityEngine.Random.Range(0, _roadList.Count)];
}
I have no idea what I'm doing wrong. I'm basically trying to create a pedestrian AI system for my procedurally generated town.
I tried debugging several times, but I can't seem to find my way around it.
Learning Setter and Getter
I am making a console log app where I create a Box class and make an object and set values: width, height, and length using setter and getter. I was referencing an solution on github, but I haven't make it work yet. I don't know where I made mistake.
My Code
using System;
namespace ClassDemo2
{
class Box
{
private double _width;
private double _height;
private double _length;
public double Width
{
get { return _width; }
set { this._width = Width; }
}
public double Height
{
get { return _height; }
set { this._height = Height; }
}
public double Length
{
get { return _length; }
set {this._length = Length; }
}
public double volume()
{
return Width * Height * Length;
}
}
public class Program
{
static void Main(string[] args)
{
Box box = new Box();
//Set value
box.Width = 12;
box.Height = 12;
box.Length = 12;
//Get value
double width = box.Width;
double height = box.Height;
double length = box.Length;
Console.WriteLine("Box properties");
Console.WriteLine("Width: {0}", width);
Console.WriteLine("Height: {0}", height);
Console.WriteLine("Length: {0}", length);
Console.WriteLine("Volume: {0}", box.volume());
}
}
}
Console Window
The setters in the Box class aren't doing anything. The setters aren't assigning a value to the private fields in the Box class.
You may as well remove the fields altogether and use auto-implemented properties.
For example:
class Box
{
public double Width { get; set; }
public double Height { get; set; }
public double Length { get; set; }
public double Volume()
{
return Width * Height * Length;
}
}
class Box
{
public double Width { get; set; }
public double Height { get; set; }
public double Length { get; set; }
public double volume()
{
return Width * Height * Length;
}
}
Use Auto-Implemented Properties (https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/auto-implemented-properties)
I am having a problem with my homework. I have an instance variable price that is supposed to have a get method and no set method. I have this price variable calculated and assigned through a constructor. I noticed that if you change either the width or height value to another number in Main, the price variable does not change. I added a updatePrice() method that will work if explicitly called in Main but would like to have it implemented automatically through the height/width set methods. I can't get it to work right now.
Explicit call to updatePrice() after changing width variable which works.
using System;
using static System.Console;
class Photo
{
private int width { get; set; }
private int height { get; set; }
protected double price;
public int Width {
get
{
return width;
}
set
{
updatePrice(value, height);
width = value;
}
}
public int Height {
get
{
return height;
}
set
{
updatePrice(width, value);
height = value;
}
}
public Photo(int width, int height)
{
this.width = width;
this.height = height;
if (width == 8 && height == 10)
price = 3.99;
else if (width == 10 && height == 12)
price = 5.99;
else
price = 9.99;
}
public virtual double Price
{
get
{
return price;
}
}
public String ToString()
{
return GetType() + " with a width of " + width + " and a height of " + height +
" with a base price of " + Price.ToString("C2");
}
// used to be updatePrice() w/ no parameters
public void updatePrice(int width, int height)
{
if (width == 8 && height == 10)
price = 3.99;
else if (width == 10 && height == 12)
price = 5.99;
else
price = 9.99;
}
static void Main()
{
Photo photo = new Photo(10, 12);
WriteLine(photo.ToString());
photo.height = 4;
// updatePrice();
WriteLine(photo.ToString());
}
}
Photo with a width of 10 and a height of 12 with a base price of $5.99
// change height to 4
Photo with a width of 10 and a height of 4 with a base price of $5.99
// price should be $9.99
Here is your code refactored as adviced in my comment of the question, with updatePrice marked protected virtual to allow polymorphism, added .Name in ToString, and I removed useless accessors of private fields:
class Photo
{
private int width;
private int height;
protected double price;
public int Width {
get
{
return width;
}
set
{
width = value;
updatePrice();
}
}
public int Height {
get
{
return height;
}
set
{
height = value;
updatePrice();
}
}
public Photo(int width, int height)
{
this.width = width;
this.height = height;
updatePrice();
}
public virtual double Price
{
get
{
return price;
}
}
public override string ToString()
{
return GetType().Name +
" with a width of " + width +
" and a height of " + height +
" with a base price of " + Price.ToString("C2");
}
protected virtual void updatePrice()
{
if (width == 8 && height == 10)
price = 3.99;
else if (width == 10 && height == 12)
price = 5.99;
else
price = 9.99;
}
}
So you don't need to call updatePrice from outside:
static void Main()
{
Photo photo = new Photo(10, 12);
WriteLine(photo.ToString());
photo.height = 4;
WriteLine(photo.ToString());
}
Instead of updating the price, calculate the price dynamically in the Price property. Like this you are sure that it always reflects the current state.
public virtual double Price
{
get
{
if (width == 8 && height == 10) return 3.99;
if (width == 10 && height == 12) return 5.99;
return 9.99;
}
}
I just made this speed test with the property as above:
var stopWatch = new Stopwatch();
stopWatch.Start();
for (int i = 0; i < 1_000_000; i++) {
photo.Height = 4;
double price = photo.Price;
photo.Height = 10;
price = photo.Price;
}
stopWatch.Stop();
Console.WriteLine("Elapsed ms: " + stopWatch.ElapsedMilliseconds);
Note that it calculates the price 2 million times. It takes 67 ms to execute! So it is not worth the effort to try to optimize this calculation. You are only saving a few nanoseconds. But putting the calculation in the property simplifies you code and makes it more reliable.
Note also that you must override the existing ToString method inherited from object.
public override string ToString()
{
return $"{GetType()}: width = {width}, height = {height}, base price = {Price:C2}";
}
Then you can print the photo with
WriteLine(photo);
as WriteLine automatically uses this method now. I also used string interpolation. This is more readable than string concatenation.
I am trying to create a custom texture class, and I want to be able to choose if I the texture is 8bit or float a.k.a I want to be able to set _buffer to be either RGBFloat[] or RGBByte[] but I cant figure out how to do it with out making the whole class generic but if I do it generic it will be possible to set other object types other then just the ones that I want to limit it to. Maybe its possible to use inheritance or interface in some way, I don't know.
Example C# Code: (the places with T are not correct, just placeholder)
public struct RGBFloat
{
public float R { get; }
public float G { get; }
public float B { get; }
public RGBFloat(float r, float g, float b)
{
R = r;
G = g;
B = b;
}
}
public struct RGBByte
{
public byte R { get; }
public byte G { get; }
public byte B { get; }
public RGBByte(byte r, byte g, byte b)
{
R = r;
G = g;
B = b;
}
}
public enum TextureFormat
{
RGBFloat,
RGBByte
}
public class Texture2D
{
public int Width { get; }
public int Height { get; }
private T[] _buffer; // want it to be able to be either RGBFloat[] or RGBByte[] but nothing else.
public Texture2D(int width, int height, TextureFormat textureFormat)
{
Width = width;
Height = height;
switch (textureFormat)
{
case TextureFormat.RGBFloat:
_buffer = new RGBFloat[width * height];
break;
default:
_buffer = new RGBByte[width * height];
break;
}
}
public T this[int i]
{
get { return (_buffer[i]); }
set { _buffer[i] = value; }
}
public T this[int x, int y]
{
get { return (_buffer[Width * y + x]); }
set { _buffer[Width * y + x] = value; }
}
}
Example of a working generic class I have created that is similar to my TextureClass but this one is meant to be able to support any object type.
public class Computebuffer<T>
{
public int Count { get; }
private T[] _buffer;
public Computebuffer(int count)
{
Count = count;
_buffer = new T[count];
}
public T this[int i]
{
get { return (_buffer[i]); }
set { _buffer[i] = value; }
}
public void Initialize(T value)
{
for (int i = 0; i < Count; i++)
{
_buffer[i] = value;
}
}
public void SetData(T[] data)
{
for (int i = 0; i < data.Length; i++)
{
_buffer[i] = data[i];
}
}
public void GetData(T[] data)
{
for (int i = 0; i < data.Length; i++)
{
data[i] = _buffer[i];
}
}
public void Clear()
{
_buffer = new T[Count];
}
}
EDIT 1: (Updated version, almost working):
Issue: With this code I am able to add a RGBFloat to a Texture2D and that doesn't make sense. (see main program)
public interface IRGBType { }
public struct RGBFloat : IRGBType
{
public float R { get; }
public float G { get; }
public float B { get; }
public RGBFloat(float r, float g, float b)
{
R = r;
G = g;
B = b;
}
}
public struct RGBByte : IRGBType
{
public byte R { get; }
public byte G { get; }
public byte B { get; }
public RGBByte(byte r, byte g, byte b)
{
R = r;
G = g;
B = b;
}
}
public class Texture2D<T> where T : struct, IRGBType
{
public int Width { get; }
public int Height { get; }
private IRGBType[] _buffer;
public Texture2D(int width, int height)
{
Width = width;
Height = height;
_buffer = new IRGBType[width * height];
Initialize();
}
private void Initialize()
{
Type type = this.GetType();
if (type == typeof(RGBByte))
{
for (int i = 0; i < Width * Height; i++)
{
_buffer[i] = new RGBByte(0, 0, 0);
}
}
else
{
for (int i = 0; i < Width * Height; i++)
{
_buffer[i] = new RGBFloat(0, 0, 0);
}
}
}
public IRGBType this[int i]
{
get { return (_buffer[i]); }
set { _buffer[i] = value; }
}
public IRGBType this[int x, int y]
{
get { return (_buffer[Width * y + x]); }
set { _buffer[Width * y + x] = value; }
}
}
MainProgram:
Texture2D<RGBFloat> texFloat = new Texture2D<RGBFloat>(64, 64);
Texture2D<RGBByte> texByte = new Texture2D<RGBByte>(64, 64);
texFloat[32, 32] = new RGBFloat(10, 50, 60);
texByte[32, 32] = new RGBFloat(0.9f, 0.24f, 0.5f); // this should not work I should not be able to add a RGBFloat to a RGBByte Texture2D
EDIT 2: (Updated version v3) still one issue, how would I Initialize _buffer array with an optional value, so new Texture2D<RGBFloat>(64, 64) should Initialize with new RGBFloat(0,0,0) and Texture2D<RGBFloat>(64, 64, new RGBFloat(0.5f,0.6f,0.7f)) should Initialize with value provided:
public class Texture2D<T> where T : struct, IRGBType
{
public int Width { get; }
public int Height { get; }
private T[] _buffer;
public Texture2D(int width, int height, T? initializeValue = null)
{
Width = width;
Height = height;
_buffer = new T[width * height];
Initialize(initializeValue);
}
private void Initialize(T? value)
{
Type type = this.GetType();
T rgb;
if (type == typeof(RGBFloat))
{
rgb = value ?? new RGBFloat(0, 0, 0); // Error: Operator '??' cannot be applied to operands of type 'T' and 'RGBFloat'
}
else
{
rgb = value ?? new RGBByte(0, 0, 0); // Error: Operator '??' cannot be applied to operands of type 'T' and 'RGBByte'
}
for(int i = 0; i < Width*Height; i++)
{
_buffer[i] = rgb;
}
}
public T this[int i]
{
get { return (_buffer[i]); }
set { _buffer[i] = value; }
}
public T this[int x, int y]
{
get { return (_buffer[Width * y + x]); }
set { _buffer[Width * y + x] = value; }
}
}
EDIT 3: The full final version that now works correctly:
public interface IRGBType { }
public struct RGBFloat : IRGBType
{
public float R { get; }
public float G { get; }
public float B { get; }
public RGBFloat(float r, float g, float b)
{
R = r;
G = g;
B = b;
}
}
public struct RGBByte : IRGBType
{
public byte R { get; }
public byte G { get; }
public byte B { get; }
public RGBByte(byte r, byte g, byte b)
{
R = r;
G = g;
B = b;
}
}
public class Texture2D<T> where T : struct, IRGBType
{
public int Width { get; }
public int Height { get; }
private T[] _buffer;
public Texture2D(int width, int height, T? initializeValue = null)
{
Width = width;
Height = height;
_buffer = new T[width * height];
if (initializeValue.HasValue)
{
for (int i = 0; i < Width * Height; i++)
{
_buffer[i] = initializeValue.Value;
}
};
}
public T this[int i]
{
get { return (_buffer[i]); }
set { _buffer[i] = value; }
}
public T this[int x, int y]
{
get { return (_buffer[Width * y + x]); }
set { _buffer[Width * y + x] = value; }
}
}
}
You can create an interface that your RGBFloat and RGBByte structs implement, and limit the generic type to that interface. The interface can just be a "marker", with nothing in it:
public interface IRGBType { }
public struct RGBFloat : IRGBType
{
public float R { get; }
public float G { get; }
public float B { get; }
public RGBFloat(float r, float g, float b)
{
R = r;
G = g;
B = b;
}
}
public struct RGBByte : IRGBType
{
public byte R { get; }
public byte G { get; }
public byte B { get; }
public RGBByte(byte r, byte g, byte b)
{
R = r;
G = g;
B = b;
}
}
You can then have your generic class only accept types that implement this interface:
public class Texture2D<T> where T: IRGBType
{
...
}
If you know that you'll always have this interface implemented by a struct, you can further restrict the generic:
public class Texture2D<T> where T: struct, IRGBType
{
...
}
EDIT: Make sure to use the generic T parameter everywhere in your class, not the interface. This is necessary to ensure type safety, otherwise your indexers can accept any IRGBType, which can be very problematic. Correct usage:
public class Texture2D<T> where T: struct, IRGBType
{
private T[] _buffer;
public Texture2D(int width, int height)
{
...
_buffer = new T[width * height];
...
}
public T this[int i]
{
get => _buffer[i];
set => _buffer[i] = value;
}
}
You can try using only one generic struct like this:
public struct RGB<T>
where T : struct,
IComparable, IFormattable, IConvertible,
IComparable<T>, IEquatable<T>
{
public T R { get; }
public T G { get; }
public T B { get; }
public RGB(T r, T g, T b)
{
R = r;
G = g;
B = b;
}
}
public class RGBComputeBuffer<T>
where T : struct,
IComparable, IFormattable, IConvertible,
IComparable<T>, IEquatable<T>
{
public int Count { get; private set; }
private RGB<T>[] _buffer;
public RGBComputeBuffer(int count)
{
_buffer = new RGB<T>[count];
Count = count;
}
public RGB<T> this[int i]
{
get { return _buffer[i]; }
set { if ( !_buffer[i].Equals(value) ) _buffer[i] = value; }
}
public void Initialize(RGB<T> value)
{
for ( int i = 0; i < Count; i++ )
_buffer[i] = value;
}
public void SetData(RGB<T>[] data)
{
Array.Resize(ref _buffer, data.Length);
Count = data.Length;
for ( int i = 0; i < data.Length; i++ )
_buffer[i] = data[i];
}
public void GetData(RGB<T>[] data)
{
Array.Resize(ref data, _buffer.Length);
for ( int i = 0; i < data.Length; i++ )
data[i] = _buffer[i];
}
public void Clear()
{
_buffer = new RGB<T>[Count];
}
}
Example of usage:
var bufferOfRGBByte = new RGBCompositeBuffer<byte>(100);
var bufferOfRGBFloat = new RGBCompositeBuffer<float>(100);
An interface would be your best bet. By having RGBFloat and RGBByte implement an interface then you can use that interface type in your array. It will also allow adding other RGB types later.
public interface IRGB
{
}
public struct RGBFloat : IRGB
{
public float R { get; }
public float G { get; }
public float B { get; }
public RGBFloat(float r, float g, float b)
{
R = r;
G = g;
B = b;
}
}
public struct RGBByte : IRGB
{
public byte R { get; }
public byte G { get; }
public byte B { get; }
public RGBByte(byte r, byte g, byte b)
{
R = r;
G = g;
B = b;
}
}
public enum TextureFormat
{
RGBFloat,
RGBByte
}
public class Texture2D
{
public int Width { get; }
public int Height { get; }
private IRGB[] _buffer; // want it to be able to be either RGBFloat[] or RGBByte[] but nothing else.
public Texture2D(int width, int height, TextureFormat textureFormat)
{
Width = width;
Height = height;
switch (textureFormat)
{
case TextureFormat.RGBFloat:
_buffer = new IRGB[width * height];
break;
default:
_buffer = new IRGB[width * height];
break;
}
}
public IRGB this[int i]
{
get { return (_buffer[i]); }
set { _buffer[i] = value; }
}
public IRGB this[int x, int y]
{
get { return (_buffer[Width * y + x]); }
set { _buffer[Width * y + x] = value; }
}
}
If you want to access the R,G,B variables however you may need to add some kind of accessor methods/properties to the interface.
why the result in the area of the rectangle and it's perimeter comes out by zero?
in using C#
namespace ConsoleApplication8
{
class Program
{
static void Main(string[] args)
{
rec r = new rec();
r.L = Convert.ToInt32(Console.ReadLine());
r.wi = Convert.ToInt32(Console.ReadLine());
Console.WriteLine(r.area());
Console.WriteLine(r.per());
}
}
class rec
{
int l;
int w;
public int L
{
set
{
l = L;
}
get
{
return l;
}
}
public int wi
{
set
{
w = wi;
}
get
{
return w;
}
}
public rec()
{
}
public rec(int x, int y)
{
l = x;
w = y;
}
public double area()
{
return l * w;
}
public int per()
{
return 2 * l + 2 * w;
}
}
}
set should be using implicit value parameter. Your code sets properties to they current value instead:
private int width;
public int Width
{
get { return width; }
set { width = value; }
}
Note that since you don't use any logic in get/set you can use auto-implemented properties instead:
public int Width {get;set;} // no need to define private backing field.