XNA - how to use the same key for different options? - c#

So I have this code: Variables:
enum gameState
{
gameLoading,
mainMenu,
gameOptions,
levelSelect,
gamePlaying,
gameOver
}
In the Update() method:
if (CurrentGameState == gameState.gameLoading)
{
if (Keyboard.GetState().IsKeyDown(Keys.E))
{
graphics.ToggleFullScreen(); //?
}
graphics.ApplyChanges();
}
...
//gameState.gameLoading logic
if (Keyboard.GetState().IsKeyDown(Keys.Enter))
CurrentGameState = gameState.mainMenu;
So what I want is to have Enter pressed in gameState.gameLoading and both resolution is fullscreen and the gameState is equal to mainMenu. When in gameState.mainMenu the resolution can't be changed from fullscreen to windowed by pressing enter. How to achieve this? Maybe using list?

I think you should have different classes for any gameState if they need to have different behaviours. This will ensure you that each Update affect only its own gameState.

Since you've already decided what the states of your game are, why don't use the State Machine design pattern to control your input handling behaviour?
This pattern's agenda is to delegate the work from the actual object to its states. What you do is create a class with an Update() method for each state like pinckerman suggested, and enter all the input handling + state transition logic there. You can find an example here: http://sourcemaking.com/design_patterns/state.
When I use it, I detach the context from it's states and transitions completly by using an abstract state class and inherit from it. This makes it easier to change the state machine if needed.
Here is a quick example:
public class Context
{
private GameState state;
public void Update()
{
state.Update();
}
public void ChangeState(GameState nextState)
{
state = nextState;
}
}
public abstract class GameState
{
protected Context context;
public virtual void Update()
{
// some basic implementation if you want.
}
}
public class GameLoadingState : GameState
{
public override void Update()
{
// Handle key presses.
context.ChaneState(new MainMenuState(context));
}
}
public class MainMenuState : GameState
{
public override void Update()
{
// Handle key presses in some other way.
// Change state if needed.
}
}
Again, if you don't like the implementation of the passive context, you can change it to be more active.
Hope this helps!

Related

Unity c#: Code-structure or how to access a method/variable from another class/script?

I have two classes: Menu_Buttons, in which there are definitions for methods executed on clicking different buttons in the menu, and PauseMenu, which defines what happens when the Menu key is pressed during the game.
Menu_Buttons:
public class Menu_Buttons : MonoBehaviour
{
public void Menu_NewGameClick()
{
SceneManager.LoadScene(1);
}
public void Menu_ContinueClick()
{
Debug.Log("This will continue the game from the last save");
}
public void Menu_LoadGameClick()
{
SceneManager.LoadScene(1);
Debug.Log("Another menu will show to choose which save to load");
}
public void Menu_SaveGameClick()
{
SaveItem();
Debug.Log("This will save the game");
}
public void Menu_OptionsClick()
{
Debug.Log("This will show the game options");
}
public void Menu_QuitClick()
{
Application.Quit();
Debug.Log("The Game should quit now");
}
}
PauseMenu:
public class PauseMenu : MonoBehaviour
{
//private bool isPauseMenuOpened = false;
public GameObject pauseMenu;
void Update()
{
if (Input.GetKeyDown(KeyCode.B))
{
if (pauseMenu.activeSelf) { ClosePauseMenu(); }
else { OpenPauseMenu(); }
}
}
public void OpenPauseMenu()
{
pauseMenu.SetActive(true);
Cursor.visible = true;
Cursor.lockState = CursorLockMode.Confined;
//isPauseMenuOpened = true;
Time.timeScale = 0f;
}
public void ClosePauseMenu()
{
pauseMenu.SetActive(false);
Cursor.visible = false;
Cursor.lockState = CursorLockMode.Locked;
//isPauseMenuOpened = false;
Time.timeScale = 1f;
}
}
I wanted to add another method called Menu_ResumeClick, which would resume the game from the Pause Menu. Of course, I could just create this method in the PauseMenu script and then everything is fine. It looks like this:
public void Menu_ResumeClick()
{
ClosePauseMenu();
}
But since I would like to keep things organised, I thought it would be better to put this method in the Menu_Buttons script along with all the other similar methods. So I tried this:
public void Menu_ResumeClick()
{
PauseMenu.ClosePauseMenu();
}
And then problems begin... I get an error: an object reference is required for the non-static field method or property. Then if I change any of those classes to static, I get errors saying: cannot declare instance members in a static class. Not to mention that static classes canot inherit from MonoBehaviour. Maybe I would be able to solve those problems somehow, but the thing is I don't want to change the whole code just because I would rather have a method in another class. It's just for keeping things organised, nothing more.
I have to admit that I'm a bit frustrated by how these things work. I can easily put the Menu_ResumeClick() method in the PauseMenu class, but in the future it may be difficult to keep track of things if I have various methods scattered around different scripts. The most reasonable solution is to put every menu button in the Menu_Buttons class and then access them from there, but it poses problems that I described. Actually this is not the first time when I'm having problems with accessing methods or variables from other classes - there always seem to be some difficulties. It seems the best way to write code would be to just have a single class for the whole game because then I would be able to access absolutely anything easily - but again the problem would be with keeping things organised.
So, the question is: can I easily use methods (or variables) from other classes, without changing the whole code for this purpose? In other words can I somehow just call a method from another class like this: className.MethodName(); or set a variable from another class like this: className.varName = 2; without making everything static, etc.?
And a bonus question: If it's not possible, then how should I structure my code? Should I try to squeeze as many things as possible into a single class to be able to access them easily, should I make classes static, whenever it's possible, etc.?
In PauseMenu, you can add a field for the Menu_Buttons, which Unity can serialize, so you can pull the GameObject (what contains the Menu_Buttons) in the inspector, and you can call its public methods (and access its public members) from PauseMenu.
public Menu_Buttons MenuButtons;
// or (I much more like this version, keeping things as encapsulated as possible)
[SerializeField] private Menu_Buttons _menuButtons;
private void Resume() => _menuButtons.Menu_ResumeClick();
Edit based on comments:
Both script can have references to each other. As both logically related, I wouldn't separate them, because with the references, we couple them anyway.
Example:
public class Menu_Buttons : MonoBehaviour
{
[SerializeField] private PauseMenu _pauseMenu;
public void Menu_ResumeClick() => _pauseMenu.ClosePauseMenu();
// ...
}
public class PauseMenu : MonoBehaviour
{
[SerializeField] private Menu_Buttons _menuButtons;
// ...
public void ClosePauseMenu()
{
// ...
}
}

How to assign multiple functions to a button at different times?

I want a button to do multiple things but not at the same time.
For e.g. in the game, when the player comes near the door and press the button, i want it to open the door. And when player comes near a weapon and press the SAME button, i want the player to pick up the weapon.
P.S. I'm making a game for mobile.
You could for example use an enum and set a value/type on it.
You can set a value when you are near a door, for example, and overwrite it when you are near a weapon.
As soon as the button is pressed, you simply check the value of the enum and execute an action based on the value.
enum Actions
{
OpenDoor,
NearWeapon
}
You actually do not need different callbacks for this.
I would have one single callback react differently to whatever you are close to.
This is pretty much the same as here. Slightly different use case but the principle is similar.
There is basically two main option
Either the target objects implement the logic => use a common interface/base class
Your player implements the logic => use whatever to differ between the object types
Then your player could check what it "is close to" - I will just assume physics again but how exactly you check what you are "close to" is up to you - and interact with that target object.
Interface
You could simply have a shared interface like e.g.
public interface IInteractable
{
void Interact(/*pass in whatever arguments you need e.g.*/Player player);
}
and then have your classes implement it and the logic e.g.
public class Door : MonoBehaviour, IInteractable
{
public void Interact(Player player)
{
// whatever
}
}
and
public class Weapon : MonoBehaviour, IInteractable
{
public void Interact(Player player)
{
// whatever
}
}
and then assuming you use physics (triggers) you could do e.g.
public class Player : Monobehaviour
{
[SerialzieField] private Button button;
// we will store multiple close objects so we can smoothly transition between them in case
// we are close to multiple ones - up to you of course
private readonly List<IInteractable> currentActives = new();
private void Awake()
{
i(!button) button = GetComponent<Buton>();
// you attach a snigle callback
button.onClick.AddListener(Interact);
}
private void OnTriggerEner(Collider other)
{
// does this object have an IInteractable
var interactable = other.GetComponentInParent<IInteractable>();
if(interactable == null) return;
currentCloses.Add(interactable);
}
private void OnTriggerExit(Collider other)
{
// was the object an IInteractable?
var interactable = other.GetComponentInParent<IInteractable>(true);
if(interactable == null) return;
currentCloses.Remove(interactable);
}
private void Interact()
{
// some Linq magic to pick the closest item - again up to you
var currentClosest = currentCloses.Select(item => (MonoBehaviour)item).OrderBy(item => (item.transform.position, transform.position).sqrMagnitude).FirstOrDefault();
if(currentClosest == null) return;
// now let that object handle the interaction
// this class doesn't need to know what exactly this means at all
currentClosest.Interact(this);
}
}
This is of course a little bit inflexible and you always need to have a common shared interface and pass along all needed parameters. It can also get quite dirty if e.g. the weapon implements its own "pick up" - doesn't feel quite right.
Different Types
You could simply have different types (components) on your target objects, lets say e.g.
// have a common shared base class
public abstract class Interactable : MonoBeaviour
{
}
and then have derived types
public class Door : Interactable
{
// they can either implement their own logic
public void Open()
{
// whatever
}
}
and e.g.
public class Weapon : Interactable
{
// this one is purely used to differ between the type
// we rather expect whoever uses this will implement the logic instead
}
and then pretty similar as above
public class InteractionController : Monobehaviour
{
[SerialzieField] private Button button;
private readonly List<Interactable> currentActive = new();
private void Awake()
{
i(!button) button = GetComponent<Buton>();
button.onClick.AddListener(Interact);
}
private void OnTriggerEner(Collider other)
{
var interactable = other.GetComponentInParent<Interactable>();
if(!interactable) return;
currentCloses.Add(interactable);
}
private void OnTriggerExit(Collider other)
{
var interactable = other.GetComponentInParent<Interactable>();
if(!interactable) return;
currentCloses.Remove(interactable);
}
private void Interact()
{
var currentClosest = currentCloses.OrderBy(item => (item.transform.position, transform.position).sqrMagnitude).FirstOrDefault();
if(currentClosest == null) return;
// just that this one you check which actual type this component has
// and deal with it accordingly, completely customizable
switch(currentActive)
{
case Door door:
door.Open();
break;
case Weapon weapon:
PickupWeapon(weapon);
break;
default:
Debug.LogError($"Interaction with {currentActive.GetType().AssemblyQualifiedName} is not implemented!");
break;
}
}
// Just as example that the target doesn't even need to implement the method itself
private void PickupWeapon(Weapon weapon)
{
// whatever
}
}

Building a hierarchical state machine in Unity, having trouble with virtual functions

So I've been working on a state machine for a player character in a Unity game, and thought a hierarchical system would work well. However, I'm having some trouble getting methods to traverse the inheritance chain. If someone could point out my mistake for me, I'd greatly appreciate it.
Here's my PlayerScript : Monobehavior script:
public PlayerState State;
public void Start() {
State = new StoppedState();
State.Enter(this);
}
public void Update() {
State.Update(this);
}
And here are the PlayerStates:
public class PlayerState {
public virtual PlayerState Update(PlayerScript player) {
Debug.Log("Blorp");
return null;
}
public virtual void Enter(PlayerScript player) {}
}
public class LowPriorityState : PlayerState {
public new virtual PlayerState Update(PlayerScript player) {
Debug.Log("Blop");
PlayerState newState = base.Update(player);
//Do state stuff, determine if state should change
return newState;
}
}
public class StoppedState : LowPriorityState {
public override PlayerState Update(PlayerScript player) {
Debug.Log("Blip");
PlayerState newState = base.Update(player);
//Do state stuff, determine if state should change
return newState;
}
public override void Enter(PlayerScript player) {
Debug.Log("Entered Stopped State");
}
}
The expected output after 1 frame is:
Entered Stopped State
Blip
Blop
Blorp
but instead I'm getting:
Entered Stopped State
Blorp
...which is completely baffling, because it's clearly using the overridden "Enter" method but not using the overridden "Update" method. Does anyone know what I'm doing wrong and how to fix it?
The "new" modifier is used to hide a method of the base class and create a completely new method. This way, if the variable is of type BaseClass, it will call the method in the base class, and if the variable is of type DerivedClass, it will call the method in the derived class.
So in the LowPriorityState you are creating a new method, not overriding the one from PlayerState. So your field State of type PlayerState will continue to call the method from the base class.
And then you override this new method in StoppedState, but as your field State is of type PlayerState, it continues to call the method from the base class.
So just replace the new keyword with override.

How should you initialize constant data that needs parameters from another part of the code?

I don't think I explained my question very well in the title, so I'll do my best to do it here.
I have an abstract class called Song, a class that extends it MidiSongand then I have a SongCreator interface and a MidiSongCreatorclass that implements it. I would like to have a way to store lots of SongCreators so I can call their Create method but the problem is, since the SongCreators will each be a MidiSongCreator I am wondering how I should initialize each MidiSongCreator since it takes a MIDIPlayer and other things to help initialize it which doesn't have a static reference to it. Should I create a static class that holds lots of SongCreators? Should I not make the SongList class static?
What is looks like:
public abstract class Song{
public IList<Playable> notes { get; private set; }
public SongPlayData Start(){
// calls onStartEvent
return CreateSongData();
}
protected abstract SongPlayData CreateSongData();
public bool Update(SongPlayData songData, float songTime,List<SongPlayer> players) { // note that the players list is a list of people who are playing this game (this is a rhythm game) (doesn't have anything to do with MIDIPlayer
}
public void End(){
//calls end event
}
}
public class MidiSong : Song { // this is the class that needs the MIDIPlayer parameter
public MIDIPlayer midiPlayer;
protected MidiSong(MIDIPlayer player){
this.midiPlayer = player;
}
protected override SongPlayData CreateSongData() {
return new MidiSongData(midiPlayer);
}
}
public interface SongCreator<out T> where T : Song {
T Create();
}
public class MidiSongCreator : SongCreator<MidiSong>, IListenerObject { // this is the class that I need to store lots of instances of. the midiPlayer will probably be the same every time
private MIDIPlayer player;
public MidiSongCreator(MIDIPlayer player) {
this.player = player;
Init();
}
private void Init() {
player.midiListener.listener = this;
//
}
private void Clear() { // resets all the data so we can create another Song if we need to (even without entering stuff in)
if(player.midiListener.listener == this) {
player.midiListener.listener = null;
}
}
public MidiSong Create() {
MidiSong r = new MidiSong(player);
// I'm still going to implement calls to other methods from midiPlayer
Clear();
return r;
}
public void OnLoad(MidiFile file) {
// does stuff to load midi file (deals with individual events)
}
}
public class MasterSong : MonoBehaviour { // this should initialize last btw (It's in the Script Execution Order)
public MIDIPlayer midiPlayer;
public Song song;
public SongPlayData playData;
// Use this for initialization
void Start() {
// this is where I'd like to reference a SongCreator and call it's create method and Start the song
//for instance:
song = SongList.SONG_NAME.Create();
playData = song.Start();
}
void Update() {
}
}
It's a RhythmGame made with unity, but I didn't add the unity tag because I feel that this is more of a C#/design thing.
Also note, that I have my classes much more organized that just one file with all these.
I'm looking for ways to improve on the design that I have.
This is a design problem, domain design!
I suggest don't write code yet. Create a class diagram, with pen and paper, don't need to use tools in the beginning.
Try to determine entities - classes, interfaces etc - and the relationship among them. Just use boxes and arrow, don't need to put details yet. With boxes and arrows, you will be able to have a picture of your domain much more clearly. Keep refining and changing it, still at this high level, without details, until you are satisfied.
Then, step by step, refine it by adding details/properties such attributes and methods. This may cause to change the diagram from the first step.
I intentionally did not refer to specifics of you questions like the classes and interfaces you mentioned. Since, there is not enough information to comment on that. Secondly, and more importantly, you should start at high level of design and once that is done, then do coding based on your design.

Change a variable's accessibility during runtime

I wish to know if there is room for changing a variable's accessibility during runtime in Unity C#? The reason I want this is to hide unnecessary public variables when my script uses another state. I tried some dynamic variables, but I get errors that it can't be found.
I have that springDistance but I want to use it only when the state of the trapType is springOut.
Some code:
public class SpringTrap : MonoBehaviour
{
private Transform objectToMove;
// Use this for initialization
public enum TypeOfTrap
{
springOut
}
[Tooltip("Set the type of trap here to use.")]
public TypeOfTrap trapType = TypeOfTrap.springOut;
public float springDistance;
void Start ()
{
objectToMove = transform.FindChild("ObjectsToAnimate");
}
void OnTriggerEnter2D(Collider2D other)
{
if (other.gameObject.CompareTag("Player"))
{
//if the player has entered the danger zone
switch (trapType)
{
case TypeOfTrap.springOut:
break;
}
}
}
IEnumerator SpringOut(float springDistance)
{
float deltaDist = 0.0f;
while(deltaDist < springDistance)
{
objectToMove.position +=
}
}
}
Manipulation of the inspector is done with custom editor scripts. There you can display things, e.g. based on conditions.
Here is an example that does a very similar thing to the requested (displaying different things based on an enum field):
http://answers.unity3d.com/questions/417837/change-inspector-variables-depending-on-enum.html
An easier way to do what you are trying to achieve is to create an abstract trap class and then subclass different types of traps.
The abstract trap class handles collisions and then calls the abstract method Trigger.
public abstract class Trap : MonoBehaviour {
void OnTriggerEnter2D(Collider2D other)
{
if (other.gameObject.CompareTag("Player"))
Trigger(other.transform);
}
protected abstract void Trigger (Transform victim);
}
A spring trap can then be easily created by extending Trap and overriding the Trigger method.
public class SpringTrap : Trap {
public float SpringDistance;
protected override void Trigger (Transform victim) {
victim.position += Vector3.up * SpringDistance;
}
}
Now you don't have to worry about hiding irrelevant properties based on trap type because the only properties that will appear in the inspector are those you add to that variation of trap.

Categories