I am trying to make use of the MVC Pattern in Unity. I am a programming beginner.
Traps and moving Platforms use the same code so i created a base for them. I divide the code into "Data"-class and "Method"-class.
Both objects move to Point A, then to Point B, back to Point A and so on..
Point A and Point B got a trigger, to change the Movementdirection of the Platform/Trap.
The base class holds the data. The subclass gets the data and fills the base data. In the base class i have the object:
public virtual GameObject MovingObject { get { return null; } }
The subclass overrides the property returning null to make it return the right object. I try it this way:
[SerializeField]
private GameObject movingObject;
public override GameObject MovingObject { get { return movingObject; } }
The private variable is set in the Editor and sets the value to the property. This property gives the information to the base class. The problem is that i get null references and I do not know how to fix that. The base class does not return an object. The information get lost on their way to the base...
Is my logic wrong?
If you need to see the whole structure of these six classes you can look it up on
https://github.com/Garzec/MidnightFeast/tree/master/Assets/Scripts/MovingObjects
Sorry, i did not want to post all lines of code and unrelevant stuff :)
I looked at your code. Assuming you will never need an instance of just a "MovingObjectsController" this looks like you need an abstract class as your base class. An abstract class cannot be instantiated, but it can require a child class (subclass) to implement abstract members, removing the need to return null in the parent. For example, you would define your controller as :
public abstract class MovingObjectsController
{
protected abstract MovingObjectsData Data { get; }
}
public class PlatformController : MovingObjectsController
{
private MovingObjectsData data;
public PlatformController()
{
this.data = new MovingObjectsData(); //This being whatever data is specific to this object
}
protected override MovingObjectsData Data {
get
{
return data;
}
}
}
This way the child is required to implement whatever the parent needs, but the parent isn't required to provide a default implementation that doesn't make sense.
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 don't really know how to formulate my issue it's a bit complicated for me, i'll try my best to explain.
I'm making a space game, i have a base class which represent places, and i want to have different type of places like planets, space stations, asteroïds, trading ships etc. The player can click on those objects and get informations.
So my classes looks like something like this:
public class Place {
public int placeId;
public string placeName;
public string placeDescription;
/* Place constructor */
}
public class Planet : Place {
/* Specific proprieties of planet */
public PlanetType planetType;
public int planetSize;
...
// Planet constructor
public Planet(int placeId, string placeName, string placeDescription, PlanetType planetType, int planetSize) : base(placeId, placeName, placeDescription) {
this.planetType = planetType;
this.planetSize = planetSize;
...
}
}
And i have a delegate which accept a function like selectPlace with Place in parameters because i don't want to make a delegate for each type of Place i have.
In another script which is supposed to show the information of any kind of Place, i recieves the Place object that the player clicked on. I think i found a solution, however is this correct to do something like this ?
private void updateSelectedPlaceUI(object sender, EventsController.PlaceEventArgs placeArgs){
// This is just a test, i should check which type of subclass it is before
Planet planetTest = placeArgs.Place as Planet; // So now i can use planetTest.planetType
}
And placing this in a switch case so i can handle any type. I just want to be able to get the proprieties from any derived class of Place in order to display them in UI. I would like to know a better way to achieve this.
But i'm wondering if my design is ok and necessary, it has been a while since i haven't used inheritance / polymorphism, and i feel like i'm doing it the wrong way.
I would propably make the UI part of showing the properties a specific place generic to accept something like a PropertyItem, you can decide the properties yourself.
public class PropertyItem
{
public string Text { get; set; }
public object Value { get; set; }
}
And then in your select method you would just call the abstract method of your base class (make your base class abstract as well)
public abstract class Place
{
...
public abstract IEnumerable<PropertyItem> GetProperties();
}
And now you can override this in your Planet
public class Planet : Place
{
...
public override IEnumerable<PropertyItem> GetProperties()
{
yield return new PropertyItem { Text = "Size", Value = this.planetSize };
}
}
And eventually you would use the GetProperties() method to get the properties of your place and show them in a tabular or what ever format your UI knows how to handle the PropertyItem type.
private void updateSelectedPlaceUI(object sender, EventsController.PlaceEventArgs placeArgs)
{
MyUserInterfaceWidget.DisplayProperties(placeArgs.Place.GetProperties());
}
Forgive me because I know my wording is terrible. I'll just give an example.
public class MainClass{
public int someVariable;
public List<HasAClass> cList = new List<HasAClass>();
addHasAClass(HasAClass c){
cList.Add(c);
}
}
public class HasAClass{
public HasAClass(){
//Modify someVariable in some way????
}
}
public class HasASubClass : HasAClass{
public ComposedClass(){
//Modify someVariable in some way???
}
}
I having trouble finding the right words for this questions but here is what I am trying to do:
I am creating an aid for an RPG similar to dungeons and dragons. Each character can have a variety of special abilitys which can effect the characters in some way (both negative and positive). I am trying do this with a variety of subclasses which store the pertinent info and get added to the character at varying points in time. What I can't figure out is how to modify the properties of the Character(I called it Main Class in my example) when instances of the HasA class are added to it.
The HasAClass needs a reference to the owning instance, so that it can ask the parent for values and update them when required...
public class HasAClass
{
private MainClass _mainClass;
public HasAClass(MainClass mainClass)
{
_mainClass = mainClass;
_mainClass.someVaraible = 42;
}
}
You then need to pass the owner reference into the constructor of the HasAClass when they are created. If this is not possible at the time of creating the instance then you would instead need to assign it as a property after it has been created. Such as inside the addHasAClass method.
I have two classes that I'd like to keep in separate files.
namespace GridSystem
{
public class Grid
{
public void AddItem(GridItem item)
{
item.InformAddedToGrid();
}
}
}
namespace GridSystem
{
public class GridItem
{
public void InformAddedToGrid()
{
Debug.Log("I've been added to the grid");
}
}
}
How do I ensure no other classes are allowed to call InformAddedToGrid?
I'm trying to emulate Actionscript namespaces, which can be used on a method, in place of public, private, internal, etc. It doesn't exactly protect the method, but forces an extra step of including the namespace before the method can be accessed. Is there an alternative approach to this in C#?
If GridItem itself can be hidden from the outside world as well I would consider putting GridItem inside Grid as a nested class. That way it won't be visible outside of the class
http://www.codeproject.com/Articles/20628/A-Tutorial-on-Nested-Classes-in-C
Not that you should do this, you should do what TGH suggests, have a public interface for GridItem, and have gridItem nested in Grid (then have a factory method on Grid to create Items and use partial Grid class to have them in separate files).
Because there isn't a way of having friend methods ( you can do friend classes through InternalsVisibleToAttribute )
You COULD do this ( but don't... )
public partial class Grid
{
public void AddItem(GridItem item)
{
item.InformAddedToGrid();
}
}
public class GridItem
{
public void InformAddedToGrid()
{
if (new StackTrace().GetFrame(1).GetMethod().DeclaringType !=
typeof(Grid)) throw new Exception("Tantrum!");
Console.WriteLine("Grid called in...");
}
}
then
var g = new Grid();
g.AddItem(new GridItem()); // works
new GridItem().InformAddedToGrid(); // throws a tantrum...
A really ugly answer would be to make it private and use reflection.
Another ugly answer would be to make it throw an exception if the caller is wrong.
Both of these are much slower to execute than a normal call also.
I don't think there's a good answer. C# doesn't have friends.
IMHO the answer is simple: access modifiers are just there to remind the programmer of the intent of how public/private a class should be. Through reflection you can lift those barriers.
The usage you make of a class is all in your hands: if your class is meant to only be used in one place, make it so. If anything, if a class has a special way of being used, document it - put it in the XML comments.
That said, in this specific example I'd believe since the GridItem doesn't add itself to the grid, it's not its job to notify about it (what if "I've not been added to the grid"?). I think InformAddedToGrid belongs somewhere in your Grid class as a private method, where there's a concept of adding an item... assuming that's what AddItem(GridItem) really does.
You can do it as TGH suggested, with nested classes, except the other way around. Nest Grid within GridItem and make InformAddedToGrid private. Here I use a nested base class so the public API can remain the same. Note that no one outside of your assembly can inherit from GridBase because the constructor is internal.
public class GridItem
{
public class GridBase
{
internal GridBase() { }
public void AddItem(GridItem item)
{
item.InformAddedToGrid();
}
}
private void InformAddedToGrid()
{
Debug.Log("I've been added to the grid");
}
}
public class Grid : GridItem.GridBase { }
Another option is to have GridItem explicitly implement an internal interface. This way no one outside of your assembly can use the interface by name and therefore cannot call InformAddedToGrid.
public class Grid
{
public void AddItem(GridItem item)
{
((IGridInformer)item).InformAddedToGrid();
}
}
public class GridItem : IGridInformer
{
void IGridInformer.InformAddedToGrid()
{
Debug.Log("I've been added to the grid");
}
}
internal interface IGridInformer
{
void InformAddedToGrid();
}
I have some problems cloning an object hierarchie. It's a toolkit for modelling applications, the toolbox contains class instances as prototypes. But I'm having a hard time cloning these :)
The following code shows the problem:
public abstract class Shape {
protected List<UIElement> elements;
private Canvas canvas;
...
public Canvas getCanvas() { ... };
}
public class MovableShape : Shape {
protected ... propertyA;
private ... propertyXY;
...
}
public abstract class AbstractLayout : MovableShape, ... {
...
}
public class SomeLayoutClass : AbstractLayout, ... {
...
}
public class AContainingClass {
SomeLayoutClass Layout { get; set; }
...
}
When I insert an object of AContainingClass into my project worksheet, it should be cloned. So far I tried manual cloning (which fails because of the private fields in the base classes) and binary serialization (BinaryFormatter and MemoryStreams).
The first approach lacks a way to call the base.clone() method (or am I wrong?), the latter does not work because UIElements aren't [Serializable].
Note: it must be a deep copy!
Any ideas? Thanks!
UPDATE
Just to clarify my manual cloning approach:
If each class has it's own Clone method, how to call the Clone method of the base class?
public class Shape { // not abstract any more
...
public Shape Clone() {
Shape clone = new Shape() { PropertyA = this.PropertyA, ... };
...do some XamlWriter things to clone UIElements...
return clone;
}
}
public class MovableShape : Shape {
...
public MovableShape Clone() {
// how to call base.Clone???
// this would be required because I have no access to the private fields!
}
}
And here the function for it:
public T XamlClone<T>(T source)
{
string savedObject = System.Windows.Markup.XamlWriter.Save(source);
// Load the XamlObject
StringReader stringReader = new StringReader(savedObject);
System.Xml.XmlReader xmlReader = System.Xml.XmlReader.Create(stringReader);
T target = (T)System.Windows.Markup.XamlReader.Load(xmlReader);
return target;
}
If you are attempting to clone UIElements, use the XamlWriter to save to a string, though no method of cloning is foolproof. You then use XamlReader to load a copy. You could still run into issues. Things like handlers not being copied, x:Name being duplicated, etc. But for simple elements like Grid or Brush, it works great.
Edit 1: There is no generic way to clone anything, however:
1) If a clone function is written correctly, it will call the base Clone for you, and copy the base class stuff, too. If it isn't written correctly calling the base Clone won't help much, though you can call a private method this way.
2) If you have to, you can use Reflection to copy pretty much anything, even click handlers, from an old object to a new object.
3) XamlWriter and XamlReader will copy and instantiate heirarchies of objects, just minus certain properties.
Edit 2: Here's a common cloning design pattern I use in my class hierarchies. Assume base class shape, derived class circle:
protected Circle(Circle t)
{
CopyFrom(t);
}
public override object Clone()
{
return new Circle(this);
}
protected void CopyFrom(Circle t)
{
// Ensure we have something to copy which is also not a self-reference
if (t == null || object.ReferenceEquals(t, this))
return;
// Base
base.CopyFrom((Shape)t);
// Derived
Diameter = t.Diameter;
}
Haven't tried it myself, but XamlWriter looks promising.