If I have a custom class Vector3 and I have a class object Myobject that use the vector3 class as a property and when I set a new vector
myobject.pos = new vector3(x,y,z); the set will trigger in this case Debug.Log("set") as expected but If I instead of creating a new vector I only want to change x but still have set triggered I would want to do myobject.pos.x = x but this will not trigger the set in MyObject but the set in my vector3 class for x is there any way of fixing this so set in MyObject triggers when I change only the "sub property" x of the vector3.
public class MyObject{
private Vector3 p_pos = new Vector3(0, 0, 0);
public Vector3 pos
{
get { return (p_pos); }
set
{
Debug.Log("set");
p_pos = value;
}
}
}
The only way I can think of doing it is to create a separate method in MyObject class like this MyObject.SetPosX(x):
public void SetPosX(double _x)
{
Debug.Log("set");
p_pos.x = _x;
}
But It is not a very clean way of doing it so would prefer another solution.
The way I see it could be implemented in a more structured way is to allow Vector3 notify someone when a property has been changed. My object class would be listening to and react when necessary.
In the code you provide it looks like overhead but in fact, it depends on a real situation.
Code is below
using System;
using System.Diagnostics;
public class Program
{
public static void Main()
{
MyObject myObject = new MyObject();
Vector3 vector3 = new Vector3(1, 1, 1);
myObject.p_pos = vector3;
myObject.p_pos.X = 5;
Console.ReadLine();
}
}
public class Vector3
{
public Vector3(double x, double y, double z)
{
X = x; Y = y; Z = z;
}
private double _x;
private double _y;
private double _z;
public double X
{
get
{
return _x;
}
set
{
_x = value;
OnPropertyChanged(EventArgs.Empty);
}
}
public double Y
{
get
{
return _y;
}
set
{
_y = value;
OnPropertyChanged(EventArgs.Empty);
}
}
public double Z
{
get
{
return _z;
}
set
{
_z = value;
OnPropertyChanged(EventArgs.Empty);
}
}
public event EventHandler PropertyChanged;
protected virtual void OnPropertyChanged(EventArgs e)
{
var handler = PropertyChanged;
if (handler != null)
{
handler(this, e);
}
}
}
public class MyObject
{
private Vector3 _p_pos = null;
public Vector3 p_pos { get
{
return _p_pos;
}
set
{
if (_p_pos != null)
_p_pos.PropertyChanged-= _p_pos_PropertyChanged;
_p_pos = value;
_p_pos.PropertyChanged += _p_pos_PropertyChanged;
}
}
private void _p_pos_PropertyChanged(object sender, EventArgs e)
{
Console.Write("_p_pos_PropertyChanged");
}
}
The other way which could be more preferable is to make vector3 immutable so each time you need to change the value you have to create the new instance of vector3. This should allow you to stay with the lightweight version of vector3 and still have control over its value.
As the reason why it works like that seems not to be answered, I'll give it a shot.
public class TestClass
{
private Vector3 _v = 0;
public Vector3 V { get { return _v; } set { _v = value; } }
void DoSomething ()
{
V = new Vector3 (2, 0, 0); // This will trigger 'set'.
V.x = 2; // This will not.
}
}
If you have a Vector3 property and set its specific values, you set the values within the Vector3 class itself, but do not affect the assignment/reference to the said Vector3. In order to change its x value, you do not set a new or other Vector3 for 'V'. One way to circumvent that, as you already figured out, is simply to use a method to change the values of 'V' and trigger your extra code. Another one would be to have your own class which triggers your extra code when its properties are changed (for Vector3 not quite possible).
If you only want to track changes to Vector3s, you'd have to create something like a value Watcher class, which would be triggered in update to detect changes to values you want to track. To create this could be quite sophisticated and would involve lambda expressions and generics at least, possibly even an entire code structure in Unity by using a global base class for everything that shall inherit from MonoBehavior.
Related
I am adding a set of array values through inspector window. I am trying to achieve to trigger a function, when I change my array values. That is, my script should check if the new values are not equal to old values and then call this function.
I do not want to use Update as it will take more memory and processing power, so what could be the alternative?
public class SetValues : MonoBehaviour {
[Serializable]
public struct SetValues
{
public float Position;
public float Value;
}
public SetValues[] setValues;
void Function_ValuesChanged()
{
Debug.Log("The Value is changed");
//Do Something
}
}
Try MonoBehavior.OnValidate()
Example:
public class SetValues : MonoBehaviour {
[Serializable]
public struct SetValues
{
public float Position;
public float Value;
}
public SetValues[] setValues;
void OnValidate()
{
Debug.Log("The Value is changed");
//Do Something
}
}
If something happens in game and you want to notify other scripts use events. Events are lightweight and easy to implement.
In class that contain array, create property and change array value, only from property. Never directly interact with array field.
// Create Event Arguments
public class OnArrayValueChangedEventArgs : EventArgs
{
public float Position;
public float Value;
}
// Crate Event
public event EventHandler<OnArrayValueChangedEventArgs> OnArrayValueChanged;
Array[] myArray;
// Change Array value only from this property, so when you change value, event will be called
public Array[] MyArray
{
get { return myArray; }
set { myArray = value; OnArrayValueChangedEvent(this, new OnArrayValueChangedEventArgs() { Position = myArray.Position, Value = myArray.Value };}
}
From second class you should just subscribe to this event and do the thing. I will call this event from my GameManager Singleton class.
private void Awake()
{
GameManager.Instance.OnArrayValueChanged += Instance_OnArrayValueChanged;
}
private void Instance_OnArrayValueChanged(object sender, GameManager.OnArrayValueChangedEventArgs e)
{
// Do the thing
}
I have this bit of code:
Brick brick1= new Brick(parent.X - 1,parent.Y);
X & Y are integers,
Basiclly what i want to do is: when the x of the parent brick changes, the x of brick1 changes,where it dosnt matter the value of parent.X, brick1.X will always be equal to parent.X - 1
Is there an way of accomplishing this?
Assuming that Brick is not a struct you could do this. You could also do this through inheritance with a ChildBrick class but unless you need the added complication, at least in my mind, it is simpler to just allow Brick to have a parent that is a Brick and add a constructor for the parent. Then if you retrieve a value and it needs to be computed from the parent you just check for whether you have a parent and calculate accordingly.
class Brick
{
private Brick _parent;
private int _x;
private int _y;
Brick(Brick parent) {_parent = parent);}
Brick(int x, int y)
{
_x = x;
_y=y;
}
public int X
{
get
{
if (_parent != null) return _parent.X - 1;
return _x;
}
}
public int Y
{
get
{
if (_parent != null) return _parent.Y;
return _y;
}
}
}
Just make brick1 a derived class with a calculated read only property
public class childBrick: Brick
{
public new float X
{
get { return base.X - 1.0 }
private set { base.X = value; }
}
public static Brick Make( float x, float y)
{
return new childBrick
{
X = x;
Y = y;
}
}
}
use it like this
Brick brick1 = childBrick.Make(parent.X - 1,parent.Y);
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;
I am trying to write animation component for my game engine. Animation component has to modify (animate) values of any member of any game object. Problem is that members are usually value types, but animation component needs some kind of reference to them, to be able to change it.
First I thought about using reflection, but reflection is too slow. I read about other techniques in C# that may be able to help (Pointers, Reflection.Emit, Expression trees, Dynamic Methods/Objects, delegates, lambda expressions, closures...) But i don't know these things good enough, to be able to solve the problem.
Animation component would have methods that would be able to take and store a reference to random object's member and animate its value over time. Like this: StartSomeAnimation(ref memberToAnimate)
There would be other parameters (like animation length), but problem is with passing members. Reference to memberToAnimate would need to be stored (even if it is value type) so it can be updated by animation component every frame.
The closest I was able to get to the solution on my own is with lambda expressions and Action<> Func<> delegates (see example below). It is about 4x slower than directly changing members + some more garbage allocation. But I still can't make such simple method signature like in example above.
class Program
{
static void Main(string[] args)
{
GameItem g = new GameItem();
Console.WriteLine("Initialized to:" + g.AnimatedField);
g.StartSomeAnimation();
// NOTE: in real application IntializeAnim method would create new animation object
// and add it to animation component that would call update method until
// animation is complete
Console.WriteLine("Animation started:" + g.AnimatedField);
Animation.Update();
Console.WriteLine("Animation update 1:" + g.AnimatedField);
Animation.Update();
Console.WriteLine("Animation update 2:" + g.AnimatedField);
Animation.Update();
Console.WriteLine("Animation update 3:" + g.AnimatedField);
Console.ReadLine();
}
}
class GameItem
{
public int AnimatedField;// Could be any member of any GameItem class
public void StartSomeAnimation()
{
// Question: can creation of getter and setter be moved inside the InitializeAnim method?
Animation.IntializeAnim(
() => AnimatedField, // return value of our member
(x) => this.AnimatedField = x); // set value of our member
}
}
class Animation // this is static dumb class just for simplicity's sake
{
static Action<int> setter;
static Func<int> getter;
// works fine, but we have to write getters and setters each time we start an animation
public static void IntializeAnim(Func<int> getter, Action<int> setter)
{
Animation.getter = getter;
Animation.setter = setter;
}
// Ideally we would need to pass only a member like this,
// but we get an ERROR: cannot use ref or out parameter inside an anonymous method lambda expression or query expression
public static void IntializeAnim(ref int memberToAnimate)
{
Animation.getter = () => memberToAnimate;
Animation.setter = (x) => memberToAnimate = x;
}
public static void Update()
{
// just some quick test code that queries and changes the value of a member that we animate
int currentValue = getter();
if (currentValue == 0)
{
currentValue = 5;
setter(currentValue);
}
else
setter(currentValue + currentValue);
}
}
EDIT: A more complete example added to hopefully make question a little clearer. Please focus on how closures are created with lambda expressions and not on game architecture. Currently for each member, we want to animate, two lambda expressions have to be written each time we start a new animation (IntializeAnim methods). Can starting an animation be simplified? Look at how IntializeAnim methods are called currently.
class Program
{
static bool GameRunning = true;
static void Main(string[] args)
{
// create game items
Lamp lamp = new Lamp();
GameWolrd.AddGameItem(lamp);
Enemy enemy1 = new Enemy();
Enemy enemy2 = new Enemy();
GameWolrd.AddGameItem(enemy1);
GameWolrd.AddGameItem(enemy2);
// simple game loop
while (GameRunning)
{
GameWolrd.Update();
AnimationComponent.Update();
}
}
}
static class GameWolrd
{
static List<IGameItem> gameItems;
public static void Update()
{
for (int i = 0; i < gameItems.Count; i++)
{
IGameItem gameItem = gameItems[i];
gameItem.Update();
}
}
public static void AddGameItem(IGameItem item)
{
gameItems.Add(item);
}
}
static class AnimationComponent
{
static List<IAnimation> animations;
public static void Update()
{
for (int i = 0; i < animations.Count; i++)
{
IAnimation animation = animations[i];
if (animation.Parent == null ||
animation.Parent.IsAlive == false ||
animation.IsFinished)
{// remove animations we don't need
animations.RemoveAt(i);
i--;
}
else // update animation
animation.Update();
}
}
public static void AddAnimation(IAnimation anim)
{
animations.Add(anim);
}
}
interface IAnimation
{
void Update();
bool IsFinished;
IGameItem Parent;
}
/// <summary>
/// Game items worry only about state changes.
/// Nice state transitions/animations logics reside inside IAnimation objects
/// </summary>
interface IGameItem
{
void Update();
bool IsAlive;
}
#region GameItems
class Lamp : IGameItem
{
public float Intensity;
public float ConeRadius;
public bool IsAlive;
public Lamp()
{
// Question: can be creation of getter and setter moved
// inside the InitializeAnim method?
SineOscillation.IntializeAnim(
() => Intensity, // getter
(x) => this.Intensity = x,// setter
parent: this,
max: 1,
min: 0.3f,
speed: 2);
// use same animation algorithm for different member
SineOscillation.IntializeAnim(
() => ConeRadius, // getter
(x) => this.ConeRadius = x,// setter
parent: this,
max: 50,
min: 20f,
speed: 15);
}
public void Update()
{}
}
class Enemy : IGameItem
{
public float EyesGlow;
public float Health;
public float Size;
public bool IsAlive;
public Enemy()
{
Health = 100f;
Size = 20;
// Question: can creation of getter and setter be moved
// inside the InitializeAnim method?
SineOscillation.IntializeAnim(
() => EyesGlow, // getter
(x) => this.EyesGlow = x,// setter
parent: this,
max: 1,
min: 0.5f,
speed: 0.5f);
}
public void Update()
{
if (GotHitbyPlayer)
{
DecreaseValueAnimation.IntializeAnim(
() => Health, // getter
(x) => this.Health = x,// setter
parent: this,
amount: 10,
speed: 1f);
DecreaseValueAnimation.IntializeAnim(
() => Size, // getter
(x) => this.Size = x,// setter
parent: this,
amount: 1.5f,
speed: 0.3f);
}
}
}
#endregion
#region Animations
public class SineOscillation : IAnimation
{
Action<float> setter;
Func<float> getter;
float max;
float min;
float speed;
bool IsFinished;
IGameItem Parent;
// works fine, but we have to write getters and setters each time we start an animation
public static void IntializeAnim(Func<float> getter, Action<float> setter, IGameItem parent, float max, float min, float speed)
{
SineOscillation anim = new SineOscillation();
anim.getter = getter;
anim.setter = setter;
anim.Parent = parent;
anim.max = max;
anim.min = min;
anim.speed = speed;
AnimationComponent.AddAnimation(anim);
}
public void Update()
{
float calcualtedValue = // calculate value using sine formula (use getter if necessary)
setter(calcualtedValue);
}
}
public class DecreaseValueAnimation : IAnimation
{
Action<float> setter;
Func<float> getter;
float startValue;
float amount;
float speed;
bool IsFinished;
IGameItem Parent;
// works fine, but we have to write getters and setters each time we start an animation
public static void IntializeAnim(Func<float> getter, Action<float> setter, IGameItem parent, float amount, float speed)
{
DecreaseValueAnimation anim = new DecreaseValueAnimation();
anim.getter = getter;
anim.setter = setter;
anim.Parent = parent;
anim.amount = amount;
anim.startValue = getter();
anim.speed = speed;
AnimationComponent.AddAnimation(anim);
}
public void Update()
{
float calcualtedValue = getter() - speed;
if (calcualtedValue <= startValue - amount)
{
calcualtedValue = startValue - amount;
this.IsFinished = true;
}
setter(calcualtedValue);
}
}
#endregion
You can create an interface:
interface IGameItem
{
int AnimatedField { get; set; }
}
class GameItem : IGameItem
{
public int AnimatedField { get; set; }
}
class Animation
{
public IGameItem Item { get; set; }
public void Update()
{
if (Item.AnimatedField == 0)
{
Item.AnimatedField = 5;
}
else
{
Item.AnimatedField = Item.AnimatedField + Item.AnimatedField;
}
}
}
And running of your super-animation engine will look like:
class Program
{
static void Main(string[] args)
{
GameItem g = new GameItem() { AnimatedField = 1 };
Animation a = new Animation() { Item = g };
a.Update();
Console.WriteLine(g.AnimatedField);
a.Update();
Console.WriteLine(g.AnimatedField);
a.Update();
Console.WriteLine(g.AnimatedField);
Console.ReadLine();
}
}
However, note that exposing public setters for everyone is not a good practice. Each class must be supplied with an interface which is fully used by it. Read about interface segregation principle and other SOLID principles.
UPD:
Another option is to make items to know how to animate themself:
interface IAnimatable
{
void Animate();
}
class IntegerItem : IAnimatable
{
int _n;
public IntegerItem(int n)
{
_n = n;
}
public void Animate()
{
Console.WriteLine(_n);
}
}
class AnimationSequencer
{
public void Update(IAnimatable item)
{
item.Animate();
}
}
public static class Animation
{
public static void Initialize(object element)
{
//// initialize code
}
public static void Update(object element)
{
//// update code
}
}
public class GameItem : Animatable
{
public GameItem(object memberToAnimate)
{
this.MemberToAnimate = memberToAnimate;
}
}
public class Animatable
{
public object MemberToAnimate { get; set; }
public virtual void Initialize()
{
Animation.Initialize(this.MemberToAnimate);
}
public virtual void Update()
{
Animation.Update(this.MemberToAnimate);
}
}
Thus the code will be:
var gameItem = new GameItem(yourObjectToAnimate);
gameItem.Initialize();
gameItem.Update();