Doubts about drawing to specific areas

kftX

Member
Hello everyone, GMS newbie here and I have a question that 1h+ of google under different terms doesn't seem to help. Hopefully someone knows/is able to help me in what I want to do, if not, I'll move on to a different concept. In this case, it would be a text-based game (think old style text adventures).

photo_2021-01-11_18-58-49.jpg
(1 is Viewport 1 and 2 is Viewport 2)

As you can see this game area is split into 3 different areas. My idea is that 1 would be the narration area where the text would be shown to the player. 2 would be a clickable GUI area with choices.

As you can probably see I created various viewports so that each would "house" its one specific part of the game area/GUI. Think of them as containers. The doubt I have is that no matter how much I search around on the internet I can't seem to find a way to make objects stay constrained within 1 or 2. If I drag the object with the draw text I created it'll just appear at the 100, 100 coordinate relative to Viewport 0 rather than Viewport 1.

Screenshot 2021-01-11 190907.png



So my question basically is:

Is there any way to make objects "spawn" within a specific Viewport and staying constrained within that area, or is there a better way to achieve what I want to do? What am I missing? I even tried creating specific instances for this but I have no idea how to use those instances and make them useful.

If anyone could explain to me what I'm doing wrong, that would be amazing.

Thanks in advance :)
 

Nidoking

Member
The viewport/camera has two important components: The port is where it appears on the game window, which is what you have in your picture. The view is the portion of the room that's shown within that port. Just put whatever's supposed to be in each port in different parts of the room, set the views accordingly, and do whatever you need to do to keep those instances in the view.
 

Kaliam

Member
Hello everyone, GMS newbie here and I have a question that 1h+ of google under different terms doesn't seem to help. Hopefully someone knows/is able to help me in what I want to do, if not, I'll move on to a different concept. In this case, it would be a text-based game (think old style text adventures).

View attachment 37014
(1 is Viewport 1 and 2 is Viewport 2)

As you can see this game area is split into 3 different areas. My idea is that 1 would be the narration area where the text would be shown to the player. 2 would be a clickable GUI area with choices.

As you can probably see I created various viewports so that each would "house" its one specific part of the game area/GUI. Think of them as containers. The doubt I have is that no matter how much I search around on the internet I can't seem to find a way to make objects stay constrained within 1 or 2. If I drag the object with the draw text I created it'll just appear at the 100, 100 coordinate relative to Viewport 0 rather than Viewport 1.

View attachment 37015



So my question basically is:

Is there any way to make objects "spawn" within a specific Viewport and staying constrained within that area, or is there a better way to achieve what I want to do? What am I missing? I even tried creating specific instances for this but I have no idea how to use those instances and make them useful.

If anyone could explain to me what I'm doing wrong, that would be amazing.

Thanks in advance :)

So as Nidoking said, viewports are "where it appears on the game window" which means what your doing with them is right! But in order to get each viewport to show something different, you need to create new cameras that are looking at a different parts of the room. This is where things start to get a bit complex as you'll have to use some code to create your cameras and either make them look at a static location or move them to the location you want that part of your game to appear.

The below code shows you how you could define a simple camera matrix and then apply it to your view. The view matrix of your camera defines what the camera is viewing and the direction that it is viewing it. For this example the camera is just pointing directly at our room at a specified x and y position. The projection matrix defines the size of the camera's view, so you would match the width and height of this to the size of the view area you want to see. After all that you then tell the camera to use these matrixes and then tell your view to use this camera. Then you can change the view matrix to move this camera anywhere in your room, so you can specify an area of coordinates in your room as the position for that kind of content.

GML:
//create a new camera
camera = camera_create();

//Build a new view matrix for our camera
var vm = matrix_build_lookat(x, y, -100, x, y, 0, 0, 1, 0);

//Build a new projection matrix for our camera
var pm = matrix_build_projection_ortho(width, height, -100000, 100000);

//Update the camera with the new settings
camera_set_view_mat(camera, vm);
camera_set_proj_mat(camera, pm);

//apply the new camera to the view you specified
view_set_camera(myView, camera);
That said, a much simpler solution to your problem I think would be to just use surfaces!

All you need to for this part is create surfaces of the size you need for each section, so like 600x400 or whatever resolution. Then, when you want to draw some objects to that "Part" of your room specifically, target it and it will only appear there. Then just create three of these with the sizes you want, and when your done drawing to them, just render them to the screen like a sprite in the locations on screen that you want.

One other benefit of doing this other than making things less complex is you can treat each surface as if the where using the same coordinates. When you target a surface, by default the top left corner will always be x = 0, y = 0. In this way, every surface you create is basically a canvas on which you can draw whatever you like, and then you can place that canvas wherever you want on your game screen.

GML:
CREATE EVENT:
mySurface = -1;

DRAW EVENT:
//test to make sure the surface exists, this must be done for every surface
if(!surface_exists(mySurface)){

    mySurface = surface_create(width, height);
}

//target the surface so that anything drawn will be drawn to it instead of the main game
surface_set_target(mySurface);

    /////Draw all your objects in here with coordnates (x = 0 to width) and (y = 0 to height)/////

surface_reset_target();

//now draw the surface to any screen location you want
draw_surface(mySurface, x, y);
Then you can just do that for any additional areas you want to have.

Hope that helped!
 

kftX

Member
The viewport/camera has two important components: The port is where it appears on the game window, which is what you have in your picture. The view is the portion of the room that's shown within that port. Just put whatever's supposed to be in each port in different parts of the room, set the views accordingly, and do whatever you need to do to keep those instances in the view.
So that's how it works! I kind had got it but that breaks it down a lot better.

So as Nidoking said, viewports are "where it appears on the game window" which means what your doing with them is right! But in order to get each viewport to show something different, you need to create new cameras that are looking at a different parts of the room. This is where things start to get a bit complex as you'll have to use some code to create your cameras and either make them look at a static location or move them to the location you want that part of your game to appear.

The below code shows you how you could define a simple camera matrix and then apply it to your view. The view matrix of your camera defines what the camera is viewing and the direction that it is viewing it. For this example the camera is just pointing directly at our room at a specified x and y position. The projection matrix defines the size of the camera's view, so you would match the width and height of this to the size of the view area you want to see. After all that you then tell the camera to use these matrixes and then tell your view to use this camera. Then you can change the view matrix to move this camera anywhere in your room, so you can specify an area of coordinates in your room as the position for that kind of content.

GML:
//create a new camera
camera = camera_create();

//Build a new view matrix for our camera
var vm = matrix_build_lookat(x, y, -100, x, y, 0, 0, 1, 0);

//Build a new projection matrix for our camera
var pm = matrix_build_projection_ortho(width, height, -100000, 100000);

//Update the camera with the new settings
camera_set_view_mat(camera, vm);
camera_set_proj_mat(camera, pm);

//apply the new camera to the view you specified
view_set_camera(myView, camera);
That said, a much simpler solution to your problem I think would be to just use surfaces!

All you need to for this part is create surfaces of the size you need for each section, so like 600x400 or whatever resolution. Then, when you want to draw some objects to that "Part" of your room specifically, target it and it will only appear there. Then just create three of these with the sizes you want, and when your done drawing to them, just render them to the screen like a sprite in the locations on screen that you want.

One other benefit of doing this other than making things less complex is you can treat each surface as if the where using the same coordinates. When you target a surface, by default the top left corner will always be x = 0, y = 0. In this way, every surface you create is basically a canvas on which you can draw whatever you like, and then you can place that canvas wherever you want on your game screen.

GML:
CREATE EVENT:
mySurface = -1;

DRAW EVENT:
//test to make sure the surface exists, this must be done for every surface
if(!surface_exists(mySurface)){

    mySurface = surface_create(width, height);
}

//target the surface so that anything drawn will be drawn to it instead of the main game
surface_set_target(mySurface);

    /////Draw all your objects in here with coordnates (x = 0 to width) and (y = 0 to height)/////

surface_reset_target();

//now draw the surface to any screen location you want
draw_surface(mySurface, x, y);
Then you can just do that for any additional areas you want to have.

Hope that helped!
Thank you so much! That's exactly what I wanted! It worked perfectly to create the three areas!

I had considered the possibility of surfaces but since I'm very new to this an just grasped viewports, I thought it could've been the solution I wanted. Your idea with surfaces works just as good but removes the possible performance overhead of running three different viewports/cameras. Amazing! Can't thank you enough for having gone to the trouble of typing all that with those useful comments so I could interpret/implement quickly!! :D

You're a hero :D
 

Yal

🍋 *lemon noises*
GMC Elder
view_current could also be useful to constrain drawing to only one viewport. E.g. if something should only be drawn in view 0 and not the others:
GML:
//Draw event
if(view_current != 0){
  exit;
}
/* the rest of the event goes here */
 
Top