Recently started working with XNA (coming from java) and run into a problem with displaying game screens. When loading up XNA I get given a game.cs class which I interpreted to be a set a functions for drawing a single self-contained screen in the game. As obviously typing the code for all your different screens into this single class would get very messy very quickly so I created the below class to handle changes:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
namespace Colonies
{
public class GameManager //manages game screens
{
Microsoft.Xna.Framework.Game currentScreen;
public enum screens { menu, game, summary };
public GameManager()
{
initialize();
}
public void initialize()
{
currentScreen = new Menu(this);
((Menu)currentScreen).Run();
}
public void changeScreen(int i)
{
switch (i)
{
case 0:
currentScreen = new Menu(this);
((Menu)currentScreen).Run();
break;
case 1:
currentScreen = new World(this);
((World)currentScreen).Run();
break;
case 2:
currentScreen = new Summary(this);
((Summary)currentScreen).Run();
break;
}
}
}
}
However when one of these changes is triggered this causes an error flag up telling me I can't call game run more than once. Does this mean by initial estimation about having a single all purpose game screen is actually correct?! Should be manager instead be being queried for game like screens which methods are then called in the main game.cs class?
i.e.
in game.cs update method for example:
protected override void Update(GameTime gameTime)
{
// Allows the game to exit
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
// TODO: Add your update logic here
aGameManager.getAGameObject.DoAnUpdate();
base.Update(gameTime);
}
So essentially my main game class is never run again but just changes what it displays. Would this be the correct solution? (So much of the game class is hidden I am not sure what is the correct way to use it)
The Game class is the entire game. That's why it's called Game. If you want, you can create 'screen' objects, that each control a different screen, and use the Game class as you were trying to use the 'game manager'.
EG:
public static int currentScreen = 0; // Any screen can change this variable when needed
List<Screenobject> myscreens = new List<Screenobject>(); // Populate this with screens
// OR
menuscreen = new menuScreen();
otherscreen = new otherScreen();
// ...
protected override void Update(GameTime gameTime)
{
myscreens[currentScreen].Update(gameTime);
// OR
switch (currentScreen)
{
case 1:
menuscreen.Update(gameTime); break;
// ...
}
base.Update(gameTime);
}
and Draw(..) the same as Update(..)
create enumerator
enum gamestate
mainmenu
gameplay
options
end enum
and then simply in your update (draw) main functions
if gamestate = mainmenu then mainmenu.update();
if gamestate = gameplay then gameplay.update()
Related
I was trying to make a 2d Unity Latin translator, but i got a problem. How could i make that it recognises the Text and Dropdown variables already inside the "Declinatio". I need to check for the last 2 characters of this string which is SGenTextStr, and the data should be taken from the SGenText InputField. I dont know if you got a fix for this, i didnt find anything that was helpful on the internet.
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using UnityEngine.UI;
public class LatinDecl : MonoBehaviour
{
public static void Declinatio()
{
string SGenTextStr;
string AnsTextStr;
int StrLength;
SGenTextStr = SGenText.text;
AnsTextStr = AnsText.text;
StrLength = SGenTextStr.Length();
switch (SGenTextStr.charAt(StrLength - 2) + SGenTextStr.charAt(StrLength - 1))
{
default:
break;
}
}
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
InputField SGenText;
Dropdown DeclDrop;
InputField AnsText;
}
}
One of the things you may use a lot in Unity games is the Gameobject.GetComponent<>() method. It allows you to access values and functions from other components or scripts in your Unity Scene.
There are also an issue with declaring your variables in Update() as it will cause them to be wiped clean every frame, instead you may want to move them outside all together.
Because of that you will also have trouble with Declinatio() as it is currently static, which wont allow it to reference any non-static variables outside of it.
The last issue is that C# doesn't actually have an implementation of String.charat() however you can use String[int] to achieve the same thing.
With all those changes it would look something like this:
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using UnityEngine.UI;
public class LatinDecl : MonoBehaviour
{
public InputField SGenText;
public Dropdown DeclDrop;
public InputField AnsText;
public void Declinatio()
{
string SGenTextStr;
string AnsTextStr;
int StrLength;
SGenTextStr = SGenText.GetComponent<InputField>().text;
AnsTextStr = AnsText.GetComponent<InputField>().text;
StrLength = SGenTextStr.Length;
switch (SGenTextStr[(StrLength - 2)] + SGenTextStr[(StrLength - 1)])
{
default:
break;
}
}
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
}
}
I've created a rectangle, that has its own class. In the class I have a delegate created, that closes the game.
Creating the delegate:
public event EventHandler ExitRequested = delegate { };
In the update method I tell when to execute it:
if (mouseState.LeftButton == ButtonState.Pressed)
{
ExitRequested(this, EventArgs.Empty);
}
In my main class I execute the delegate like this (the exitGame is a rectangle):
exitGame.ExitRequested += exitGame_ExitRequested;
What I'm wondering about is there a way how to remove all items from the screen? Lets say it's for a "new game" functionality. I tried to create this functionality the same way I created the exit functionality but I can't figure out how to remove the items...
As far as I understand, you are trying to remove all game entities / objects in order to start a new game. Usually this is achieved by storing entities in a collection, and then simply removing all collection entries when a 'new game' is needed. As for entities which are not generic, such as the player, usually you just reset every member that needs to be reset; position, points etc.
Say you have a class to hold information about entities, such as enemies:
public class Entity
{
public Texture2D Sprite;
public Rectangle Bounds;
public Entity(Texture2D Sprite, Rectangle Bounds)
{
this.Sprite = Sprite;
this.Bounds = Bounds;
}
public void Update(GameTime gameTime)
{
//Movement code here
}
public void Draw(SpriteBatch spriteBatch)
{
spriteBatch.Draw(Sprite,Bounds,Color.White);
}
}
And you then store all entities in a collection:
public List<Entity> Entities = new List<Entity>();
You update and draw each entity by looping through the collection:
//In main game class
public void Update(GameTime gameTime)
{
foreach (Entity e in Entities)
e.Update(gameTime);
}
public override void Draw(GameTime gameTime)
{
foreach (Entity e in Entities)
e.Draw(spriteBatch);
}
Then when you want to start a new game, and effectively remove all entities, you can simply remove all entries in the Entities list. (For example using List.Clear(), there are many ways)
Keep in mind this is an example which has not been tested, so to say. This is can be optimized, and is more to give you an idea of why collections are useful for organizing game objects / entities.
I am writing a State Manager script for Unity in C#. Everything appears to be correct but when I test it out inside Unity, all the Debug.Log lines output twice. I'm following along with a book called Learning C# by Developing Games with Unity 3D Beginner's Guide. I have studied and studied the reference and I do not see what I am doing wrong. The script is far from finished, I think, but according to the text there should only be one output per Log.
This is my ISBase for the interface.
namespace Assets.Code.Interfaces
{
public interface IStateBase
{
void StateUpdate();
void ShowIt();
void StateFixedUpdate();
}
}
This my the BeginState, there is also a PlayState, WonState, and LostState. They're all pretty much identical except for the class name, the constructor name, the Debug.Log output, and the the new SwitchState.
using UnityEngine;
using Assets.Code.Interfaces;
namespace Assets.Code.States
{
public class BeginState : IStateBase
{
private StateManager manager;
public BeginState (StateManager managerRef) //Constructor
{
manager = managerRef;
Debug.Log ("Constructing BeginState");
}
public void StateUpdate()
{
if (Input.GetKeyUp (KeyCode.Space))
manager.SwitchState (new PlayState (manager));
}
public void ShowIt()
{
}
public void StateFixedUpdate()
{
}
}
}
And here is the actual StateManager.
using UnityEngine;
using Assets.Code.States;
using Assets.Code.Interfaces;
public class StateManager : MonoBehaviour
{
private IStateBase activeState;
void Start ()
{
activeState = new BeginState (this);
}
void Update ()
{
if (activeState != null)
activeState.StateUpdate ();
}
public void SwitchState(IStateBase newState)
{
activeState = newState;
}
}
IF it prints twice, it means that the call is done twice.
As obvious as it may sound, it is a matter to track it down, and I believe Unity will point you to the line of code called, if you double click on the console entry in the editor. This should open your IDE, or if it is open, just point the IDE to the line called.
Based on that, you may figure out that you have the same script on multiple objects; or you may have the same debug.log call in 2 different places of the script, but that are executed close to each other, ending up with you seeing the same statement.
Not much that can be done, without put a breakpoint and follow step by step
have you checked whether you have two same scripts attached to the same game object accidentally?
usually the duplicate log occurs for me when i got same script attached twice without me noticing it.
on the other hand, i would suggest guarding input from happening when switching state. anything to do with user input will need some guard from rapid repetition.
e.g.
if (!switchingStateCoolDown) {
Input.GetKeyUp (KeyCode.Space) { ... };
}
// hope you get the idea.
I have a class in Unity that a list of toggle switches that get turned on and off in a separate scene from the rest of my game. What I'm wanting is to have the user select one button and then have a corresponding action happen in my main game when they go back to that scene. However, I'm having issue sending information between scenes.
At the moment my toggle class looks like this:
private bool action1 = false;
public bool Action1
{
get { return action1;}
}
void OnGUI()
{
action1 = GUI.Toggle(new Rect(10, 10, 100, 30), action1, "test");
}
void Update()
{
if(Input.GetButton("Jump"))
{
Application.LoadLevel("Main");
}
}
Then in a class held in my Main scene, I have the following code:
private ActionClass actionIsOn = new ActionClass();
void Start()
{
if(actionIsOn.Action1 == true)
{
Debug.Log("action is on");
}
else
{
Debug.Log("nothing happening");
}
}
However, when I test this, nothing happens.
Have I set this up correctly? Is there a better way to pass this information from one scene to another?
Option #1:
Use a static class to hold global info that's relevant to multiple scenes.
public static class GlobalData
{
public static bool SomeBooleanFlag;
}
This way in your first scene you can set GlobalData.SomeBooleanFlag to some value, and in your second scene you can check for it.
Option #2:
You can use Object.DontDestroyOnLoad to ensure that an object in your scene doesn't get destroyed when a new scene is loading. This way you can aggregate all of the info that you want to pass to the other scene in a single object (or use multiple objects, and keep them all alive), and make sure it stays alive even after the scene has changed.
http://docs.unity3d.com/Documentation/ScriptReference/Object.DontDestroyOnLoad.html
I have an interface (ICamera) which is implemented by 2 classes (FreeCamera, StaticCamera). The classes are inheriting from GameComponent.
Example definiton:
public class FreeCamera : GameComponent, ICamera
{
...
}
Now I'm adding the classes to the Game Components and register one of the components to a game service
private FreeCamera freeCam;
private StaticCamera staticCam;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
freeCam = new FreeCamera(this) { Enabled = true };
staticCam = new StaticCamera(this) { Enabled = false };
Services.AddService(typeof(ICamera, freeCam);
Components.Add(freeCam);
Components.Add(staticCam);
...
}
Then I want to change the provider for the service during the application flow with help of a toggle function
namespace Game1
{
protected override void Update(GameTime gameTime)
{
var keyboard = Keyboard.GetState();
if(keyboard.IsKeyDown(Keys.C))
{
if(freeCam.Enabled)
{
Services.RemoveService(typeof(ICamera));
Services.AddService(typeof(ICamera, staticCam);
freeCam.Enabled = !freeCam.Enabled;
staticCam.Enabled = !staticCam.Enabled;
}
else
{
Services.RemoveService(typeof(ICamera));
Services.AddService(typeof(ICamera, freeCam);
freeCam.Enabled = !freeCam.Enabled;
staticCam.Enabled = !staticCam.Enabled;
}
}
base.Update(gameTime);
}
}
The StaticCamera takes only input by mouse (you can rotate the camera), the FreeCamera can also moved by keyboard input. When I call the method above (by pressing C on the keyboard) the FreeCamera class gets deactivated but the viewport seems frozen and does not react to any input. When I call the method again after a short time the FreeCamera gets activated again and everything works as expected.
Now I have 2 questions regarding this:
Is it possible to change the service
provider of a game service in the
game loop?
Is there a better approach
to handle different camera types in a
game and switch between them easily?
Thanks in advance for any help.
Like you answered, use a camera manager. It acts as both a factory and a container for the current camera. The manager you can register as a service. Manager would look something like this:
public class CameraManager
{
private Dictionary<Type, ICamera> _cameras;
private ICamera _current;
public ICamera Current
{
get
{
return _current;
}
}
// Sets the current cammera to the internal instance of the camera type
public void SetCurrent<T>() where T : ICamera
{
if (!_cameras.ContainsKey(typeof(T)))
{
// TODO: Instantiate a new camera class here...
}
_current = _cameras[typeof(T)];
}
}
This is just rough code - would need to be filled in more. One limitation is you can only have one camera per type. Giving cameras a string name, or an enum flag would let you toggle between an arbitrary number of cameras.
Thanks for the tip. I just wrote the code down from my head without my IDE at hand, so please do not look too much into syntax errors etc.
In my game I'm using wrapper classes for the input. The code is just a brief example of the problem - how to substitute a game service if both classes are using the same interface.
My new idea: I could use a "manager" class (like CameraManager in this case) which has the following methods
public void SetCameraType(CameraType type) //CameraType could be an enum
public ICamera GetCamera()
and then put the manager class into the service (with its own interface like ICameraManager).
Edit: this was considered as an answer to the comment above ... but it seems I clicked the wrong button - sorry
I think if you left off the code about adding and removing the service in the Update you'd be good and added lines changing the Visible property. The Enable property effects calls to Update, but the Visible property effects calls to Draw.
So I'd suggest the Update look like this:
protected override void Update(GameTime gameTime)
{
var keyboard = Keyboard.GetState();
if(keyboard.IsKeyDown(Keys.C))
{
if(freeCam.Enabled)
{
freeCam.Enabled = false;
freeCam.Visible = false;
staticCam.Enabled = true;
staticCam.Visible= true;
}
else
{
freeCam.Enabled = true;
freeCam.Visible = true;
staticCam.Enabled = false;
staticCam.Visible= false;
}
}
base.Update(gameTime);
}