Multiple Viewports on the one screen

Hi All,
This is my first post here and am happy to be a member of your forum. I am not new to Programming but am very new to Mono game. I expect this has been asked before, however.
I am using C# and am beginning an old school style Star Trek game and cant seem to find a tutorial that shows me how I can have multiple clipped viewports within the one game. Obviously a Star Trek Game needs for example a scanner screen, an on screen area to send maps or star fields to, whatever I can come up with. Can any of you good folk point me in the direction of a suitable tutorial or example?

Thank you for your time.

Something like this…

I think you should look at Nez and Myra. They have full UI frameworks, with viewports and widows and UI and focusing. Myra is a bit like WPF, which might be useful if MAUI actually replaced xamarin and you are doing mobile . Nez and Myra shold work on any systems.

When I do this I usually use the RenderTarget2D class, drawing the separate areas to rendertargets first and then drawing the rendertargets to the screen. However it seems this can also be done with the ViewPort class as well.

A similar topic discussing this can be found here:

Also an example using Viewports can be found here (the XNA download might not work with MonoGame but the explanation and code should still be applicable):
http://rbwhitaker.wikidot.com/viewports-split-screen

Thank you all for your replies, I will have a look at them and see if I can nut it out.
Cheers

Hi folks,
Back again.

OK so I have started fresh and used the C# Mono game template and it runs and makes the basic full screen game window out of the box.

All Good,
so then I have begun to add the render target code line by line from HERE

All went well until I added…

_graphics.GraphicsDevice.SetRenderTarget(onScreen);

then it crashes, at this line on the Draw Method

With this exception

Clearly I am missing the point here :slight_smile: I do that quite a bit lol

I feel if I can nut out my error I can use the default C# template for the full screen window
and add render targets as needed I will be good to go.

Here is my code in full, it really is just the Vis Stud 2019 Mono game template with a few added lines from the link above,

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;

namespace Trek02
{
    public class Game1 : Game
    {
        private GraphicsDeviceManager _graphics;
        private SpriteBatch _spriteBatch;
        RenderTarget2D onScreen;

        const int onScreenWidth = 800;
        const int onScreenHeight = 400;


        //GraphicsDevice.SetRenderTarget(myRenderTarget1);
        public Game1()
        {
            _graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
            IsMouseVisible = true;
        }

        // TODO: Add your initialization logic here
        protected override void Initialize()
        {
            // Full Screen
            _graphics.PreferredBackBufferWidth = 1920;
            _graphics.PreferredBackBufferHeight = 1080;

            // on screen window 800 x 400
            var onScreenDevice = _graphics.GraphicsDevice;
            onScreen = new RenderTarget2D(onScreenDevice, onScreenWidth, onScreenHeight, false, onScreenDevice.DisplayMode.Format, DepthFormat.Depth24);
           
            
            
       //     mSpriteBatch = new SpriteBatch(device);


            _graphics.ApplyChanges();
            base.Initialize();
        }

        // TODO: use this.Content to load your game content here
        protected override void LoadContent()
        {
            _spriteBatch = new SpriteBatch(GraphicsDevice);

        }

        // TODO: Add your update logic here
        protected override void Update(GameTime gameTime)
        {
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape))
                Exit();


            base.Update(gameTime);
        }

        // TODO: Add your drawing code here
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.Silver);
          
            _graphics.GraphicsDevice.SetRenderTarget(onScreen); // <--- This is the line that kills all

            base.Draw(gameTime);
        }
    }
}

Sorry for the lengthy post, I think I was an ENT in a past life :slight_smile:

If you follow all the steps in that post it should work, but it won’t work with just that line on it’s own. Currently you are switching to an off screen rendertarget but are not switching back to the backbuffer for the final draw to the screen.

The line GraphicsDevice.SetRenderTarget(null) will be needed to unset the rendertarget before base.Draw.

Edit: Just to be clear the post I was referring to was by kosmonautgames where they posted this:

GraphicsDevice.SetRenderTarget(myRenderTarget1);

SpriteBatch.Begin();

… Draw

SpriteBatch.End();

GraphicsDevice.SetRenderTarget(myRenderTarget2);

SpriteBatch.Begin();

…

SpriteBatch.End();

//Backbuffer
GraphicsDevice.SetRenderTarget(null);

SpriteBatch.Begin();

//Draw renderTargets

SpriteBatch.Draw(myRenderTarget1, …);

etc.

SpriteBatch.End();

A render target is basically a texture2d. Using multiple render targets will come in handy for doing effects (lighting shadows etc) but it does come at a performance cost when switching between render targets (especially on computers with integrated graphics cards) so dont go using a seperate rendertarget for seperate components. Ideally a max of 5 or 6 through a frame draw would be the most you want to use.

A render target is also handy for scaling your game to different monitor sizes. Draw your game at 1920x1080 for example to a second rendertarget. Then scale that rendertarget to your monitor and add black bars if the asoect ratio is not 16:9

Also when creating a render target, if your planning on switching to it multiple times per frame, when creating it you can set it to preserve contents. (This also comes at a performance cost) switching to a render target will clear it

The set rendertarget by default is null. This means any drawing is done to the screen. So if you want to draw to another rendertarget at the start of the draw call you need to setrendertarget(YourRenderTarget)

Then once everythings drawn, you need to set the rendertarget back to null, so your drawing to the screen. Because a rendertarget is basically a texture2d, you can then call soritebatch.draw using YourRenderTarget as the texture2d

Regarding drawing things on seoerate parts of the screen for UI (windows displaying different parts of the game etc) viewports is the way to go. There is little performance cost, and viewports will also automatically clip any over draw. If you need some simple examples let me know and i can dig some up

If this is 2D you could probably get away with just clipping sprites you are drawing instead of multiple viewports.