So yeah, i feel really dumb to ask this question, but i'm currently in the process of writing a simple pathfinder script. I want to use dictionaries like
Dictionary<Floor, FloorInfo>
where floor is the floor tile i am referencing and FloorInfo is custom class as follows:
public class FloorInfo
{
Floor lastFloor;
float floorValue;
public FloorInfo(Floor lastF, float val)
{
lastFloor = lastF;
floorValue = val;
} }
But after i create something like
FloorInfo info = new FloorInfo(current, F);
I cannot get the values, like info.val or info.lastF
Could you explain to me what am I doing wrong? I feel really awkward that i got stuck on something like that or past 45 minutes.
EDIT: Okay, thank you everyone who already answered. Seems like most obvious things can be quite problematic as well. Thanks again and have a nice day!
Make them public if you want to access them from outside the class.
You must mark the fields lastFloot and floorValue as public, or better yet provide a public property for accessing those private fields, like this:
public class FloorInfo
{
private Floor m_lastFloor;
private float m_floorValue;
public Floor LastFloor {
get { return m_lastFloor; }
}
public float FloorValue {
get { return m_floorValue }
}
public FloorInfo(Floor lastF, float val)
{
m_lastFloor = lastF;
m_floorValue = val;
}
}
Then you can access the values like this:
FloorInfo info = new FloorInfo(current, F);
float value = info.FloorValue;
The lastF and val are parameters to your constructor. These are gone as soon as the constructor completes.
You have copied these values to lastFloor and floorValue but currently they are private. You should make these public. If you dont specify a modifier then by default it is private and is not visible outside of the class that they are defined.
public class FloorInfo
{
public Floor lastFloor;
public float floorValue;
public FloorInfo(Floor lastF, float val)
{
lastFloor = lastF;
floorValue = val;
}
}
so you can then reference info.floorValue and info.LastFloor
If you want good design then you should make these into properties and possibly make the set private so they it cannot be changed outside of the FloorInfo class. Also make the properties start with capital letters.
public class FloorInfo
{
public Floor LastFloor { get; private set; }
public float FloorValue { get; private set; }
public FloorInfo(Floor lastF, float val)
{
lastFloor = lastF;
floorValue = val;
}
}
That is because C# class' field's access modifier (by default) is private. What you do above is trying to access private field outside of the scope of the class (which is not allowed).
To access the fields, make its access modifiers public, then you can access them outside of the class scope:
public class FloorInfo
{
public Floor lastFloor; //note the public keyword
public float floorValue;
public FloorInfo(Floor lastF, float val)
{
lastFloor = lastF;
floorValue = val;
}
}
And simply access the fields like:
FloorInfo info = new FloorInfo(current, F);
info.lastFloor = new Floor();
info.floorValue = 45.0;
Note that you do not access the lastF and val from above since they are simply your constructor's parameters. You access the fields of your class, not its constructor's parameters.
That being said, it is more common to access them as property rather than field.
public Floor lastFloor { get; set; }
public float floorValue { get; set; }
This is because with property, you could set something else in your getter and setter (such as checking if the inputs for your property is valid), which is, most of the time, a safer design:
const float floorValueLimit = 20.0;
private float pFloorValue;
public float floorValue {
get { return pFloorValue; }
set {
if (value <= floorValueLimit){ //check limit
pFloorValue = value;
} //else, don't update
}
}
But you cannot do this using field.
Also, as an additional side note, public field would normally have capital letter as its first character in C# typical naming convention:
public class FloorInfo
{
public Floor LastFloor; //note the public keyword
public float FloorValue;
public FloorInfo(Floor lastF, float val)
{
lastFloor = lastF;
floorValue = val;
}
}
Related
I'm creating a platform system using a raycast controller that uses an interface to perform different tasks based on the type of platform with which my player is currently colliding. Some of the platform types include ice, passable blocks and muddy ground.
I want to know how to better optimize my code, as I currently call Unity's somewhat expensive "GetComponent()" function every frame, even if I never change between blocks. What I'd like to do is only call GetComponent() when I change from one type of platform to a different type of platform (i.e. muddy ground --> ice), but don't know how to do this using an interface.
I thought I would be able to compare types using enums, but you're not allowed to declare types in an interface.
if (hit)
{
//I'd only like to run this block of code if the type of platform changes
var platform = hit.collider.gameObject.GetComponent<IPlatform>();
State.IsCollidingWithPassablePlatform = platform.IsPassable;
State.IsJumpBoosted = platform.IsJumpForce;
State.IsBoosted = platform.IsForce;
xForce = platform.XForce;
yForce = platform.YForce;
zForce = platform.ZForce;
defaultParameters.accelerationTimeGrounded = platform.AccelerationTimeGrounded;
defaultParameters.accelerationTimeAirborne = platform.AccelerationTimeAirborne;
Interface example:
interface IPlatform {
float AccelerationTimeGrounded { get; }
float AccelerationTimeAirborne { get; }
float XForce { get; }
float YForce { get; }
float ZForce { get; }
bool IsPassable { get; }
bool IsForce { get; }
bool IsJumpForce { get; }
Ice platform:
public class PlatformIce : MonoBehaviour, IPlatform {
public float AccelerationTimeGrounded { get { return accelerationTimeGrounded; } }
public float AccelerationTimeAirborne { get { return accelerationTimeAirborne; } }
public float XForce { get { return xForce; } }
public float YForce { get { return yForce; } }
public float ZForce { get { return zForce; } }
public virtual bool IsPassable { get { return false; } }
public bool IsForce { get { return false; } }
public bool IsJumpForce { get { return false; } }
[SerializeField]
private float accelerationTimeGrounded = 1.0f;
[SerializeField]
private float accelerationTimeAirborne = 3.0f;
private float xForce = 0;
private float yForce = 0;
private float zForce = 0;
}
Remember your last GameObject and check if this one has changed
private lastGameObj;
[...]
if(lastGameObj!= hit.collider.gameObject) {
var platform = hit.collider.gameObject.GetComponent<IPlatform>();
// [...] your magic here
lastGameObj= hit.collider.gameObject;
}
You will get an additional condition, but you won't run your code 60 times/sec inclusive that GetComponent();.
You CAN use enums inside an Interface, you just have to declare the enum type outside the Interface.
I.E.:
public enum PlatformType {Normal, Ice, Fire, etc}; //Use public only if needed, of course
interface IPlatform {
PlatformType platformType { get; }
//Your other stuff here
}
This will break encapsulation, clearly, but if you really want to use an enum in an interface, there's no way around it.
for example we have class Foo
class Foo {
public class Physics {
float gravity = 9.8f;
float seperateDistance = 10f;
}
public Physics physics;
void Start(){
physics = new Physics();
Bar baz = AddComponent<Bar>();
}
}
Meanwhile, in Bar component, we are trying to get the gravity value inside Foo's physics.
Currently this is the only way I can think of. which i somehow feel not good about. If class Foo is removed then Bar will not working anymore, which i guess is not a good practice.
Inside the baz we created in Foo:
void Start(){
//...
float gravity = getComponent<Foo>().physics.gravity;
//...
}
Is there any better ways to do this?
If I'm reading you correctly, the issue that you're worried about is class coupling. As Georg's answer said, you should be using properties, not fields. But you can avoid class coupling by injecting an interface into Bar that Foo implements. This means that you don't need a Foo to code Bar:
public interface IGravitySource
{
double Gravity { get; }
}
public sealed class Foo : IGravitySource
{
private readonly Physics myPrivatePhysics = new Physics();
private sealed class Physics
{
public double Gravity { get; } = 9.81;
public double Smoothness { get; } = 0.05;
}
public double Gravity => myPrivatePhysics.Gravity;
}
public sealed class Bar
{
private readonly IGravitySource gravitySource;
public Bar(IGravitySource gravitySource)
{
this.gravitySource = gravitySource;
}
public void Start()
{
//...
var gravity = gravitySource.Gravity;
gravity += 1;
//...
}
}
EDIT:
Technically, you might be introducing debt by effectively re-implementing the properties of IGravitySource in multiple places. One solution to this is to have the IGravitySource only have a single member, IGravity. This way, if you decide to extend IGravity with direction, you don't need to change the implementation of Foo:
public interface IGravitySource
{
IGravity Gravity { get; }
}
internal interface IGravity
{
double AccelerationDueToGravity { get; }
}
public sealed class Foo : IGravitySource
{
private readonly Physics myPrivatePhysics = new Physics();
private sealed class Physics : IGravity
{
public double AccelerationDueToGravity { get; } = 9.81;
public double Smoothness { get; } = 0.05;
}
public IGravity Gravity => myPrivatePhysics;
}
public sealed class Bar
{
private readonly IGravitySource gravitySource;
public Bar(IGravitySource gravitySource)
{
this.gravitySource = gravitySource;
}
public void Start()
{
//...
var gravity = gravitySource.Gravity.AccelerationDueToGravity;
gravity += 1;
//...
}
}
This is usually done through properties which are basically pairs of two methods, a getter and setter method.
To use them, just exchange public Physics physics; by public Physics physics { get; set; }. There is no need to change the consuming code since properties are accessed like fields in C#. However, properties also allow you to customize the getter and setter. The good thing is that such a modification is transparent to client code, so you can change the access to that property without having to change code that consumes the property. Further, properties can be virtual or abstract and are allowed to be part of an interface.
You can check if there's a Foo component attached
void Start() {
//Check if there's Foo, if no then give them default to 3;
float gravity = GetComponent<Foo>() ? GetComponent<Foo>().physics.gravity : 3;
//...
}
Or you can also add RequireComponentAttribute to the class Bar, so that Foo will always tied to Bar RequireComponentAttribute
But if you mean 'what if Foo Class(not component) doesn't exist anymore.
I suggest you to do Method Injection like Adam Brown answers.
But there's another solution when class is no longer exist.
here's my thought.
Create a special Attribute to detemine which field is shareable. and then get the field wh use that Attribute.
Example :
of course this isn't tested yet, but by theory it will work.
//Some special attribute
[AttributeUsage(AttributeTargets.Field)]
public class ShareFieldAttribute : Attribute {
}
class Foo {
public class Physics {
float gravity = 9.8f;
float seperateDistance = 10f;
}
//mark ShareField attribute to this field
[ShareField]
public Physics physics;
void Start(){
physics = new Physics();
Bar baz = AddComponent<Bar>();
}
}
class Bar {
void Start() {
//Get the field 'public Physics physics' by name and Type
Physics physics = GetShareField<Physics>("physics", null);
float gravity = physics ? physics.gravity : 3;
//...
}
//Method Helper
public T GetShareField<T>(string fieldName, T defaultValue)
{
foreach(var c in GetComponents<MonoBehaviour>())
{
var fields = c.GetType().GetFields().Where(field => field.FieldType == T && field.Name == fieldName && field.IsDefined(typeof(ShareFieldAttribute), false));
return (T)fields[0].GetValue(c);
}
return defaultValue;
}
}
I am creating a VECTOR object like so, but I am initializing it in the constructor:
public VECTOR position { get; private set; }
I am doing this operation:
position.x += 2;
VECTOR has a variable x defined as:
public double x { get; set; }
I get the error when I do the +=2 operation that says:
Cannot modify the return value of 'Projectile.position' because it is
not a variable
I want to be able to modify the position vector in the current class, and I want it to be accessible but not modifiable in other classes.
Probably, your problem is with the Vector class actually being a struct. Assume you have the following declarations:
public class Projectile
{
public VECTOR position { get; private set; }
public Projectile()
{
position = new VECTOR();
}
}
public struct VECTOR
{
public double x {get; set;}
}
You cant edit properties of the position property directly because you are accessing a copy of that field (explained here).
If you don`t want to convert your VECTOR into a class you can add a method that updates the position of your projectile:
public void UpdatePosition(double newX)
{
var newPosition = position;
newPosition.x = newX;
position = newPosition;
}
That will create a copy of the position, then update its x property and override the stored position. And the usage would be similar to this:
p.UpdatePosition(p.position.x + 2);
Expose the X property (and others) of VECTOR in a class.
public class myObject {
private VECTOR position;
public double X { get{return position.x;}set{position.x=value;}}
}
Usage example:
myObject.X += 2;
If I have a Struct or a Class, lets say I'm using a Vector2 (which has two members, float X and float Y), how am I supposed to properly get/set its methods in a class?
This is the code I know of right now:
public class MyClass
{
private Vector2 vector; //Has to be private
public Vector2 Vector
{
get { return vector; }
set { vector = value; }
}
}
But what if I wanted to edit the members (or certain members) of the Vector2 with the set method? Something like this is what I'm asking for:
set.X
{
vector.X = value.X;
}
set.Y
{
vector.Y = value.Y;
}
And it would be called as simply as Vector.X = 5. I thought up an alternative, using something like public float VectorX { set { vector.X = value; } } but I would prefer a more logical and object-orientated way. Is there?
It makes a BIG difference whether Vector2 is a class or a struct.
Since Vector2 is a class you can simply do
obj.Vector.X = 5;
having
public class MyClass
{
private Vector2 _vector; //Has to be private
public Vector2 Vector
{
get { return vector; }
set { vector = value; }
}
}
If, however Vector2 was a struct then you cannot modify the return value from the get. If you try you will get a compile error:
Cannot modify the return value of ... because it is not a variable.
You can work around this using the method you suggested with
public float VectorX
{
get { return _vector.X; }
set { _vector.X = value; }
}
public float VectorY
{
get { return _vector.Y; }
set { _vector.Y = value; }
}
or you could provide a wrapper class around Vector2 like:
class Vector2Wrapper
{
public Vector2 Vector;
}
and then store a Vector2Wrapper in MyClass like
public class MyClass
{
private Vector2Wrapper _vector2Wrapper;
public Vector2Wrapper VectorWrapper
{
get { return _vector2Wrapper; }
set { _vector2Wrapper= value; }
}
}
and you can then modify it like
obj.VectorWrapper.Vector.X = 5;
you can't specify a submethod to handle that partial set, because that set is handled by the Vector class and us thus out of your scope. the moment someone calls Myobject.Vector they are calling your get funcion, but when it moves on to .X they are calling the Vector.get_X function.
This may be easier to see by looking at the compiled code using the ILDasm tool, which reveals the actual method calls your properties make sugar out of.
Now, what you CAN do is to wrap certain properties, as mentioned. The result would like like so.
public class MyClass
{
private Vector2 _vector; //Has to be private
public Vector2 Vector
{
get { return vector; }
set { vector = value; }
}
public float VectorX
{
get { return _vector.X; }
set { _vector.X = value; }
}
public float VectorY
{
get { return _vector.Y; }
set { _vector.Y = value; }
}
}
Another option might be to use the pattern of INotifyPropertyChanged in your Vector class, raising an event every change which your MyClass can then listen to and react to, thus applying logic when child elements are updated.
There is also the option of using an indexer property
public class MyClass
{
public enum Axis { X, Y }
private Vector2 _vector; //Has to be private
public Vector2 Vector
{
get { return vector; }
set { vector = value; }
}
public float this[Axis axis]
{
get { return axis == Axis.X ? vector.x : vector.y; }
set
{
if(axis == Axis.Y)
{
// Special logic here
vector.Y = value;
}
if(axis == Axis.X)
{
// Special logic here
vector.X = value;
}
}
}
}
Because Vector2 is a struct, you are getting a COPY. You need to use the setter to set a new Vector2. There are 2 ways:
Vector2 v = myClass.Vector; //get a copy of the vector
v.X = 5f; // change its value
myClass.Vector = v; // put it back
I don't really like the following, but it's one statement:
myClass.Vector = new Vector2(2f, myClass.Vector.Y)
Inside MyClass, you can create a property that sets only the X value:
public float X {
get { return Vector.X; }
set {
Vector2 v = Vector;
v.X = value;
Vector = v;
}
}
(Vector can be an automatic property)
I know that this is a pretty obvious question but from what I've seen I can't yet get it.
I don't exactly understand how Getters and Setters work in C#, for instance, I have this code for a character in a game I'm supposed to make for college:
namespace Clase_25_3_2014
{
class Brick
{
private int speed { get; set; }
private Vector2 pos { get; set; }
private Texture2D skin { get; set; }
public Brick(int speed, Vector2 position, Texture2D skin)
{
this.Speed(speed);
this.Pos(position);
this.Skin(skin);
}
}
}
Now, as it stands, where I use the class I try to call it like this:
Brick brick = new Brick(1, Vector2.Zero, mySkin);
brick.GetPos();
Now, obviously that looks weird for you guys, and that's because I haven't yet found out how am I supposed to use it correctly so that it works like a brick.getPos(); from java.
Sorry for the really obvious question, but I can't seem to find an answer for me.
You can't do GetPos because pos is private and you don't have a method called "GetPos". If you make pos public, you can just use Brick.pos to get and Brick.pos(position) to set.
Here's how you could write this class:
namespace Clase_25_3_2014
{
class Brick
{
public Brick(int speed, Vector2 position, Texture2D skin)
{
this.Speed = speed;
this.Pos = position;
this.Skin = skin;
}
public int Speed { get; set; }
public Vector2 Pos { get; set; }
public Texture2D Skin { get; set; }
}
}
Types of Class access:
// lots of explicity (is that a word? :)
public MyClass
{
// Field
// It is recommended to never expose these as public
private int _myField;
// Property (old school, non-auto private field)
public int MyProperty
{
public get
{
return this._myField;
}
public set
{
this._myField = value;
}
}
// Property (new school, auto private field)
// (auto field cannot be accessed in any way)
public int MyProperty2 { public get; private set; }
// Method (these are not needed to get/set values for fields/properties.
public int GetMyMethod()
{
return this._myField;
}
}
var myClass = new MyClass;
// this will not compile,
// access modifier says private
// Set Field value
myClass._myField = 1;
// Get Property Value
var a = myClass.MyProperty;
// Set Property Value
myClass.MyProperty = 2;
// Get Property Value
var b = myClass.MyProperty2;
// this will not compile
// access modifier says private
// Set Property Value
myClass.MyProperty2 = 3;
// Call method that returns value
var c = myClass.GetMyMethod();
When you declare an auto-property in C#, it will get compiled behind the scenes into get and set methods, but you do not need to even think about those. You can access the property as if it were a field.
The benefit of having the property is that you can easily swap it out for a more conventional property with a backing field so that you can provide custom logic in the getter and/or setter. Until you need that, however, it is just extra noise. The auto-property provides the syntactic sugar to avoid that noise.
Brick brick = new Brick(1, Vector2.Zero, mySkin);
Vector2 oldPos = brick.pos;
brick.pos = new Vector2.One;
Try changing to this:
public Brick(int speed, Vector2 position, Texture2D skin)
{
this.Speed = speed;
this.Pos = position;
this.Skin = skin;
}
And with C# you don't need this type of constructors. You can declare an object of this class without constructor with the following way:
public Brick brickTest(){
Speed = 10,
Position = new Vector2(),
Skin = new Texture2D()
};
namespace Clase_25_3_2014
{
class Brick
{
public int Speed { get; set; }
public Vector2 Pos { get; set; }
public Texture2D Skin { get; set; }
public Brick(int speed, Vector2 position, Texture2D skin)
{
this.Speed = speed;
this.Pos = position;
this.Skin = skin;
}
}
}
Using outside:
Brick brick = new Brick(1, Vector2.Zero, mySkin);
Console.WriteLine(Brick.Pos);
however, Behind the scenes the compiler create for each Property:
Private variable storage of the Property-type.
Two function (Get\Set).
Translate the property used to their Functions.
You should just do:
Brick brick = new Brick(1, Vector2.Zero, mySkin);
Vector2 vec = brick.pos;