Template for component construction in Unity with C# - c#

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,..).

Related

Unity 2D - access to variables of GetComponent<T> sent as param

I have this script for saving my character. I have lot of NPCs and each NPC has its own script. I want to use method SaveCharacter for saving every NPC. How can I send g.GetComponent<Warrior_Movement>() as a parameter and get access to its variables? When I use <T>, I can't get variables of gameobject's script. Thanks
void SaveCharacter(Character character, string gameObjectName)
{
GameObject g = GameObject.Find(gameObjectName);
character.position = new float[] { g.transform.position.x, g.transform.position.y, g.transform.position.z };
character.selectedScheme = g.GetComponent<Warrior_Movement>().selectedScheme;
character.currentWaypointIndex = g.GetComponent<Warrior_Movement>().currentWaypointIndex;
character.nextWaypointIndex = g.GetComponent<Warrior_Movement>().nextWaypointIndex;
character.loopSide = g.GetComponent<Warrior_Movement>().loopSide;
}
Problem
You can NOT use a variable for passing it into the generic version of GetComponemt like
public void DoSomething(Type componemtType)
{
var component = GetComponent<componentType>();
}
since the types used for implementing the generics have to be compile time constant and therefor can not be a variable (or only one that is compile time constant)!
You could use the non-generic version of GetComponent like
public void DoSomething(Type componentType)
{
var component = GetComponent(componentType);
}
but than you would have to parse it in order to have access to any fields or methods that are specific for that component:
var parsedComponent = component as componentType;
So again you can NOT do this since the type used for as also has to be compile time constant and therefor can not be a variable.
Solution 1: Shared Base class
In the case all your different classes have common fields you want to save, they should all inherit from a common base type like e.g.
// By making a class abstract it can not be instanced itself but only be implemented by subclasses
public abstract class BaseMovement : MonoBehaviour
{
// fields that will be inherited by subclasses
public int currentWaypointIndex;
public int nextWaypointIndex;
//...
// You could also have some generic methods that are implemented
// only in the subclasses like e.g. Getters for the values
// you want to access
public abstract string SaySomething();
}
And than inherit your classes from that like e.g.
public class Warrior_Movement : BaseMovement
{
// Inherits all fields of BaseMovement
//... additional type specific stuff
// If you have abstract methods in the base class
// every subclass has to implement all of them
public override string SaySomething()
{
return "Harr harr, I'm a warrior!";
}
}
public class Other_Movement : BaseMovement
{
// Inherits all fields of BaseMovement
// Additional type specific stuff
// If you have abstract methods in the base class
// every subclass has to implement all of them
public override string SaySomething ()
{
return "Harr harr, I'm ... something else :'D ";
}
}
Than you can use something like
void SaveCharacter(Character character, BaseMovent bMovement)
{
character.position = new float[] { bMovement.transform.position.x, bMovement.transform.position.y, bMovement.transform.position.z };
character.currentWaypointIndex = bMovement.currentWaypointIndex;
character.nextWaypointIndex = bMovement.nextWaypointIndex;
}
and call it like
GameObject g = GameObject.Find(gameObjectName);
var movement = g.GetComponemt<BaseMovement>();
SaveCharacter(someCharacter, movement);
Solution 2: Overloads
Alternatively if you use different values for different components than don't use a shared base class but instead create overloads of SaveCharacter like
public void SaveCharacter(Character character, Warrior_Movement wMovement)
{
// Do stuff with wMovement
// ...
}
public void SaveCharacter (Character character, Other_Movement oMovement)
{
// Do stuff with oMovement
// ...
}
so the wheneever you use SaveCharacter the types you pass in will decide which implementation of SaveCharacter should be used.
To
When I use , I can't get variables of gameobject's script.
I don't know what you mean exactly but you can access the GameObject the component is attached to by using gameObject e.g.
bMovement.gameObject.SetActive(true);
Note:
If somehow possible you should avoid using Find since it is quite performance intense. Try to get the reference as soon as possible e.g. either by referencing it in the Inspector using a public GameObject field or if it is Instantiated save it to a variable like
var warrior = Instantiate (/*...*/);
and pass it around.

C# - make it so only the same instance can modify its properties/call methods?

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.)

C#/AS3 How do I create a public global data object that any other object can read, but only certain objects can set?

Here is the conundrum. I have a specific set of state variables that are used in almost every supporting object I have, and I want those variables to be able to be read by any object that needs to read them, but I want to protect them so that only 1 object has the ability to set them.
For example, lets say I am making a poker game. Variables like:
- Minimum Ante
- Maximum Bet
- Maximum Number of Players
- Current GameState (Placing Bets, Shuffling, Dealing, Paying, etc.)
Personally, I prefer small compact component classes, so lets say I have the majority of the poker game logic in 1 controller class, but i have 50 supporting objects that handle everything that isn't the poker game logic itself, such as a PlayerInterface, a graphics controller, 'The Deck' to handle shuffle and deal logic, etc. Alot of my smaller support classes need to see what the minimum ante is, and the current method I am using is for the controller class to pass these variables into the supporting classes as parameters.
The obvious downside to this is I have 50 supporting objects all holding on to their own local variables for minimum ante to hold the same information that I am passing to them from the controller. Wasted parameters, memory, and opens a ton of risk if any of those variables ever get out of sync.
So, how to I make these variables global so everyone can access and read them? The knee jerk reactionary answer is some public static variables, however this presents the problem that anyone could also write to them. Not only do I not want my supporting objects having the power to change the minimum ante without the controller's knowledge, but I also don't want the client shell that holds the poker game to be able to change them without first going through the proper checks contained in the controller.
So what do I do? Someone once mentioned to me the idea of a Singleton, but after plenty of research, most of it a few years old or more, I found about a 50/50 split in the community who say Singletons are a good idea vs those who think they aren't.
If not singletons or statics, then what? I am open to any ideas to research and try out.
Remember, I want any object, anytime, anywhere to be able to GET the data it needs, but only a very specific object to have the ability to SET the data, should it need to change, so that it can filter through the proper checks. By proper checks, I mean for example in the poker game, if a player has the ability to change the Minimum Bet on the table, he should only be able to do so between hands, or before a tournament begins. I don't want him messing with these things during play.
Thanks in advance for any input.
You could use interfaces approach here.
Declare two interfaces as
public interface IReadOnlyAccess
{
int Property{get;}
}
public interface IFullAccess
{
int Property{get;set;}
}
Then your class would implement both interfaces like
public interface MyClass: IReadOnlyAccess, IFullAccess
{
public int Property{get;set;}
}
Then wherever you need full access you get it via IFullAccess, if otherwise - via IReadOnlyAccess.
Make an inner class, it will have access to the main classes private vars:
public class OuterClass
{
public string StringProperty { get; private set; }
public InnerClass CreateInnerClass()
{
InnerClass ic = new InnerClass(this);
return ic;
}
public class InnerClass
{
private OuterClass _outer;
public InnerClass(OuterClass oc)
{
_outer = oc;
}
public string Prop
{
get
{
return _outer.StringProperty ;
}
set
{
_outer.StringProperty = value;
}
}
}
}
So create the main class that most people have readonly access:
var oc = new OuterClass();
oc.StringProperty = "123"; <-- not allowed, is `readonly`
To write to properties, create inner class instance:
var oc = new OuterClass();
var ic = oc.CreateInnerClass();
ic.StringProperty = "123";
Seems like the cleanest, easiest solution is to have everything done in your controller class.
Let's say something like this:
AS3:
//adding the final keyword, locks this class so others can't extent/inherit from it
public final class MyController {
//create a privately scoped var (it can only be accessed in this class)
private var minBet:Number = 0;
//create a public getter that can be read by any class/object
public function get minimumBet():Number {
return minBet;
}
private function set minimumBet(value:Number):void {
//do you checks etc
minBet = value;
}
}
C#
//sealed in C# is the same as final in AS3
public sealed class MyController
{
private float minBet = 0;
public float minimumBet
{
get { return minBet; }
}
}
instanceOfMyController.minBet //will throw an error
instanceOfMyController.minimumBet = 10; //will throw an error
instanceOfMyController.minimumBet //will supply the value of the minBet var
If you're doing a lot cross-language code, consider checking out something like Haxe which can compile out to AS3 or C# with the same code.

Accessing a property of a subclass with an array of the base class

I am writing a game in Unity, and have come across an issue with accessing a subclass property.
I have a base class called "Component" that is only used to group together all the subclasses that inherit it. I have a "Track" class that inherits from Component that has some public properties.
public class Track : Component {
public int x;
public int y;
}
Another class keeps an array of Components and makes changes to them.
public class Example: MonoBehaviour {
private Component[] components = new Component[10];
void Start () {
components[0] = new Track();
components[0].x = 5; //Does not compile
}
}
I am unsure of how to access the properties in Track with an array of the base class Component. I appreciate any help anyone can provide. Thanks!
If you're sure it's a Track, you could cast it to that type:
components[0] = new Track();
((Track)components[0]).x = 5;
In this case, you're sure it's a Track because you just instantiated it.
But if it's possible other classes could also inherit from Component, and that your components collection may not have instances of Track, you'll want to check first before doing the assignment.
var track = components[0] as Track;
if (track != null)
track.x = 5;

Using constructors of monobehaviors

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.

Categories