Using InputListeners and Boxing Viewport Adapter. When I change window size everything works, Gaphics is resized, mouse tracking is properly translated and boxing viewport is correct. However when I resize window with fullscreen button, the mouse tracking does not translate. What am I missing?
Thanks
I think it’d help if you posted some sample code, preferably a new project that demonstrates the issue without any extra code your project may have.
One thing that occurs to me though is that if you are doing any kind of scaling in your render, you’ll need to perform some kind of screen to world translation to get your raw mouse coordinate into your world. When you change the window size, are you scaling all your graphics to fit, or are you just drawing to the space unscaled?
Are you familiar with Monogame.Extended?
I am using the BoxingViewportAdapter and scale graphics and mouse tracking in my input class.
Also using Monogame Windows assembly. When I originally implemented this code there seemed to be some differences between the Windows & GL assemblies.
When I change the window size the OnClientSizeChanged event is raised in the BoxingViewportAdapter but when I click on the fullscreen button of the window OnClientSizeChanged event is not raised. I don’t see an event for fullscreen anywhere. Is there a fullscreen event that I can raise to fix this error?
As regards SOLID, I have tried to implement these methods in my code. However, I keep running into the limitations of C# and don’t know how to fix them. I would like to pass a game class to all my library classes. For example, I have a SpriteBatch in my Game class that I want to access in my library classes. It is easy to pass this as a parameter but my library class project can’t decode any fields or attributes because they are only known in the game class project.
It would be nice to have examples of SOLID in C# code. The terminology is very confusing.
Hope you understand what I am driving at.
Thanks.
Oh sorry, I’m not familiar with MonoGame.Extended. I’ve heard of it, but I haven’t used it. I actually would expect that OnClientSizeChanged event to be raised. Having said that, you do have the option of wrapping BoxingViewportAdapter in your own class so that you can do whatever you need to do, then do whatever you need BoxingViewportAdapter.
I don’t know what BoxingViewportAdapter contains, but for the sake of argument lets just assume it’s a class that has a single property on it, IsFullscreen, which has get and set implemented. I can then do…
public interface IViewportAdapter
{
event EventHandler<EventArgs> FullscreenChanged;
bool IsFullscreen { get; set; }
}
public class ViewportAdapterImplementation : IViewportAdapter
{
private BoxingViewportAdapter _wrappedObject = null;
public ViewportAdapterImplementation(BoxingViewportAdapter wrappedObject)
{
_wrappedObject = wrappedObject ?? throw new ArgumentNullException();
}
protected virtual void OnFullscreenChanged(EventArgs e)
{
if (this.FullscreenChanged != null)
this.FullscreenChanged(this, e);
}
#region IViewportAdapter Implementation
public event EventHandler<EventArgs> FullscreenChanged;
public bool IsFullscreen
{
get { return _wrappedObject.IsFullscreen; }
set
{
if (value != _wrappedObject.IsFullscreen)
{
_wrappedObject.IsFullscreen = value;
OnFullscreenChanged(new EventArgs());
}
}
}
#endregion
}
Now if I want to use this in my game, I might make the constructor take an instance of IViewportAdapter.
public class MyGame : Game
{
private IViewportAdapter _viewportAdapter = null;
public MyGame(IViewportAdapter viewportAdapter)
{
_viewportAdapter = viewportAdapter ?? throw new ArgumentNullException();
}
}
Then when I instantiate it, I might do something like…
var game = new Game(new ViewportAdapterImplementation(new BoxingViewportAdapter()));
In doing this, I’ve abstracted BoxingViewportAdapter away and can simply interact with IViewportAdapter. All the functionality is still there, because I’ve wrapped it (some advice, only wrap what you use, then extend as you use more), but also if I want to change that functionality I can just create a new implementation of IViewportAdapter and give that to MyGame instead. In addition, I now have an event that gets fired when we change from fullscreen to not fullscreen and back again, so I can now check the value and do things when that happens… which sounds like something you might be after.
This is also an example of solid code, exhibiting Liskov Substituion and Dependency Inversion.
Regarding you not being able to pass as SpriteBatch to other classes, you should be able to. If those classes are in another project, you just need a reference to MonoGame and they will be able to take it as a parameter without issue. You’re then free to use them in your other classes as inputs. I do this in my own project… my game entities take a SpriteBatch object that they will use for drawing in as a constructor parameter, then use it during drawing.
For my own purposes, the project I’m currently working on, one of my goals is to ensure that everything is unit tested, so I’ve taken it a step further. Similar to above, I’ve created interfaces for all of the MonoGame functionality I use, then implemented those interfaces as a very simple, dumb wrapper object. Then when I create my entry point, I just instantiate those wrapper objects and give them to my game. This lets me mock everything so I can write a good unit test… but you don’t really need to go that far if you don’t want to
Let me know if that makes sense and if you have any other questions about SOLID, let me know and maybe we can come up with a few more examples to examine together.
I think I need to break this down into smaller steps.
In Monogame Windows is there an event for Fullscreen when the max button is pressed? I can’t find anything and it does not raise the ClientSizeChanged event.
When I have solved this issue, I can start to understand wrappers and interfaces.
Thanks.
I think I see what the problem is. I didn’t realize that when you said fullscreen, you meant maximizing the window
Yes, I’m seeing the same issue you are now. When you resize with the window handles, you get the event, but when you resize by clicking the maximize button, you don’t. Looking closer, when you hit the maximize button, it looks like it scales your screen up… which is why you’re seeing that discrepancy in the mouse tracking.
I found this bug report via a Google search…
It suggests that it’s been fixed, but it hasn’t been released yet. You’ll need to wait for MonoGame 3.7, or build the current version in the development branch. The only workaround I can offer you is, if you’re only going to work on the Windows platform, get a System.Windows.Forms.Form from your game’s Window.Handle property, then subscribe to that SizeChanged event.
Here’s an example…
using WinForms = System.Windows.Forms;
/// <summary>
/// This is the main type for your game.
/// </summary>
public class Game1 : Game
{
...
public Game1()
{
_graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
this.IsMouseVisible = true;
this.Window.AllowUserResizing = true;
WinForms.Form f = (WinForms.Form)WinForms.Form.FromHandle(this.Window.Handle);
f.SizeChanged += (sender, e) => System.Diagnostics.Debug.WriteLine("Resize occurred!");
}
...
}
When I tested this code, I was able to see the debug statement.
Thanks, I think I’ll wait because I want to eventually make my game portable to run on other platforms.
Regarding passing a Spritebatch, maybe I didn’t explain it correctly.
I have 2 projects, a Game project and a Library project. I reference the Library project in my game project. All Library classes are known to the game project. However any classes in the Game project are not known to the library project unless passed as a parameter.
Example:
PlayScreen Class is based on Screen
In game project:
public PlayScreen(GameRoot game)
: base(game)
{
}
In Library project:
public Screen(Game game)
: base(game)
{
}
As you can see the game class GameRoot is passed as Game to the Screen class. Any properties that are in GameRoot that are not in Game are unavailable to Screen. If we were to reference the game class in the Library class we get a circular reference.
How do we get around this?
Further, I would like to make all the viewport properties available to the screens. What is the best way to do this.
Thanks.
You can pass it directly. A lot of it depends on how you structure your code, but if your Screen needs an instance of SpriteBatch to do work, give it that instance.
public Screen(Game game, SpriteBatch spriteBatch)
{
...
}
public PlayScreen(GameRoot game, SpriteBatch spriteBatch)
: base(game, spriteBatch)
{
...
}
// In some GameRoot object which has a SpriteBatch named mySpriteBatch
var playScreen = new PlayScreen(gameInstance, mySpriteBatch);
Same deal, give the screen an instance of viewport that it can use to do work. Constructor injection is fairly common and an easy way to get dependencies into your objects. Keep an eye out though… sometimes you find your constructors growing. If you think it’s starting to get unreasonable you can explore other options, such as using a dependency container. You can also pass dependencies in as method parameters, typically if they’re single use and not used anywhere except that method. Kinda one of those things you do by feel… at least for me. Others may have better ideas
The nice thing about dependency injection though is it makes your code much easier to unit test since you don’t need to worry about staging anything. Everything your object needs is given to it, it doesn’t have to get it from anywhere.
Not sure I am explaining the problem correctly.
Let’s suppose GameRoot has a definition for mySpriteBatch. and there is a custom class CustomSpriteBatch both in the game project.
Then:
public PlayScreen(GameRoot game, CustomSpriteBatch spriteBatch)
: base(game, spriteBatch)
{
…
}
Now:
In library project
public Screen(Game game, SpriteBatch spriteBatch)
{
...
}
game.mySpriteBatch raises an error because mySpriteBatch is not defined in library project.
Similarly,
spriteBatch cannot be downcast as CustomSpriteBatch because CustomSpriteBatch is only known in the game project.
One can use reflection by referencing the types in the game project but this gets messy and contravenes the rule of good coding.
So, how do you reference these properties in the library project?
If you’ve created another class to wrap SpriteBatch and provide other functionality, you’ll need to move that to either the same library that Screen is in, or a completely separate library that both of them can reference.
If you absolutely do need to have CustomSpriteBatch defined in the same library as PlayScreen, but still used by Screen, create an interface (ICustomSpriteBatch) that defines all the functionality you plan to use and let both reference that instead.
I have many examples of this and I find myself moving classes between projects to get the solution to compile.
It also seems that Microsoft get around this problem in .net. How do they do it?
I have a dozen controls, buttons, forms, textboxes, etc. based on Control. In my game I have a control tree. ScreenManager, Screens, Forms, Controls and sub-controls in the tree. Each parent calls a child to initialize, update and draw. But because of this problem the child does not have access to any properties of the parent unless it is in the same project and then can be downcast.
For example:
When the Form changes its state i.e. minimized, maximized then the controls need to know this. The properties of the Form are unavailable to the control unless they are in the same project. Consequently, I have put all the classes in a library which kind of defeats the purpose of a library.
I would like to make the library transportable. But, if I put specific game logic in the library that is no longer possible.
Is there a description of game design that shows how this can be accomplished?
Are you aware that I live in Calgary?
I would definitely suggest you look into and become more experienced with using interfaces in your code. This will definitely help you solve the issue you’re running into right now. Your children, defined in Project A, should be able to interact with an interface that you implement in project B.
Let me try to create an example using what you have described so far…
Lets say you have defined Button, which inherits from Control, in one project…
public class Control { }
public class Button : Control { }
Then in another project, you’ve defined Form which stores a list of Controls. Then, in your game Initialize, you add a Button to it…
public class Form
{
public event EventHandler<EventArgs> FormResized;
public List<Control> Controls { get; private set; } = new List<Control>();
public void TriggerFormResized()
{
if (this.FormResized != null)
this.FormResized(this, new EventArgs());
}
}
public class MyGame : Game
{
private Form _form = new Form();
public Initialize()
{
_form.Controls.Add(new Button());
_form.TriggerResize();
}
}
If I’m reading you correctly, this is an example of where you’re at now. We’ve created a form that can trigger some kind of resize event, but Button can’t know about it because Form is defined in another project which cannot be referenced since the Form project already references the Button project.
This is where you can use an interface to define what is available on a Form. You’re effectively creating a contract where you’re saying “Hey, anybody who implements this interface… I don’t really care what other things you do, but you will at least provide these things.”
So, in the project that defines button (or some project below that in the hierarchy), we can define an interface for Form which says that it has an event on it, FormResized.
public interface IForm
{
event EventHandler<EventArgs> FormResized;
}
Now, we can give an instance of IForm to Button, so it can do things.
public class Button : Control
{
private IForm _parent;
public Button(IForm parent)
{
_parent = parent ?? throw new ArgumentNullException();
_parent.FormResized += (sender, e) => System.Diagnostics.Debug.WriteLine("Parent form has resized!");
}
}
Now, we just have Form inherit from the interface…
public class Form : IForm
{
// All the other stuff
}
Now, in the example game above, when we tell Form to trigger a resize event, button will know about it.
Obviously this is a contrived example, but hopefully you get what I mean
No, that’s cool How long have you lived here?
Out of curiosity, how did you know I do?
I did a search for Gary Texmo on the web
Maybe we can meet up and you can tutor me in person?!
lionelthomas46(at)gmail(dot)com
Cheers.
Ahhh you googled me, cool That’s a little out of date, though I would appreciate it if you’d take my personal information out of this forum post. Make others google me as well
I don’t know that I’m comfortable taking on any kind of personal, one on one tutor role at this time, but I’m happy to try to help out here! Have a read on my previous post above and let me know what you think. Have you any experience working with interfaces?
That’s OK, I just thought we were getting off topic and there was a better way to communicate i.e via email.
I think I understand interfaces and have used them although not too extensively. I still don’t see how this solves the compiler reference problem. If Form is in the game project and control is in the library project, then how does one reference the properties of Form in Control in the library project whether through a derivation or an interface?
All good The benefit of a thread like this is that others coming along looking for similar help can benefit from what we’ve written here.
Just linking to this for clarity. I wish there was a way to make it not preview it >.<
In this example, Control references the properties of IForm, not Form (though Form also provides that property). Form simply implements the interface, satisfying the contract that IForm has established. Control (or Button) doesn’t interact with Form directly, it does it via the interface. Because you define IForm in the library, Control (or Button) knows what it can do.
You should be able to set up exactly the scenario I described in that thread. Give it a try in projects separate from your actual game. I know for me, sometimes it really helps to isolate things in a different environment to remove the distractions. Then you can play in that isolated sandbox and not have to worry about anything except what you’re focusing on learning.
Thanks, I use interfaces in many places in my game in particular in the InputHandler(). The game doesn’t care how the handler implements the mouse actions like LeftButtonPressed in just uses the function. So if I change the way the handler works the rest of the I/O works just fine as long as the contract is abided by.
The interface works well provided no custom classes that are defined in the game project are passed in the interface. So my game class GameRoot cannot be passed in the interface because it is not known in the Library project. However the XNA Game class can because it is known in both the game and library projects.
So, I still don’t see how to get around this reference problem.