Hi there I'm currently trying to optimize some code. As I'm still new to coding I try to use this opportunity to learn new "complicated" features. So now I'm stuck with delegate functions and lambda operators and don't know how to use them properly. My goal is to have a class which has one static Dictionary in which all values for different types of enemies I want for my game are stored. My current code probably works(didn't test it yet) but I don't fully understand it.
public class EnemyTypes
{
private class TypeValues
{
public delegate void Func(Transform Entity);//just used for handing over values on initialization, somehow has to be public
private string Name; //the Name of an EnemyType, NOT the name of a specific entity
private float BaseSpeed; //actual speed of each enemy is randomly set within (BaseSpeed +/- SpeedTolerance) everytime it respawns
private float SpeedTolerance;
private Func Animate;
public TypeValues(string Name, float BaseSpeed, float SpeedTolerance, Func Animate) //constructor apparently needs to be public too?
{
this.Name = Name;
this.BaseSpeed = BaseSpeed;
this.SpeedTolerance = SpeedTolerance;
this.Animate = Animate;
}
}
[SerializeField]
private static Dictionary<int, TypeValues> Types = new Dictionary<int, TypeValues>
{
{1, new TypeValues("Standard", 1f, 0.5f, Entity => Entity.Rotate(new Vector3(0, 5, 0)))}
};
}
As you can read from the comments I don't understand why the delegate and the constructor have to have the same access modifier. And why can't it be protected? Also is there a way to get rid of Func and define the delegate directly when creating the ANimate variable?
TypeValues(...) constructor can't be private or protected because you need to call it outside of the TypeValues class.
Constructor's parameters contain Func delegate, so it should be at least as visible as the constructor is. So, if constructor has to be public, then this delegate has to be public too.
You don't really need to declare your own delegate, but you can use standard System.Action<T> (documentation here). Declare your field as private Action<Transform> Animate;
Related
I have camera script class that do culling task and it contains these variables and an event :
protected float CullDetailSmall = 25.0f;
protected float CullDetailMedium = 80.0f;
protected float CullDetailLarge = 130.0f;
protected float CullDetailExtraLarge = 250.0f;
protected float CullDetailXExtraLarge = 450.0f;
protected float CullDetailXXExtaLarge = 650.0f;
public virtual void Awake(){
//culling apply logic using above variable values
}
The camera script class is the base class for CamFly and CamWalk. Now i want to change the base class camera script variable values, so I make this function in each class (CamFly and CamWalk)
public void SetCullingValues(int cullDetailSmall
, int cullDetailMedium
, int cullDetailLarge
, int cullDetailExtraLarge
, int cullDetailXExtraLarge
, int cullDetailXXExtaLarge
, int CullFloor
)
{
base.CullDetailSmall = cullDetailSmall;
base.CullDetailMedium = cullDetailMedium;
base.CullDetailLarge = cullDetailLarge;
base.CullDetailExtraLarge = cullDetailExtraLarge;
base.CullDetailXExtraLarge = cullDetailXExtraLarge;
base.CullDetailXXExtaLarge = cullDetailXXExtaLarge;
base.CullFloor = CullFloor;
base.Awake();
}
It is working fine and doing what i want but its certainly not a good piece of code. I am amzed that how can i do it correctly?? Remember
i am calling above function under some conditions, like if some
condition are matched then execute above function and change base
class variable.
second i want to this for both inherited members.
Please check the next link from Microsoft with relevant abstract class documentation and best practices.
https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/abstract
An abstract class is used as a base template for derived classes. It is used to enforce a design rule.
abstract class YourClass
{
public int a;
public abstract void A();
}
class Example : YourClass
{
public override void A()
{
Console.WriteLine("Example.A");
base.a++;
}
}
have Camera script class that do culling task and it contains these variables and an event
I see no event, I see a void returning virtual method named Awake.
It is working fine and doing what i want but its certainly not a good piece of code
What makes you think that? Yes, its improvable but I've seen far worse.
I am amzed that how can i do it correctly
Yeah, that happens to all of use sometimes...
My two cents of advice:
In general, do not expose fields directly. If the fields are subject to modification, use read/write properties. This way you can always ensure that the state of your base class remains consistent.
Name methods appropiately so the name conveys what the method does. SetCullingValues does not make it clear that the method will also call Awake. Either call it SetCullingValuesAndAwake or do not call Awake.
Why is SetCullingValues even declared in the derived types? Declare it in the base type.
1 and 3 assumes you have access to Camera. If you don't then there is not much you can do to improve what you already have.
I am making a game engine with the MonoGame Framework. Since this is a multiplayer game, other players need to know certain information about other players, such as position and velocity, typically for AI reaction.
I am about to implement Lua scripting for player actions. However, I can't currently think of a way to have it so a player cannot modify the other players' information, such as position and name.
For instance, say I have the following property in C#:
public Vector2 Pos { get { return pos; } private set { this.pos = value; } }
private Vector2 pos;
Looks good, right? Well not quite. Say I have a function that returns the closest enemy called GetNearestEnemy(), which returns another Player. Because the Player class has access to its own properties, I can just as easily do something like this in some other method:
public void DoStuff()
{
Player otherPlayer = GetNearestEnemy();
otherPlayer.Pos = new Vector2(34,151);
}
So I think "maybe I could just pass the instance as a parameter."
public void SetPos(Player instance, Vector2 pos)
{
if (instance != this)
return;
else
this.pos = pos;
}
... and always pass "this" as an argument. However, that also has the same problem: I could just as easily pass GetNearestEnemy() to the method and I'd be able to set the enemy position.
This is the type of behavior I am trying to prevent. Is there a way to preferably either:
Get the instance that called the method?
Implicitly set a parameter from the calling object without them knowing?
Or is there some other way to approach it that I'm not seeing?
Unfortunately not.
There is no language support for what you want.
Let me be specific about what you want just so that you understand what I answered.
Your question is basically this: Given that I have two instances of an object, and I have properties in this object that have a private setter, is there any language support for ensuring that instance #1 cannot change this private information of instance #2?
And the answer is no.
This will compile and "work":
public class Test
{
public void TestIt(Test t)
{
t.Value = 42;
}
public int Value
{
get;
private set;
}
}
...
var t1 = new Test();
var t2 = new Test();
t1.TestIt(t2); // will "happily" change t2.Value
Basically, the onus is on you to make sure this doesn't happen if you don't want it to happen. There is no language or runtime support to prevent this.
The access modifiers you can use are:
public: Anyone can access this
private: Only the type can access this
protected: Only the type, or a descendant of the type, can access this
internal: Any type in the same assembly can access this
internal protected: Any type in the same assembly or a descendant, can access this
Other than this, you have no other options. So "only the same instance can access this" does not exist as an access modifier.
If this is the property and you are worried about being set from elsewhere:
public Vector2 Pos { get { return pos; } private set { this.pos = value; } }
private Vector2 pos;
This will NOT work. So you do not need to worry:
Player otherPlayer = GetNearestEnemy();
otherPlayer.Pos = new Vector2(34,151); // <--- no this will not work
That property can only be set from within the class.
That won't work. If Pos is a property with a private setter (as it is) the only way they could change it would be by calling a public method from within otherPlayer. Something like otherPlayer.SetPos(new Vector2(34,151)), where SetPos() is:
public void SetPos(Vector2 NewPos)
{ Pos = NewPos; }
The original scenario posted can be handled using an interface e.g. IPeerPlayer that only exposes what other players should see and hides other properties (i.e. the other properties would not be in the IPeerPlayer interface.)
Programming in C# in Unity requires tremendous amounts of boiler-plate. This is partly due to C#, but also due to design decisions in the engine itself.
The fact that I cannot construct MonoBehaviours myself means I need to write code as the following to enforce correct initialization:
using System;
using System.Collections.Generic;
using UnityEngine;
public class MyClass : MonoBehaviour
{
private int a;
private float b;
private string c;
private List<int> lst;
public static MyClass Construct (int a, float b, string c,List<int> lst)
{
//Boiler-plate stuff
var go = new GameObject ();
var mc = go.AddComponent<MyClass> ();
/*
* This part is fugly. The static method is setting
* fields on the object. The responsibility to be
* fully initialized after construction should
* lie on the object.
* I could easily forget to set fields from the
* outside.
*/
mc.a = a;
mc.b = b;
mc.c = c;
mc.lst = lst;
return mc;
}
//Same as above, but this time without constructing a new GameObject.
public static MyClass AddTo (GameObject go,int a, float b, string c,List<int> lst)
{
var mc = go.AddComponent<MyClass> ();
mc.a = a;
mc.b = b;
mc.c = c;
mc.lst = lst;
return mc;
}
}
Is there a way to create a code-snippet for this in Xamarin studio to reduce boiler-plate, or any other fancy tricks to automate the process of writing these functions?
My unfinished attempt currently looks like this with Xamarin editor-templates:
public static $classname$ Construct(){
}
Where $classname$ calls a function to get the name of current class. I don't think it's actually possible to list the identifiers of the class in the function header.
Just to pre-empt people: I know it is possible to create classes that don't derive from MonoBehaviour, but let's assume that this class actually needs the functionality of a GameObject.
I guess what you are looking for some factory pattern.
Depending on the context, I have 3 suggestions:
1 Prefabs
Avoid boiler plate code, that's why is so common to use prefabs and instantiate them. It's the prototype pattern. Declare a set of serialized properties and instantiate a clone of the current prototype (that's what you are trying to do by code).
2 Initialize in Awake
If your objects are always initialized with a defined set of value, initialize them in Awake rather than in constructors.
If they're not , well every component should in any case provide the relevant constructors overloads(as init method, since you cannot rely on constructor), or be wrapped inside a factory.
3 Use lambda
If you still prefer, or for some reasons need to, to stick with a procedural object creation, you can avoid declare methods for every class and simply pass an responsible for initializing the object. Something like:
public class Test : MonoBehaviour {
public int foobar;
}
public static T CreateAndAttach<T>(Action<T> init)
where T : MonoBehaviour
{
GameObject go = new GameObject();
T t = go.AddComponent<T>();
init(t);
return t;
}
//usage
CreateAndAttach<Test>(t => { t.foobar = 10; });
The fact that I cannot construct MonoBehaviours myself means I need to
write code as the following to enforce correct initialization
The fact is that MonoBehaviours are C# wrappers for component that resides in the C++ side of the engine, and it's the engine that owns their life time. They are de facto resources you ask for and possibly release (like other resources such as textures, meshes,..).
OK, I know why we don't use constructors on monobehaviors in Unity. For nearly all of the use cases, Start and Awake fit perfectly. Usually.
However, there's a great C# feature that only can be used with constructors — readonly fields. In my particular situation, I work on a project with a lot of developers and write an abstract MonoBehavior that will be subclassed and rewritten a lot of times by a lot of different people. And I want a field to act like constant throughout object's lifetime (or it WILL introduce strange, hard-detectable bugs) but with different values in different subclasses — in other words, a classic use-case for a readonly field. (I don't want to use properties because they have no language-enforce obligation of staying the same.)
So — can I safely use MonoBehavior's constructors? Won't some strange dragon come out of the lair somewhere down the road? What should I know if I choose to use them?
I think the main reasons Unity wants you to stay away from using the constructor is that the constructor isn't called on the main thread, and the constructor is called before serialized data is restored to the object.
So if the readonly fields you're setting in the constructor depend on data from serialized fields, then they won't work right. And if they don't then you can just assign them at initialization.
You could also use a container object to keep your readonly values, but there's nothing stopping someone else from re-assigning that container later.
using UnityEngine;
using System.Collections;
public class ReadOnlyTest : MonoBehaviour {
public string part1 = "alpha"; // change these values in the editor and
public string part2 = "beta"; // see the output of the readonly variable "combined"
public readonly string combined;
// just assign to readonly vars.
public readonly string guid = System.Guid.NewGuid().ToString();
public readonly float readOnlyFloat = 2.0f;
public class ReadOnlyContainer {
public readonly int readOnlyInt;
public readonly float readOnlyFloat;
public readonly string readOnlyString;
public ReadOnlyContainer(int _int, float _flt, string _str) {
readOnlyInt = _int;
readOnlyFloat = _flt;
readOnlyString = _str;
}
public override string ToString() {
return string.Format("int:{0} float:{1} string:{2}", readOnlyInt, readOnlyFloat, readOnlyString);
}
}
public ReadOnlyTest() {
combined = part1 + part2;
}
public ReadOnlyContainer container;
void Awake() {
if (container == null) {
container = new ReadOnlyContainer(Random.Range(-100,100), Time.realtimeSinceStartup, System.Guid.NewGuid().ToString());
}
}
void Start () {
Debug.Log(container.ToString());
Debug.Log("combine1: " + combined);
Debug.Log("guid: " + guid);
}
}
Many unity classes are created by reflection, and there's no way for unity to non-default constructors properly; hence the limitation.
#Calvin's answer points out one very good option: create classes that are not derived from MonoBehaviour; these can have constructors like any other C#. You can put those classes into fields in MonoBehaviours as long as your code can tolerate missing instances. If you use the typical quasi-singleton pattern from #Calvin's answer you'll always get an instance when you need one, and you can push the 'give me an instance the first time' logic into a method that can be overridden in derived classes to customize behavior.
If you want constant-like behavior, with the option of different values in derived classes it may be easier to define a method rather than a field. The method is effectively read-only, and it has more predictable mutations as per #Jerdak's answer.
If you must have constructors, the last option is to use the monobehavior as a minimal placeholder and write all of the interesting stuff in a class of your own, then delegate all of the work in the Monobehavior to your class.
using UnityEngine;
using System.Collections;
public class OuterPlaceholder: MonoBehaviour {
public InnerBehavior _Inner;
public void Awake() {
if (_Inner == null) {
_Inner= new InnerBehavior(4);
}
}
public void Update()
{
_Inner.DoUpdate(this);
}
}
public class InnerBehavior
{
public readonly int UpConstant;
public InnerBehavior (int up)
{
UpConstant = up;
}
public void DoUpdate(MonoBehaviour owner)
{
owner.transform.Translate(Vector3.up * UpConstant * Time.deltaTime);
}
}
This option may work best if you are sure you're going to get a lot of complex inheritance as the project evolves.
Finally: It's perfectly OK to name the field _ReadOnlyField or _DoNotWrite or whatever to tell users not to muck with it. All Python programmers live with the possibility of somebody doing far worse things and it seems to work out fine most of the time :)
From the script refs:
If you attempt to define a constructor for a script component, it will
interfere with the normal operation of Unity and can cause major
problems with the project.
MonoBehaviours are constructed many times during serialization, something Unity does quite frequently in the editor and I suspect there is a lot more going on the hood to hook the C layer to C#. Ultimately the behavior is undefined so it's best not to try.
Regarding "but with different values in different subclasses", from MSDN:
assignments to the fields introduced by the declaration [readonly] can only occur as part of the declaration or in a constructor in the same class.
So no modification in derived classes.
I'd like to create a class that has overrideable methods in the form of delegates.
I basically would like to create an interface, but not have to create a new class every time I want to make it slightly different.
Further, I would like to bundle the delegate with a number of other variables in a struct.
Now here are some more specifics.
class Gun
{
public delegate void ShootDelegate;
// There are more variables, I'm just using this one as an example
public double fireRate;
public Gun(GunStats stats)
{
this.Shoot = stats.Shoot;
this.fireRate = stats.fireRate;
}
public ShootDelegate Shoot;
}
struct GunStats
{
public ShootDelegate Shoot;
public double fireRate;
}
then, what I'd like to be able to do is make a gun like this
GunStats stats;
stats.fireRate = 3;
stats.Shoot = new delegate() { this.fireRate++; /* stupid example */ };
new Gun(stats);
however, when I create the delegate, it obviously can't interact with the inner class variables.
What's the best way to handle this?
You can pass a reference to a Gun object in the delegate.
Change delegate to:
public delegate void ShootDelegate(Gun g);
Then you can do this:
GunStats stats;
Gun g = new Gun(stats);
stats.fireRate = 3;
stats.Shoot = new delegate(g) { g.fireRate++; };