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

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;
}
}

Related

Why can't I get the Text component of an Input Field

I have a TextMeshPro Input Field but my various attempts at getting the Text component are producing null reference exceptions. The Input Field is called Name. I reference this object when the player clicks OK after submitting their name.
Here is the GetName script:
public class GetName : MonoBehaviour
{
GameObject Name;
// These two are left over from previous attempts.
public TextMeshProUGUI player_name;
public TMP_InputField player_inputField;
private string monicker;
// Integer function should be less bother than a bool when called from another script.
public int IsNameEmpty()
{
monicker = Name.GetComponent<TMP_InputField>().text.ToString();
// Program never gets this far.
The OK function in the other script is:
public class WelcomeButtons : MonoBehaviour
{
public GetName getName;
void TaskOnClick6()
{
Debug.Log("You have clicked the OK button!");
int isName = getName.IsNameEmpty(); // Causes null reference exception.
// Program never gets this far.
A simple method to get the text from the input field
public class GetName: MonoBehaviour
{
public TMP_InputField name;
public void TaskOnClick()
{
if(name =="")
{
Debug.log("NO Name Found");
}
else
{
Debug.log("NAME: "+name);
}
}
Yes, if you attached the script above to an empty GameObject, then your script is missing the Link to the GameObject containing the TMP_InputField-Component. You can fix this in two simple ways, just decide what fits best for you:
a) Attach the GetName-script to the same GameObject that also contains the TMP_InputField-Component. Replace the Line "Name.GetComponent<TMP_InputField>().text.ToString();" with "GetComponent<TMP_InputField>().text.ToString();".
b) Leave the GetName-script on the empty GameObject. Make the "GameObject Name;" line public by changing it to "public GameObject Name". Go to the Unity-Editor. When selecting the GameObject containing the GetName-script, you should see the Name-Property and an empty Field next to it in the Inspector. Drag&Drop the GameObject containing the TMP_InputField-Component into it.
So, why did your code not work before? Well, the GetName-script needs some kind of reference to your TMP_InputField-component, which was missing. You tried this by getting it from the Name-Property, but never assigned it any value.
Thanks for all the advice I've received. I now have a working version using the OnClick() approach:
public class GetName : MonoBehaviour
{
public TMP_InputField user_inputField; // User-entered name.
public void SaveName()
{
Globals.player = user_inputField.text.ToString(); // Saved for later.
Debug.Log("Globals.player is " + Globals.player);
}
public void ResetName()
{
user_inputField.text = "";
Globals.player = "";
}
}
just two lines will work :
using UnityEngine.UI;
and
public TMPro.TMP_InputField Name;

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
}

Check the previous loaded scene

I'm making a game in Unity3D with C# for mobile devices and can't figure out how to check which scene was loaded before the current scene. I need to check this to change the spawn point from the player gameobject. First I added a simple script to my buttons (loadnextscene and loadprevscene)
public class SwitchScene : MonoBehaviour {
public int sceneNumber;
public void LoadScene(int sceneNumber) {
Application.LoadLevel(sceneNumber);
}
}
A second scripts handles the touch input from the user and changes the movement of the player object.
So, for example: If the player clicks on the "load previous scene" button in the second Level to switch to the first level again, I want to set the spawn point of the player object on the right half on the screen and not on the left side like when the game was started the first time.
I tried it with Singleton and PlayerPrefs, but it did not work out.
You need to save the scene number to some variable before LoadScene, then check it after the scene loaded.
The only problem is that this variable will be destroyed after the new scene is loaded. So, to prevent it, you can use DontDestroyOnLoad. Here is what you do:
First, create a new empty game object, and attach the following script to it:
using UnityEngine;
using System.Collections;
public class Indestructable : MonoBehaviour {
public static Indestructable instance = null;
// For sake of example, assume -1 indicates first scene
public int prevScene = -1;
void Awake() {
// If we don't have an instance set - set it now
if(!instance )
instance = this;
// Otherwise, its a double, we dont need it - destroy
else {
Destroy(this.gameObject) ;
return;
}
DontDestroyOnLoad(this.gameObject) ;
}
}
And now, before you load, save the scene number in the Indestructable object:
public class SwitchScene : MonoBehaviour {
public int sceneNumber;
public void LoadScene(int sceneNumber) {
Indestructable.instance.prevScene = Application.loadedLevel;
Application.LoadLevel(sceneNumber);
}
}
And last, in your scene Start() check Indestructable.instance.prevScene and do your magic accordingly.
More info here:
http://docs.unity3d.com/ScriptReference/Object.DontDestroyOnLoad.html
*I did not compile the code, so there may be some errors, but this is the general idea.
Why did the PlayerPrefs approach did not work?
I think its the easiest way to solve your problem.
public class FirstLevel : MonoBehaviour {
public void Start() {
PlayerPrefs.SetString("SceneNumber", SceneManager.GetActiveScene().name);
}
}
And then in the second scene simply read the saved PlayerPrefs
public class SecondLevel : MonoBehaviour {
string PrevScene;
public void Start() {
PrevScene = PlayerPrefs.GetString("SceneNumber");
// if there will be a third scene, etc.
PlayerPrefs.SetString("SceneNumber", SceneManager.GetActiveScene().name);
}
public void GoToPrevScene() {
SceneManager.LoadScene(PrevScene);
}
}
You can solve this problem with a single static member variable in the SwitchScene class. No need for the singleton pattern or DontDestroyOnLoad.
public class SwitchScene : MonoBehaviour
{
public int sceneNumber;
private static int previousScene;
private int oldPreviousScene;
void Start()
{
oldPreviousScene = previousScene;
previousScene = sceneNumber;
}
public void HandleLoadPrevButtonClick()
{
SceneManager.LoadScene(oldPreviousScene);
}
}

How do I pass a method as a parameter?

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

Looking for advice on getting events to work

I'm looking for some help in understanding Events. I've been reading articles on them and watching tutorial videos.
I almost understand them, but I keep hitting snags.
I made myself a simple WinForms test app to try and learn the process. In the app, there are 2 walking sprites running around the screen.
When you click on the form, it creates a sprite of a falling thwomp (And it creates an event) the walker sprites should react to the event by choosing a new walking path headed away from the sprite. I think I've written everything correctly, but when I compile it I get the error:
Error 1 Inconsistent accessibility: parameter type 'eventStomper.RunEventArgs' is less accessible than delegate 'eventStomper.RunInFear'
Error 2 Inconsistent accessibility: parameter type 'eventStomper.RunEventArgs' is less accessible than method 'eventStomper.Walker.RunAway(object, eventStomper.RunEventArgs)'
I'm at a loss because everything is public. Any suggestions on there error? And, any advice on Event handling?
Here's the source code boiled down to just the relevant bits:
namespace eventStomper
{
public delegate void RunInFear(object sender, RunEventArgs re); //The delegate for responding to events.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
spawnWalkers(); //Create a couple of walkers to roam around the form
}
List<Thwomp> thowmpList = new List<Thwomp>(); //List of thwomps. This is iterated through for animation.
List<Walker> walkerList = new List<Walker>();// Same thing with the walkers.
public void pictureBox1_Click(object sender, EventArgs e) //When you click on the background, it spawns a thwomp
{
Point _spawnPoint = this.PointToClient(Cursor.Position);
Thwomp _thwomp = new Thwomp(_spawnPoint, sprite ); //Generate a new Thwomp
thowmpList.Add(_thwomp); //Add it to the list of Thwomps
_thwomp.TimeToRun += walkerList[0].RunAway; //Register with the two walkers roaming around.
_thwomp.TimeToRun += walkerList[1].RunAway;
//Do other things to setup the thwomp sprite
}
}
public class Thwomp
{
public int spriteX = 0;//Current sprite location
public int spriteY = 0;
public int targetX = 0;//Where the thwomp will land.
public int targetY = 0;
public event RunInFear TimeToRun;
public void Animate()
{
//Do Animation steps.
}
public Thwomp(Point spawnPoint, PictureBox spriteIncoming)
{
RunEventArgs re = new RunEventArgs();
re._pointOfFear = spawnPoint;
//Setup thwomp sprite
TimeToRun(this, re); //Trigger the event.
}
}
public class Walker
{
public int spriteX = 0; //Current sprite location
public int spriteY = 0;
public Walker(Point spawnPoint, PictureBox spriteIncoming)
{
//Create the walker
}
public void RunAway(Point dangerPoint)
{
if (Math.Abs(sprite.Top - dangerPoint.Y) < 20 && Math.Abs(sprite.Left - dangerPoint.X) < 20) //If near a newly created thwomp, run away.
{
//Pick a path headed away from the danger.
}
}
public void Animate()
{
//Move the walker away.
}
}
class RunEventArgs : EventArgs
{
public Point _pointOfFear;
}
}
I'm at a loss because everything is public.
Not quite. As the error message says:
parameter type 'eventStomper.RunEventArgs' is less accessible than delegate 'eventStomper.RunInFear'
According to that message, RunEventArgs is less accessible than RunInFear. Therefore, let's look at the accessibility levels of those two types:
public delegate void RunInFear(object sender, RunEventArgs re);
So, that is public. So far, so good.
class RunEventArgs : EventArgs
{
public Point _pointOfFear;
}
Aha! This one has no accessibility assigned to, which means that - according to the docs - it will default to internal:
Top-level types, which are not nested in other types, can only have internal or public accessibility. The default accessibility for these types is internal.
Therefore, make that RunEventArgs class public and your code should compile.

Categories