Getting adjacent objects to interact [C#] - c#

I'm doing a basic game in C#, and I'm running up on a problem I can't solve. Here's the (relevant) code:
public class GameManager
{
public GameMap MainMap;
public EntityManager GameWorld;
public SystemManager GameSystems;
public GameManager()
{
EntityManager GameWorld = new EntityManager();
SystemManager GameSystems = new SystemManager();
GameMap MainMap = new GameMap(61, 41);
}
public void InputHandler(string Trigger)
{
switch (Trigger)
{
case "north":
GameSystems.Move(GameWorld, MainMap, 0, 8);
break;
//etc
}
}
}
public class SystemManager
{
public rkcPosition _position;
public SystemManager()
{
}
public bool Move(EntityManager TargetWorld, GameMap TargetMap, int TargetID, int TargetDirection)
{
rkcPosition _position = TargetWorld.GetPosition(TargetID);
// here, GetPosition returns an instance of rkcPosition
// pulled from a List<rkcPosition> - this seems to be the problem point
}
}
The problem I'm getting is with the part where I try to call GameSystems.Move - it jumps to highlight the last line of the code I included (w/rkcPosition) and gives a null ref exception. (rkcPosition is a class I've not included in this code snippet)
I'm trying to have the Move function perform some changes to values within the GameWorld and MainMap objects. I'm beginning to think I'm doing this all wrong, so...
If I want to run a method on my existing instances "GameWorld" and "GameSystems" from the InputHandler function, how would I do this properly?

Like Sami Kuhmonen said, the problem in your code is that you are constantly passing around and reassigning your objects that are essentially supposed to be global. Not only does this require that you pass them as parameters to anything that would need them, it is also incredibly error-prone (as you have discovered).
Instead of having these objects behave like instance objects, utilize the Singleton design.
What this means is that instead of instance members, these objects are static members that represent a single global object for everything else to access.
public class GameManager
{
public static GameMap MainMap;
public static EntityManager GameWorld;
public static SystemManager GameSystems;
static GameManager()
{
GameWorld = new EntityManager();
GameSystems = new SystemManager();
MainMap = new GameMap(61, 41);
}
//...
}
Now in your other classes, instead of having to worry if you are passing around the correct object, simply reference these singletons from the GameManager.
public class SystemManager
{
public rkcPosition _position;
//...
public bool Move(int TargetID, int TargetDirection)
{
rkcPosition _position = GameManager.MainMap.GetPosition(TargetID);
}
}

You are constantly redefining variables inside methods that override the member variables. As your debugger shows the GameWorld, MainMap etc are null and you're trying to use them. I don't know how it even goes to Move() since the member variable GameSystems will also be null.
Remove the definitions of the variables inside the methods, that way you're actually storing the objects somewhere and not throwing them away immediately after the method is over. For example:
public GameManager()
{
GameWorld = new EntityManager();
GameSystems = new SystemManager();
MainMap = new GameMap(61, 41);
}

Related

C# Unity > Static instance member not causing constructor to be called

I have noticed a rather weird behaviour in my application I am creating;
I have a class I defined that has a static "instance" variable of the class type.
I would assume that (as per code attached) the constructor would be called.
Alas, it is not, unless I use the Void.get in a non-static field anywhere in my code.
public class Void : TilePrototype {
public static Tile get = new Tile((int)TileEntities.Void);
public static Void instance = new Void();
public Void() {
Debug.Log("created");
id = (int)TileEntities.Void;
isBlocking = true;
register();
}
public override RenderTile render(Tile tile){
return new RenderTile(0, new Color(0, 0, 0, 0));
}
So when I have something like :
public static TileStack empty = new TileStack(Void.get, Void.get);
the Void class constructor never gets called. But, if I have:
Tile t = Void.get;
Anywhere in my code it will be called.
Why?
Thanks.
This is a really really subtle and nuanced area of C#; basically, you've stumbled into "beforefieldinit" and the difference between a static constructor and a type initializer. You can reasonably ask "when does a static constructor run?", and MSDN will tell you:
It is called automatically before the first instance is created or any static members are referenced.
Except... public static TileStack empty = new TileStack(Void.get, Void.get); isn't a static constructor! It is a static field initializer. And that has different rules, which basically are "I'll run when I must, no later, possibly sooner". To illustrate with an example: the following will not (probably) run your code, because it doesn't have to - there isn't anything demanding the field:
class Program
{
static void Main()
{
GC.KeepAlive(new Foo());
}
}
public class Foo
{
public static TileStack empty = new TileStack(Void.get, Void.get);
}
However, if we make a tiny tweak:
public class Foo
{
public static TileStack empty = new TileStack(Void.get, Void.get);
static Foo() { } // <=== added this
}
Now it has a static constructor, so it must obey the "before the first instance is created" part, which means it needs to also run the static field initializers, and so on and so on.
Without this, the static field initializer can be deferred until something touches the static fields. If any of your code actually touches empty, then it will run the static field initializer, and the instance will be created. Meaning: this would also have this effect:
class Program
{
static void Main()
{
GC.KeepAlive(Foo.empty);
}
}
public class Foo
{
public static TileStack empty = new TileStack(Void.get, Void.get);
}
This ability to defer execution of the static initialization until the static fields are actually touched is called "beforefieldinit", and it is enabled if a type has a static field initializer but no static constructor. If "beforefieldinit" isn't enabled, then the "before the first instance is created or any static members are referenced" logic applies.
Thanks to Marc Gravell's aswer I came up with this contraption (and admittedly I do like the new solution more than the old one, so thanks again!)
Modifications done to the Void class:
public class Void : TilePrototype {
public static Void instance = new Void();
public static Tile get {
get {
return new Tile(instance.id);
}
}
public Void() {
isBlocking = true;
}
public override RenderTile render(Tile tile){
return new RenderTile(0, new Color(0, 0, 0, 0));
}
}
So as You can see I made the "get" variable a property, so that it's evaluated later, when you actually need the tile, not on construction.
I've changed all "get"s this way.
Second change is in the TilePrototype:
public class TilePrototype {
public static Dictionary<int, TilePrototype> tilePrototypeDictionary = new Dictionary<int, TilePrototype>();
public static void registerPrototype(int id, TilePrototype tp){
tp.id = id;
tilePrototypeDictionary.Add(id, tp);
}
public static bool registered = false;
public static void registerAll(){
if( registered ) return;
registerPrototype(0, Void.instance);
registerPrototype(1, Air.instance);
registerPrototype(2, Floor.instance);
registerPrototype(3, Wall.instance);
(...)
Here I've added the registerPrototype and registerAll functions.
This gives me easy access to all the registered type ids (by say Wall.instance.id) as well as the other way around (from id to instance via the Dictionary)
I also have all registered things in one place, with the possibility of runtime adding more
Overall, much neater, and here I assure that all tiles are registered properly and assigned proper IDs.
Change of ID is simple and in one place and everywhere else, access to this ID is done via a short .instance.id
Thanks again for the help :)

Getting null errors even though Im using the variable

I'm trying to learn MonoGame and I'm trying to do basic stuff and I've figured most of it out on my own but I'm getting a null pointer and I'm not sure why. I'm trying to get MainMenuScene to just draw a texture but in SceneManager currentScene keeps giving me null pointers and I have no idea why. Ill post my SceneManager code but the rest will be on github. Its not much code so it shouldnt take long if you'd look over it. I'm super confused and I'm not sure what to google to try to figure it out myself.
https://github.com/eatmykhack/MonoGame.git
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Tutorial.Scenes;
class SceneManager
{
private static SceneManager instance = new SceneManager();
Scene currentScene, newScene;
Dictionary<string, Scene> sceneDirectory =new Dictionary<string, Scene>();
public static SceneManager getInstance()
{
return instance;
}
public static Scene getCurrentScene()
{
return instance.currentScene;
}
public static void changeScene(Scene scene)
{
}
public static void addScene(string sceneName)
{
instance.newScene = instance.sceneDirectory[sceneName];
}
public void update() { currentScene.Update(); }
public void draw(SpriteBatch spriteBatch) { currentScene.Draw(spriteBatch); }
public void Initialize()
{
instance.sceneDirectory["MainMenuScene"] = new MainMenuScene();
instance.currentScene = instance.sceneDirectory["MainMenuScene"];
}
public void LoadContent(ContentManager content)
{
instance.currentScene.LoadContent(content);
}
public void UnloadContent()
{
instance.currentScene.UnloadContent();
}
}
you've declared Scene as an abstract class, so you can't just use it as you're doing: Scene currentScene, newScene. (See this reference for more details on abstract classes).
Either make scene a non-abstract class type or create another class that inherits from your abstract class, looking at your code it would be something like:
public class myScene : Scene
{
public override void Update()
{
//do something
}
// etc.
}
You are getting a NullReferenceException because you are mixing static and instance fields in your code:
There are several problems:
Your SceneManager has a public constructor, but its instance method all access the same static (singleton) instance.
Your SceneManager.Draw method does not access the static instance.
Your Game class instantiates a separate ScreenManager instance, meaning the singleton is initialized, but the Games instance isn't. This is allowed because of 1.
There are several ways of fixing this:
The Preferred way: remove the static stuff from SceneManager. Your game is going to have a single instance in the Game class anyway, and you can simply pass the instance along to any scenes. A no brainer.
However, if you want to keep this class a singleton, you need to change a couple of things. People usually want this because they are too lazy to pass the SceneManager along to each scene instance. So, singletons are bad, you won't be able to unit test anything, but I believe most indie game developers don't care too much about unit testing and would be happiest if everything was static and accessible from anywhere.
Make the constructor private, so that no other class (like Game) can instantiate it. If anyone wants to access the instance, they should do it through the getInstance() method. Which, btw, might better be a property instead:
public class SceneManager
{
// private constructor means other classes cannot instantiate this
private SceneManager() { }
private static readonly SceneManager _instance = new SceneManager();
public static SceneManager Instance
{
get { return _instance; }
}
}
If you now try to pull this off in your Game class:
var sceneManager = new SceneManager();
your compiler will tell you it's not going to work that way.
Your SceneManager should only have a single static method/property: getInstance() or the Instance property like shown above. All other methods should be instance methods of that one-and-only instance, and not access the instance field at all. They are accessing that instance anyway. It is a bad idea to have instance methods access static fields:
This is wrong:
public void Initialize()
{
var mainScene = = new MainMenuScene();
instance.sceneDirectory["MainMenuScene"] = mainScene;
instance.currentScene = mainScene;
}
But this is fine (and the this keyword is redundant, of course):
public void Initialize()
{
var mainScene = = new MainMenuScene();
this.sceneDirectory["MainMenuScene"] = mainScene;
this.currentScene = mainScene;
}
Because you're going to use it like this anyway:
// you're basically doing the same thing, but
// it's immediately clear what's going on, and there
// is no room for errors:
var manager = SceneManager.Instance;
manager.Initialize();
The simplest way to ensure you're doing it right it to remove all references to instance inside the SceneManager class.

C# Cross-Class object

I'm working on very simple Roguelike game (just for myself) and get a question:
As it is not possible to create a cross-class struct-object (entity in the game case) that could be accessible from any class of my program, what to use to create a cross-class object? I was thinking of something like storing all newly created object (enities) in a static object array, but I guess there is more simple solution on this problem.
Question itself: How to create a cross-class accessible object(s) with your own properties?
Thanks everybody, I found what I was searching for.
It seems like you tried passing around a value type (a struct) between different classes and you noticed that when you update the value in one place it doesn't change the value in another place.
That's the basic difference between value types and reference types.
If you are creating the struct yourself you may want to instead define it as a class.
If not, you could wrap all your structs in a class and pass the class around as your state object.
If all you have is simply a list of the same type of struct (like Points), just pass the List itself around. C# collections are implemented as classes.
public class GameState
{
public Point PlayerLocation { get; set; }
public List<Point> BulletPoints { get; set; }
public double Health { get; set; }
}
Now you can create a GameState and pass it around to different classes:
public class Game
{
private GameState _state = new GameState();
private BulletUpdater _bulletUpdater = new BulletUpdater();
public void Update()
{
_bulletUpdater.UpdatePoints(_state);
// Points have now been modified by another class, even though a Point is a struct.
}
}
public class BulletUpdater
{
public void UpdatePoints(GameState state)
{
for (int i = 0; i < state.BulletPoints.Count; i++)
{
Point p = state.BulletPoints[i];
state.BulletPoints[i] = new Point(p.X + 1, p.Y + 1);
}
}
}
Just remember in the above code if I were to write:
Point p = state.BulletPoints[i];
p.X += 1;
p.Y += 1;
That wouldn't affect the original point! When you read a value type from a list or from a class into only copies the value into a local variable. So in order to reflect your changes in the original object stored inside the reference type you need to overwrite it like so:
state.BulletPoints[i] = p;
This same principal is why the following also will not work:
state.PlayerLocation.X += 5; // Doesn't do anything
state.PlayerLocation.Y += 5; // Also doesn't do anything
The compiler would tell you in this case that you are doing something wrong. You are only modifying the returned value of the property, not the backing field itself. You have to write it like so:
state.PlayerLocation = new Point(state.PlayerLocation.X + 5, state.PlayerLocation.Y + 5); // This works!
You can do the following:
Using IoC Framework, like Ninject. You can setup Ninject to create single instance for all usages.
The other option is to use Singleton pattern design pattern
And the third one is to use static property
It sounds like you want to use the Singleton pattern:
http://en.wikipedia.org/wiki/Singleton_pattern
Here is an example of what this would look like in C#:
public class Singleton
{
static Singleton()
{
Instance = new Singleton();
}
public static Singleton Instance { get; private set; }
}
It's possible. What about public and static class?
public static class CrossClassObject
{
public static object MyProperty { get; set; }
public static void MyMethod() {}
}
Of course this class should be placed in the same namespace that other ones.
How to use it?
class OtherClassInTheSameNamespace
{
private void SomeMethod()
{
var localVariable = CrossClassObject.MyProperty; // get 'cross-class' property MyProperty
CrossClassObject.MyMethod(); // execute 'cross-class' method MyMethod()
}
}
No idea what you are trying to achieve... but if you want a list of objects accessible 'cross-class', just make a static class with a list of objects and then when you reference your class from any other class, you will have access to its list of objects. Here is something like that:
public static class ObjectController
{
private static IList<object> existingObjects;
public static IList<object> ExistingObjects
{
get
{
if (existingObjects == null)
{
existingObjects = new List<object>();
}
}
}
}
public class MyObject
{
public MyObject()
{
ObjectController.ExistingObjects.Add(this);
}
public void Delete()
{
ObjectController.ExistingObjects.Remove(this);
}
}
Then you can add stuff like
MyObject newObj = new MyObject();
//// other stuff... This object should now be visible to whatever other class references ObjectController
newObj.Delete();

How to make a class with multiple methods that return a value?

I have created a class that needs to alter a variable's value when it is instantiated.
Example:
In my LrgDialogBox class I might have:
public LrgDialogBox(ref oldResult)
{
// bunch of code
UserInput();
}
public UserInput()
{
newResult=false;
}
In my main class I create an object of my LrgDialogBox called lrgDia then I type:
lrgDia = new LrgDialogBox(ref result);
if (result==true) this.exit;
I basically need to know how to make the reference variable "oldResult" private in my LrgDialogBox class, so that any method can alter its value so it can be used in my main class. Hopefully without changing the parameters of my other methods. Please help.
Kris
There isn't any way for you to meaningfully store the reference parameter that is passed in and be able to modify its value later. What you need to do is add in another layer of indirection; create a reference type that holds onto the value that you really care about. Pass around references to that type, and then all of those references are indirectly pointing to a single value.
The implementation of such a wrapper is simple:
public class Wrapper<T>
{
public T Value { get; set; }
}
You can now create a class that accepts a Wrapper<bool> in the constructor, and then modifies the value within that wrapper at a later point in time.
public class Foo
{
private Wrapper<bool> flag;
public Foo(Wrapper<bool> flag)
{
this.flag = flag;
}
public void Bar()
{
flag.Value = false;
}
}
The other option available to you, since you are, in this case, only calling the method from within the constructor, is to simply have your other method return its value, rather than setting a private field. This would be the preferred design:
public class LrgDialogBox
{
public LrgDialogBox(ref bool oldResult)
{
// bunch of code
oldResult = UserInput();
}
public bool UserInput()
{
return false;
}
}
Just use a private variable to work with during the processing.
private bool _newResult;
public LrgDialogBox(ref bool oldResult)
{
// bunch of code
_newResult = oldResult;
UserInput();
oldResult = _newResult;
}
private void UserInput()
{
_newResult = false;
}

how to destroy a Static Class in C#

I am using .net 1.1. I have a session class in which I have stored many static variables that hold some data to be used by many classes.
I want to find a simple way of destroying this class instead of resetting every variable one by one. For example if there is a static class MyStatic, I would have liked to destroy/remove this class from the memory by writing MyStatic = null, which is not currently possible,
Additional question.
The idea of singleton is good, but I have the following questions:
If singleton is implemented, the 'single' object will still remain in the memory. In singleton, we are only checking if an instance is already existing. how can i make sure that this instance variable also gets destroyed.
I have a main class which initializes the variable in the static class. Even if I plan to implement a Rest() method, I need to call it from a method, for eg, the destructor in the main class. But this destructor gets called only when GC collects this main class object in the memory, which means the Reset() gets called very late
thanks
pradeep
Don't use a static class to store your variables. Use an instance (and make it a singleton if you only want one instance at any given time.) You can then implement IDisposible, and just call Dispose() when you want to destroy it.
For more information check out this site: http://csharpindepth.com/Articles/General/Singleton.aspx
EDIT
The object is still subject to garbage collection, so unless you are using lots of unmanaged resources, you should be fine. You can implement IDisposible to clean up any resources that need to be cleaned up as well.
Instead of a static class, have a static instance of a class:
class Foo
{
public int Something;
public static Foo Instance = new Foo();
public void Reset()
{
Instance = new Foo();
}
}
void test
{
int i = Foo.Instance.Something;
}
You can also delegate to an instance of the class:
class Foo
{
public int Something
{
get { return instance.something; }
}
private int something;
private static Foo instance = new Foo();
public void Reset()
{
instance = new Foo();
}
}
void test
{
int i = Foo.Something;
}
There's no way to destroy a static unless it resides in a separate AppDomain in which case you can get rid of it by unloading the AppDomain. However it is usually better to avoid statics.
EDIT: Additional question
When the singleton is no longer referenced it will be collected just as everything else. In other words, if you want it collected you must make sure that there are no references to it. It goes without saying that if you store a static reference to your singleton, you will have the same problem as before.
Use a Singleton like ktrauberman said, and have an initialization method or a reset method. You only have to write the code once and call the method.
You destroy objects, not classes. There's nothing wrong with static classes--C# provides them for a reason. Singletons are just extra overhead, unless you actually need an object, e.g. when you have to pass the object as a parameter.
Static classes contain only static variables. These variables tend to last for the lifetime of the app, in which case you don't have to worry about disposing referenced objects, unless you have a mild case of OCD. That just leaves the case where your static class allocates and releases resources throughout its lifetime. Dispose of these objects in due course as you usually would (e.g., "using...").
The best way in your condition is to have an Reset() method built-in as well, which can reset the values of the class.
class myclass
{
private static myclass singleobj = null;
private myclass(){}
public static myclass CreateInstance()
{
if(singleobj == null)
singleobj = new myclass();
return singleobj
}
}
Building on Ahemd Said's answer: (and props to him!)
class Singleton
{
private static Singleton instance = null;
private Singleton(){} // private constructor: stops others from using
public static Singleton Instance
{
get { return instance ?? (instance = new Singleton()); }
set {
if (null != value)
{ throw new InvalidValueException(); }
else
{ instance = null; }
}
}
}
void SampleUsage()
{
Singleton myObj = Singleton.Instance;
// use myObj for your work...
myObj.Instance = null; // The set-operator makes it ready for GC
}
(untested... but mostly right, I think)
You could also add in usage of the IDispose interface for more cleanup.
You can create a method in the static class which resets the values of all properties.
Consider you have a static class
public static class ClassA
{
public static int id=0;
public static string name="";
public static void ResetValues()
{
// Here you want to reset to the old initialized value
id=0;
name="";
}
}
Now you can use any of the below approaches from any other class to reset value of a static class
Approach 1 - Calling directly
ClassA.ResetValues();
Approach 2 - Invoking method dynamically from a known namespace and known class
Type t1 = Type.GetType("Namespace1.ClassA");
MethodInfo methodInfo1 = t1.GetMethod("ResetValues");
if (methodInfo1 != null)
{
object result = null;
result = methodInfo1.Invoke(null, null);
}
Approach 3 - Invoking method dynamically from an assembly/set of assemblies
foreach (var Ass in AppDomain.CurrentDomain.GetAssemblies())
{
// Use the above "If" condition if you want to filter from only one Dll
if (Ass.ManifestModule.FullyQualifiedName.EndsWith("YourDll.dll"))
{
List<Type> lstClasses = Ass.GetTypes().Where(t => t.IsClass && t.IsSealed && t.IsAbstract).ToList();
foreach (Type type in lstClasses)
{
MethodInfo methodInfo = type.GetMethod("ResetValues");
if (methodInfo != null)
{
object result = null;
result = methodInfo.Invoke(null, null);
}
}
break;
}
}
Inject the objects into the static class at startup from a non static class that implements IDisposable, then when your non static class is destroyed so are the objects the static class uses.
Make sure to implement something like "Disable()" so the static class is made aware it's objects have just been set to null.
Eg I have a logger class as follows:
public static class Logger
{
private static Action<string, Exception, bool> _logError;
public static void InitLogger(Action<string, Exception, bool> logError)
{
if(logError != null) _logError = logError;
}
public static void LogError(string msg, Exception e = null, bool sendEmailReport = false)
{
_logError?.Invoke(msg, e, sendEmailReport);
}
In my constructor of my Form I call the following to setup the logger.
Logger.InitLogger(LogError);
Then from any class in my project I can do the following:
Logger.LogError("error",new Exception("error), true);

Categories