Setting a permanent reference within a class using C#? - c#

Weird question here. I have a main class which manages a bunch of event classes...I want one of the events to alter a value in the main class.
Normally, I would do something like this by using the ref keyword...but in this case, I want to pass in the reference in the constructor, and have any further modifications by the class be reflected in the main class. Is this possible? Right now I have the following:
class MainClass {
float transparency = 0.0f;
List<Events> listOfEvents;
listOfEvents.Add(new FadeInEvent(ref float transparency));
}
class FadeInEvent {
float transparency;
public FadeInEvent(ref float t) {
transparency = t;
}
public void Update() //Occurs every frame
{
transparency += 0.01f;
}
}
This does not work; the transparency in the main class is not updated by the FadeInEvent class. How can I work this out?

How about creating a class for the variable as classes are pass by reference automatically:
class Transparency
{
public float Value = 0.0f;
}
class MainClass
{
Transparency transparency = new Transparency();
// this List<Events> doesn't match class, but I'm sure this was just a sample of a larger problem
List<Events> listOfEvents = new List<Events>();
listOfEvents.Add(new FadeInEvent(transparency));
}
class FadeInEvent{
Transparency transparency;
public FadeInEvent(Transparency t) {
transparency = t;
}
public void Update() //Occurs every frame
{
transparency.Value += 0.01f;
}
}

You cannot keep a reference to a value type, such as float. What you can do is have a FadeInEvent constructor that takes a MainClass and modify it's public Transparency property:
class MainClass
{
float transparency = 0.0f;
public float Transparency
{
get { return transparency;}
set { transparency = value;}
}
List<Events> listOfEvents;
public void AddFadeInEvent()
{
listOfEvents.Add(new FadeInEvent(this));
}
}
class FadeInEvent
{
MainClass mainClass;
public FadeInEvent(MainClass mainClass)
{
this.mainClass = mainClass;
}
public void Update() //Occurs every frame
{
mainClass.Transparency += 0.01f;
}
}

Related

Trigger a function when array values are changed

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
}

Where to initialize a static variable in Unity?

I'm using a static variable in a class but the problem is that it needs another value from another class for it's initial value(See the code snippet). I thought initializing it in Start function. But (correct me if I'm wrong) that means it will be reinitialized for every instance of the object which is something redundant since I want this variable to be initialized for just once at the creation of very first Unit which has UnitManager on.
So my question is at what place would be considered as a good practice to initialize this variable?
Thanks!
Code:
public class UnitManager : MonoBehaviour
{
// Distance in terms of Unity Unity from the target position to stop for units
static float distanceToStop;
private void Start()
{
if (WorldCoordController.OneUnityMeterToRealWorld < 10)
{
distanceToStop = 1 / WorldCoordController.OneUnityMeterToRealWorld;
}
else
{
distanceToStop = 0.1f;
}
}
}
public class UnitManager : MonoBehaviour
{
// Distance in terms of Unity Unity from the target position to stop for units
static float distanceToStop;
static bool distanceSet = false;
private void Start()
{
// If the distance is not set
if(!this.distanceSet)
{
if (WorldCoordController.OneUnityMeterToRealWorld < 10)
{
distanceToStop = 1 / WorldCoordController.OneUnityMeterToRealWorld;
} else {
distanceToStop = 0.1f;
}
this.distanceSet = true;
}
}
The "distanceSet" bool will be shared between the instances so you will only set the distance on the first one :D
Maybe consider calling UnitManager with an Init(); with the WorldCoordController value it needs.
You can create a custom class that will have a static reference to its self and be initialized only once (the first time it gets called).
Example:
public class ExampleClass
{
//Static Functionality
private static ExampleClass _inst;
public static ExampleClass Instance
{
get
{
if (_inst is null)
{
_inst = new ExampleClass();
_inst.Init();
}
return _inst;
}
}
//Class Values
public static int MyValue;
public int Value1;
//private Constructor
private ExampleClass()
{
}
//initialize values here
private void Init()
{
}
}
And then you can access the values like this:
//This will return the Value1 int
ExampleClass.Instance.Value1
or
//This will return the static MyValue int
ExampleClass.MyValue
From what you are asking, you can use only the Value1 from the above example and have it initialized only once in the init. If you want the value to be accessible only for read you can set it as property with "private set" operator.
The advantage of this is you dont need Start or Monobehaviour so it can work anywhere without having it in gameobjects.
Hope this helps, and happy coding!

Best way to read object from another class without code coupling

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;
}
}

How can I force a child to call a parent method?

I have a base class with a method. I want to force all children of this class to call this base method somewhere in their code.
public class BaseClass
{
public void BaseMethod()
{
//Do something
}
}
public class ChildClass1 : BaseClass
{
public void ChildMethod()
{
BaseMethod();
}
}
public class ChildClass2 : BaseClass
{
public void ChildMethod()
{
//Doesn't call BaseMethod();
}
}
So I want ChildClass1 to be fine, but I want ChildClass2 to throw an error.
The reason I want to do this is because my base class has a value that I don't want to forget to implement in my child class. For example, if I am making a bunch of enemies for a game, and the Enemy class has a speed modifier, I don't want to forget to include that in all of the children methods:
public class Enemy
{
public float x;
public float y;
private float speed;
public float GetSpeed()
{
return speed;
}
public void SetSpeed(float speed)
{
this.speed = speed;
}
}
public class Goomba : Enemy
{
public void Move()
{
x += 5 * GetSpeed();
}
}
public class Turtle: Enemy
{
public void Jump()
{
y += 5; //This is wrong. I forgot to adjust for speed.
//y += 5 * GetSpeed(); This is what I want to force myself to do
}
}
Although it is not actually for movement. This is an oversimplification. The base class contains ability modifiers, where the children class are unique abilities that use the modifiers.
How can I structure my code such that a child is required to call a specific parent method somewhere in the code?
You can use the TemplateMethod design pattern
public class BaseClass
{
public void BaseMethod()
{
DoSomething();
TemplateMethod();
}
protected abstract void TemplateMethod();
}
So you make your derived classes implement the template method, but clients of that class call the BaseMethod method. This forces the DoSomething() bit to execute but allows the derived classes to include their own logic.
So a simple example in the case of enemy (obvs adapt so it meets your needs).
public abstract class Enemy
{
public float x;
public float y;
private float speed;
public float GetSpeed()
{
return speed;
}
public void SetSpeed(float speed)
{
this.speed = speed;
}
public void Move()
{
x += GetMovementAmount() * GetSpeed();
}
public abstract decimal GetMovementAmount();
}
public class Goomba : Enemy
{
public void GetMovementAmount()
{
return 5;
}
}
public class Turtle: Enemy
{
public void GetMovementAmount()
{
return 6;
}
}
You could rearrange the code so that changing the position is possible only in base class:
public class Enemy
{
public float x { get; private set; }
public float y { get; private set; }
private float speed;
public Move(float dx, float dy)
{
x += dx * speed;
y += dy * speed;
}
}
Create a new class ability. It will allow you to control what happens when it is run and the user gets to make the run do whatever they want.
public class Ability
{
Action myAct { get; set; }
public Ability(Action inAct)
{
myAct = inAct;
}
public Run()
{
DoStuffBefore();
myAct();
DoStuffAfter();
}
}

Simplify creation of references to object members for animation purposes?

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();

Categories