• Hey Guest! Ever feel like entering a Game Jam, but the time limit is always too much pressure? We get it... You lead a hectic life and dedicating 3 whole days to make a game just doesn't work for you! So, why not enter the GMC SLOW JAM? Take your time! Kick back and make your game over 4 months! Interested? Then just click here!

Legacy GM [SOLVED] Can't change view_xport and view_yport in code

K

Kyuraan

Guest
Hi, i wanted to write a function, where the player can use a rifle scope. I tried to do this with a second view, which "stretches" the view_port. And it looks like this:


It works so far, but i wanted the view_xport[1] and view_yport[1] to be set to the mouse x and y coordinates, which doesn't work for some reason. The second view_port just stays in the position, that was set in the room editor, which is in the middle of the display right now.
I tried this:

if view_current == 1{
view_xport[1] = mouse_x
view_yport[1] = mouse_y​
}

Well it does move IF i do NOT use the if statement:

if view_current == 1{
}

But then it affects both views and ends up in a total mess on the display. So i have to seperate them, but then it doesn't move at all.
I tried to change the values by increasing by 1 every step or just set a random number for the xport and yport in code. It always stays in the position that was set in the room editor.

Has anyone an idea or can explain why that is?
 

obscene

Member
Never used multiple views, so no advice on that, but as an alternative idea have you tried simply redrawing the application surface with draw_surface_part_ext() in the draw GUI event? Might be easier.
 

TheouAegis

Member
Why are you setting the top left corner of the scope to the mouse?

Code:
if mouse_check_button(mb_right) {
    view_xview[1] = median(window_view_mouse_get_x(0) -(view_wview[1]>>1),view_xview[0]+(view_wview[1]>>1),view_xview[0]+view_wview[0]-view_wview[1]);//mouse_x-(view_wview[1]>>1);//
    view_yview[1] = median(window_view_mouse_get_y(0)-(view_hview[1]>>1),view_yview[0]+(view_hview[1]>>1),view_yview[0]+view_hview[0]-view_hview[1]);//mouse_y-(view_hview[1]>>1);//
    view_xport[1] = median(window_mouse_get_x()-(view_wport[1]>>1),0,view_xport[0]+view_wport[0]-view_wport[1]);
    view_yport[1] = median(window_mouse_get_y()-(view_hport[1]>>1),0,view_yport[0]+view_hport[0]-view_hport[1]);
    view_visible[1] = true;
}
else view_visible[1] = false;
A couple things going on here. First, the view's position in the room is relative to mouse_x, but that only works when there's only one view active; since we will have two views active, we need to specify view[0] as the primary view, so we use window_view_mouse_get_x/y; but the view's position in the window is relative to window_mouse_get_x/y. Second, you need to make sure the view stays within the window, which was defined by view[0], so we restrict port[1] to stay within port[0]. Third, we need to make sure the view doesn't leave the visible world (okay, this is optional), so we restrict the position of view[1] to stay within view[0]. Fourth, this is all done in the Step Event. You don't want to mess with views as they are being drawn, but the difference is usually unnoticeable; I just put it out there so you don't cause unforeseen issues later.

Update: I decided for my own sake to take it further. There are demos of sniper scopes out there, but I wanted to see if I could figure it out for myself. I will admit, I cheated a bit and googled some tips. lol

You could do a simple blacked-out camera lens effect where only the scope is visible, kind of like how you'd play Silent Scope. You can't just disable view[0], though, as that will stretch out view[1]. What you can instead do is in the Draw End event check if view_visible[1] is true and if view_current is 0. If both conditions are met, call draw_clear(0) to black out the screen. This will only affect the contents of view[0], while view[1] will still be drawn as normal. You could then add another check if view_current is 1 to have it draw optics around the view so it doesn't look like a plain square.

Alternatively, you can draw view[1] to a surface using view_surface_id[1]=surface where surface is some surface you created. When you go into sniper mode, check if the surface exists and create it if it doesn't; then set view[1] to draw to that surface. In the Draw GUI event, adjust the blend mode, draw a circle, adjust the blend mode again, draw the view surface, then reset the blend mode back. Then go ahead and draw whatever else you want, such as the scope's optics. This was the code I used to do that:
Code:
if surface_exists(crosshair)
{
    var xx = device_mouse_x_to_gui(0),
          yy = device_mouse_y_to_gui(0);
    draw_set_blend_mode(bm_subtract);
    draw_circle(xx,yy,64,0);  //the size of your scope
    draw_set_blend_mode_ext(bm_inv_dest_alpha,bm_dest_alpha);
    draw_surface(crosshair,xx-(view_wport[1]>>1),yy-(view_hport[1]>>1));
    draw_set_blend_mode(bm_normal);
    draw_sprite(spr_SniperScope,0,xx,yy);
}
 
Last edited:
K

Kyuraan

Guest
Thanks for your responses. I used TheouAegis' first code with some changes. Now it works exactly as i wanted. This is how it looks now:


I added some wiggling to it and draw a black circle to the player in the scope view, because you couldn`t see yourself throught the scope.
 
Top