0

I'm new here! I searched internet a lot for my question, but I didn't found anything - or I'm really thinking wrong.

I program on VB.NET since 2 years, and on XNA since 6 months. I built a game and an editor for the game, and they are running great.

The question i about my editor (for an RPG game), and I'll try to explain at my best.

I have a main form with menustrips on top and a big picturebox covering the entire form, a picbox that is binded to the Game1 object when it start with the command Run().

The Game1 object handles two classes, that are basically panels that it draws on the picbox of the main form: a tileset panel in the left down the tabpage, and a map panel on the right. This works perfectly.

The problem is when for the first time yesterday I tried to draw with XNA on a form. I have multiple forms to manage NPCs, equipment, conditions, events, variables, etc and in the event form, I have a tabpage that manages map teleport events. On this tabpage I have a list of maps and a picbox where I want to draw a small view of the selected map. For this, I created of course a minimap panel with it's own draw and update methods.

...but of course, the minimap appears on the main form on the normal map.

I tried to change in real time the DeviceWindowHandle, but I failed... apparently, it changes only during the Run()

I tried to create a new game object and binding him to the event teleport form, but in the moment of lunching the Run() of this object, the debugger stops saying that I cannot launch more that one game loop in a thread.

I can't believe that XNA doesn't let to draw multiple things on different forms... and I can not pause the main loop from the event form (which is called from the NPC form) to start the minimap loop!

I think that is something really easy that unfortunately I don't know... I'm getting crazy and lost... what I can do? Please help me, thanks!!

Luke85
  • 11
  • 4
  • What you'll need to do is make a game for each window, and move objects between each game. And yes, you'll need to create several threads to have several games running at the same time. Which is why you'll need to move objects between these threads (by 'lock') – Falgantil Feb 18 '15 at 11:39
  • But how I can do this? – Luke85 Feb 18 '15 at 11:48
  • Well, launch 1 Task for the main editor window, and another Task for each toolbox, and each of these tasks will run a Game. Of course the code for these games will not be similar. The one being used for Toolboxes might, if you separate things properly enough. You'll need to feed each new Game the IntPtr handle for the PictureBox on each Toolbox you make. – Falgantil Feb 18 '15 at 12:19
  • I never used Task... can you show me an example code? Thank you very much...!!! – Luke85 Feb 18 '15 at 12:23

2 Answers2

0

All you want show to the player you need draw in the game window. You have one Game with one GraphicsDevice and by default all you draw will be rendered on the game window. But you can call GraphicsDevice.SetRenderTarget method to change render target. Call it with RenderTarget2D object as parameter and anithing you will draw after this will be rendered to that render target. Next you need call GraphicsDevice.SetRenderTarget(null) to set game window as render target again.

There is my (uncompleted yet) custom GUI realization for XNA. I hope it can help you.

Update

class Game1 : Game
{
    GraphicsDevice graphicsDevice;
    SpriteBatch spriteBatch;

    public RenderTarget2D MinimapRenderBuffer;
    public RenderTarget2D AnotherRenderBuffer1;
    public RenderTarget2D AnotherRenderBuffer2;

    public EventHandler RenderBuffersUpdated;

    void Initialize()
    {
        // Better initialize them only once, don't do it in Draw method
        this.MinimapRenderBuffer = new RenderTarget2D(this.graphicsDevice, 100, 100); // any size you want
        this.AnotherRenderBuffer1 = new RenderTarget2D(this.graphicsDevice, 50, 50);
        this.AnotherRenderBuffer2 = new RenderTarget2D(this.graphicsDevice, 500, 500);
    }

    void Draw()
    {
        this.graphicsDevice.SetRenderTarget(this.MinimapRenderBuffer);
        // draw minimap to MinimapRenderBuffer

        this.graphicsDevice.SetRenderTarget(this.AnotherRenderBuffer1);
        // draw whatewer to AnotherRenderBuffer1

        this.graphicsDevice.SetRenderTarget(this.AnotherRenderBuffer2);
        // draw whatewer to AnotherRenderBuffer2

        this.graphicsDevice.SetRenderTarget(null);
        // now draw to screen

        if (this.RenderBuffersUpdated != null)
        {
            RenderBuffersUpdated(null, null);
        }
    }
}

And use rendertargets in your editor when event raised. And you can convert them to bitmaps.

Community
  • 1
  • 1
  • In the game I have no problem, since I use only one form. The problem is in the editor: I have several forms (you know, to manage equipment, events, etc). In my project the render target is a map backbuffer and that works fine (i want to draw the same map, only small!), my problem is not to draw in another backbuffer\rendertarget, but is the phisical place to draw the same backbuffer\rendertarget (not the main form picturebox, but the event forum picture box). How can I do this? Thank you ^_^ – Luke85 Feb 18 '15 at 12:05
  • Sorry, I can't imagine your app. Can you provide some screenshots? –  Feb 18 '15 at 12:55
  • Never mind, I'm figured it now. Maybe. If you need draw several different images from one game you can prerender them in Draw() and raise event for whole application. Then each window grab one of prerendered textures and draw it. What a broblem? –  Feb 18 '15 at 13:03
  • Seems a nice idea! But how I can use the Draw code - ie: Globals.SpriteBatch.Draw(Textures.Gradient, New Rectangle(PosX, PosY, Width, Height), Color.Gray) - to draw into an image instead of into the rendertarget? – Luke85 Feb 18 '15 at 16:07
  • Here it is a screenshot! [link](https://www.dropbox.com/s/q9af5hqfmdc6j9k/editor.jpg?dl=0) – Luke85 Feb 18 '15 at 16:13
0

Here's an example of what I commented (Sorry it's in C# but I don't really write VB.Net. Translating it should be pretty straight forward though):

private MainGame mainGame;
private ToolboxGame toolbox1;
private ToolboxGame toolbox2;

// And this should be put in some Form Initialization method:

Task.Factory.StartNew(() => {
        this.mainGame = new MainGame(imgEditorPictureBox.Handle)
        this.mainGame.Run();
    }
Task.Factory.StartNew(() => {
        this.toolbox1 = new ToolboxGame(toolbox1PictureBox.Handle)
        this.toolbox1.Run();
    }
Task.Factory.StartNew(() => {
        this.toolbox2 = new ToolboxGame(toolbox2PictureBox.Handle)
        this.toolbox2.Run();
    }

Something like that should do it. Obviously whenever you "move" variables from one "game" to another, keep in mind that they run on different threads, so anywhere you use it, you'll need to

lock (dummyObject)
{
    // Use data
}

to make sure you're not accessing it in one game, while the other is trying to set it.

Locking in VB.Net: Is there a lock statement in VB.NET?

You'll obviously need to come up with some smart infrastructure to get this working smoothly, but since you've made a game and editor before, I'm sure this should not prove a humongous challenge.

Community
  • 1
  • 1
Falgantil
  • 1,290
  • 12
  • 27