How do I pass a method as a parameter? - c#

I've been tinkering with a game engine and part of it has been building a class for the UI elements. My goal is to make it really simple to add buttons to the UI with just a line that will include the button location and what method it calls when someone presses that button. I just can't figure out how to pass in the target method that will trigger when the button is pressed. I can get methods to subscribe to delegate events, just not when they're wrapped up in a list of button objects I've created.
I've simplified the code down to just what I'm trying to accomplish here. The main sticking point is I'm not sure what to put in as the object type for the method parameters for addButton() in order to be able to pass in another method that can subscribe to delegate events. If I try Void or Object, I get conversion errors.
public Class UserButton
{
public delegate void triggerEvent();
public triggerEvent ButtonPress; //This should fire off the event when this particular button is pressed.
public UserButton(Point buttonlocation, Point buttonsize, string buttontext, Texture2d Texture)
{
//Store all this data
}
}
public Class UserInterface //This class is for the buttons that appear on screen. Each button should have a location and a method that it calls when it's "pressed"
{
List<UserButton> ButtonList = new List<UserButton>(); //List of all the buttons that have been created.
//Add a button to the list.
public void addButton(Point location, Point buttonsize, Texture2d texture, Method triggeredEvent) //Compile fails here because I can't figure out what type of object a method should be.
{
UserButton button = new UserButton(Point location, Point buttonsize, Texture2d texture);
button.ButtonPress += triggeredEvent; //The target method should subscribe to the triggered events.
ButtonList.Add(button);
}
public void checkPress(Point mousePos) //Class level method to sort through all the buttons that have been created and see which one was pressed.
{
foreach (UserButton _button in ButtonList)
{
if (_button.ButtonBounds.Contains(mousePos))
{
_button.ButtonPress(); //Call the event that should trigger the subscribed method.
}
}
}
}
public class Game1 : Game
{
//Main methods
//Load
protected override void LoadContent()
{
UI = new UserInterface(); //Create the UI object
UI.addButton(new Point(32,32), Texture,toggleRun()); //Pass in the method this button calls in here.
}
private void toggleRun() //The button should call this method to start and stop the game engine.
{
if (running)
{
running = false;
} else {
running = true;
}
protected override void Update(GameTime gameTime)
{
if (MouseClick) //simplified mouse check event
{
UI.checkPress(mousePos); //Pass the current mouse position to see if we clicked on a button.
}
}
}

Your "triggeredEvent" parameter should be the same delegate type "triggerEvent":
public void addButton(Point location, Point buttonsize, Texture2d texture, triggerEvent triggeredEvent)
To pass a method as the parameter, use the method name without invoking it (this will only work if the method "toggleRun" does not have any overloaded methods, and matches the signature of the "triggerEvent" delegate):
UI.addButton(new Point(32,32), Texture, toggleRun);

Related

Dynamically access methods from other script through string

I have several game objects; the idea is that each time you click on any of them a pop up window with a button shows up. Depending on the object you clicked, the pop up's button performs a different function.
This is the code I'm currently using:
Script PopUpCaller- attached to each of the game objects:
public GameObject popUp;
string rewriteThis;
void Start()
{
rewriteThis = gameObject.name; // Each game object's name = desired method's name. E.g. if the method's name is ActionA() then the game object's name would be ActionA.
}
public void TaskOnClick()
{
popUp.SetActive(true);
popUp.transform.position = Input.mousePosition;
PopUp.instance.rewriteMethodName = rewriteThis;
}
Script PopUp - attached to the pop up window
public static PopUp instance;
public string rewriteMethodName;
private void Awake()
{
instance = this;
}
void Start()
{
gameObject.SetActive(false);
}
public void DoThings()
{
GameObject.Find("MapManager").SendMessage("rewriteMethodName");
}
Script Manager containing the methods for the game objects.
public void ActionA() //named like the corresponding game object
{
//stuff to be done
}
public void ActionB() //named like the corresponding game object
{
//other stuff to be done
}
When I run the code as it is I receive the "SendMessage rewriteMethodName has no receiver!".
Now when I change "rewriteMethodName" in the PopUp script to "ActionA" or "ActionB" everything starts working, which suggests that the Manager script doesn't recognize "rewriteMethodName" even if it returns the string "ActionA" or "ActionB".
I also tried doing the same via MethodInfo and making Manager public static but it didn't work out either:
MethodInfo method =Manager.instanceManager.GetType().GetMethod("rewriteMethodName", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
method.Invoke(Manager.instanceMapManager, null);
Any suggestions how to fix it?
Thank you!
rewriteMethodName holds the method name, so should be passed in SendMessage instead of the string “rewriteMethodName”. To close out the question:
public void DoThings()
{
GameObject.Find("MapManager").SendMessage(rewriteMethodName);
}

C# Virtual Method Issue

I'm currently programming a 2D Game Engine in C# using GDI+ and at the moment I'm trying to implement a component based structure.
The idea is that my GameObject class has a list of components. Each component can be completely different to the next.
I represented components by creating a Component class, which looks like this:
public class Component : BaseObject
{
/// <summary>
/// The game object this component is attached too.
/// </summary>
private GameObject gameObject = null;
/*
* Below I called the protected virtual methods from the "BaseObject" class.
* The base object class only contains these 4 protected virtual methods. Nothing else.
*/
public void Load()
{
OnLoad(this, EventArgs.Empty);
}
public void Unload()
{
OnUnload(this, EventArgs.Empty);
}
public void Update(GameTime gameTime)
{
OnUpdate(this, new UpdateEventArgs(gameTime));
}
public void Render(GraphicsEngine graphicsEngine)
{
OnRender(this, new RenderEventArgs(graphicsEngine));
}
public GameObject GameObject
{
get { return gameObject; }
set { gameObject = value; }
}
}
In my game object class, every component that is within the components list gets updated and rendered like so:
internal void Update(GameTime gameTime)
{
OnUpdate(this, new UpdateEventArgs(gameTime));
// All components being updated
components.ForEach(c => c.Update(gameTime));
}
With all of that being said, I've created a SpriteComponent class, which is meant to render a simple 2D sprite, based on the game objects position, it's overrided render method looks like this:
protected override void OnRender(object sender, RenderEventArgs e)
{
e.GraphicsEngine.DrawBitmap(bitmap, GameObject.Transform.Position);
base.OnRender(sender, e);
}
However for some reason this happens (This is the render method of the GameObject class):
internal void Render(GraphicsEngine graphicsEngine)
{
if (Enabled)
{
// Rendering a sprite component like this works fine
// Here I've created created a SpriteComponent inside the game object class to test it
if(sprite != null)
graphicsEngine.DrawBitmap(sprite.Bitmap, transform.Position);
OnRender(this, new RenderEventArgs(graphicsEngine));
// But rendering it using it's own method doesn't work
//sprite.Render(graphicsEngine);
// and this doesn't work properly either
// components.ForEach(c => c.Render(graphicsEngine));
}
}
And here is a picture of the result when I either iterate through the components list and render it, or render the sprite component by it's self:
I would look into you calling the OnRender. It is not best practice to call these event handlers. The has to be some other method you need to call which will invoke the OnRender.
Similar to OnDraw (Event handler) and Update (Invoke method)
I think you did override wrong method, As I see you have override the OnRender
While probably you calling Render method.
Try to make the Render method virtual and override it in child classes

Function to change background of a toggle button when pressed

I am creating a function to change the background image of a toggle button when it is pressed but it is not working out for me.
I currently have this function:
public Image Background1;
public Image Background2;
public Toggle theToggle;
public void ChangeBackground()
{
if (theToggle.isOn) {
theToggle.image () = Background1;
}
else
{
theToggle.image() = Background2;
}
}
My problem is that in the scene view I don't receive the slot option to add an image to Background1 and Background2 like it happens on other scripts. Also the image parameterer is not recognized by the editor despite the fact it is on the scripting reference and that I have added the UI lybrary using:
using UnityEngine.UI;
Also, I tried to put the ChangeBackground() function inside the Update() function like this and I receive a parse error:
public Image Background1;
public Image Background2;
public Toggle theToggle;
void Update ()
{
public void ChangeBackground()
{
if (theToggle.isOn) {
theToggle.image () = Background1;
}
else
{
theToggle.image() = Background2;
}
}
}
This parse error is very strange because this is the way i did in other scripts. Can you help me?
Well for one, you have a compiler error because you're attempting to call the function "image" and assign it a value at the same time. My guess is you wanted to set the image attribute to some Sprite type variable "Background1"
So you'd change that like this:
public void ChangeBackground()
{
if (theToggle.isOn) {
theToggle.image = Background1;
}
else
{
theToggle.image = Background2;
}
}
}
Now, when there is a compiler error, the inspector will not update with new fields from a script. So if you have declared variables somewhere in your script (usually after the class declaration) like so:
public Image background1;
public Image background2;
They will appear in the inspector, waiting to be set, as long as you have no compiler errors and they are public
Also, you can't put a function declaration, nor would you want to, in C# and most programming languages.
You MUST drag the ChangeBackground function ON TO YOUR TOGGLE. Drag it to here...
Note! the following is highly advanced information, not immediately relevant to Grow's question as such.
An easy way to apply the ChangeBackground function whenever the toggle is toggled, you could simply do it in script by including these two functions:
void OnEnable()
{
theToggle.onValueChanged += ChangeBackground
}
void OnDisable()
{
theToggle.onValueChanged -= ChangeBackground
}

Screen managment XNA C#

I'm trying to implement screen management into my XNA game.
So far I've successfully implemented Example 3 from this link: http://www.xnadevelopment.com/tutorials/thestateofthings/thestateofthings.shtml
My current screen switch event is as follows:
public void GoToScreenOverview(object obj, EventArgs e)
{
screenStart = null;
screenOverview = new ScreenOverview(this, new EventHandler(GoToScreenOverview), globalVariables);
mCurrentScreen = screenOverview;
}
This moves from the (initial) screen "Start", and moves the game to the next screen "Overview". The equivalent reciprocal method GoToScreenStart does the opposite.
My question is this: How do I manage all the events?
Let's say I have 20 screens. Each screen Class will need 19 EventHandlers passed to it, which seems massively inefficient, and makes it a pain to add a new screen. Currently GoToScreenX type are events are in the Game1 class, but it seems to me that it would make more sense for all the events to be in the "BaseScreen" class, which each Screen inherits from.
If I were you, I would create a ScreenManager class. You could start with something like this:
public class ScreenManager
{
List<GameScreen> screens;
bool isinitialized = false;
public override void Initialize()
{
base.Initialize();
isinitialized = true;
}
protected override void LoadContent()
{
foreach (GameScreen screen in screens)
screen.LoadContent();
}
public void AddScreen(GameScreen screen)
{
screens.Add(screen);
if (isinitialized) screen.LoadContent();
}
// also create a removescreen
public void Draw(Gametime gametime)
{
foreach (GameScreen screen in screens)
{
screen.Draw(gametime);
}
}
// also create a similar method for Updating
}
You could make ScreenManager a DrawableGameComponent (recommended), or you could have the maingame call ScreenManager.Update() and ScreenManager.Draw() in it's respective methods. Finally, you'd have to create an abstract GameScreen class that has update and draw methods, and then have all your other Game Screens inherit from the GameScreen class. hopefully this will give you some ideas.

XNA - How Can I Edit A Rectangles Bounds From Another Class

So I have this problem where I have a variable called StarBounds in my main game class file. The file is now called MainGameClass.cs with namespace StarCatcher.
I have made a class to detect if the mouse is hovered over the StarBounds variable and then clicks. On click I would like to edit the StarBounds variable from this other class called GameFunctions.cs.
I am able to do something like...
MainGameClass mgc = new MainGameClass();
The when the hover and click event is triggered I can type in without errors:
mgc.StarBounds = new rectangle(0,0,0,0);
But in the actual game it does not change. And also I sometimes get errors when doing the "mgc.StarBounds = new rectangle(0,0,0,0);" saying it doesn't have an object reference.
I think this is most likely just a scope issue. The exception is caused because mgc is null. Make sure that GameFunctions has not declared a local copy of MainGameClass and is referencing a pre-existing instance. Otherwise, use a static variable for StarBounds as shown in the example. Example,
public class MainGameClass {
public static Rectangle StarBounds;
public void HandleInput () {
// if GameFunctions.ClickedWithinStarBounds(mouse)
// GameFunctions.OnClickStarBounds()
}
}
public class GameFunctions {
public static void ClickedWithinStarBounds(MouseState mouse) {
// create a rectangle around the mouse (ie. cursor) for the detection area
// return left mouse button is down or pressed && IsWithinStarBounds
}
public static bool IsWithingStarBounds(Rectangle area) {
return (MainGameClass.StarBounds.Intersects(area);
}
public static void OnClickStarBounds() {
MainGameClass.StarBounds = Rectangle.Empty;
}
}

Categories