• 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!

Altering the Camera Relative to the Player?

I've got a room that extends below the floor so I can have other rooms/regions underneath for purposes of hiding a secret and some other trickery with teleporting to small sub rooms without changing to a completely different game room. Because of how the camera centers on a followed object the blank space below the floor is visible and I was wondering if there's a way to alter where it sits relative to the player to conceal it when she's on the top level.

2021-02-25 (1).png 2021-02-25 (3).png
 

Tyg

Member
well if your warping to these secret areas you could drag them down below the grid or view area
i keep mine offscreen and use viewports
as to the bottom you can clamp the min/max you want to see
 
Set the camera yourself using the camera_set_view_pos() function and offset the y by an amount. :)
True, setting a static camera in the room and then having my controller object adjust relative to the player every step like I'm already doing with the background could work but I'm not 100% that would give smooth movement because the background that's set every frame can jitter a bit and I still have a found around for that

well if your warping to these secret areas you could drag them down below the grid or view area
i keep mine offscreen and use viewports
as to the bottom you can clamp the min/max you want to see
The issue more having the camera way lower than I want it to be where you can under the floor when she's standing on the ground
 

Nocturne

Friendly Tyrant
Forum Staff
Admin
True, setting a static camera in the room and then having my controller object adjust relative to the player every step like I'm already doing with the background could work but I'm not 100% that would give smooth movement because the background that's set every frame can jitter a bit and I still have a found around for that
It would be no different to using the default room camera follow options and should have nothing to do with backgrounds since they are not rendered in the same way at all. If you have issues, try changing the event it's set in, ie: begin step, end step, draw begin, draw end. Sometimes render order can cause a 1 frame lag so changing the event can resolve this.
 
It would be no different to using the default room camera follow options and should have nothing to do with backgrounds since they are not rendered in the same way at all. If you have issues, try changing the event it's set in, ie: begin step, end step, draw begin, draw end. Sometimes render order can cause a 1 frame lag so changing the event can resolve this.
That's good to know. I'll have to play around with which step event the background is being moved in to see if that fixes it.

I can't switch to drawing the background as a sprite because there has to be a background layer in the room behind the view to avoid graphical glitching as far as I can tell
 

Nocturne

Friendly Tyrant
Forum Staff
Admin
I can't switch to drawing the background as a sprite because there has to be a background layer in the room behind the view to avoid graphical glitching as far as I can tell
Yes and no... Basically, as long as there is SOMETHING behind everything else that draws over the entire view canvas before anything else then you're golden. For example, you can add a background layer that simply draws the colour black then use sprites over that. You can draw a sprite manually. You can draw a coloured rectangle in the draw begin step of an instance on a high draw layer... basically anything that covers the screen will clear the draw buffer as long as it's drawn before anything else.


EDIT: Also I suspect that your background issues are because your camera is moving in less than 1px increments and backgrounds cannot be at positions like x:100.25, only x:100 or x:101, so it gives a "stutter" to the movement. This can possibly be resolved by making the application surface double or tripple the actual view size so you're actually drawing 2, 3, or 4 pixels for every one "real" pixel. However this may also have side-effects that you don't want, eg "rotated" pixels...
 
Yes and no... Basically, as long as there is SOMETHING behind everything else that draws over the entire view canvas before anything else then you're golden. For example, you can add a background layer that simply draws the colour black then use sprites over that. You can draw a sprite manually. You can draw a coloured rectangle in the draw begin step of an instance on a high draw layer... basically anything that covers the screen will clear the draw buffer as long as it's drawn before anything else.
So if I just made a background layer with black selected that would be enough to fix the issue with garbage sprite data that's usually behind the background layer being visible?


EDIT: Also I suspect that your background issues are because your camera is moving in less than 1px increments and backgrounds cannot be at positions like x:100.25, only x:100 or x:101, so it gives a "stutter" to the movement. This can possibly be resolved by making the application surface double or tripple the actual view size so you're actually drawing 2, 3, or 4 pixels for every one "real" pixel. However this may also have side-effects that you don't want, eg "rotated" pixels...
I could add a function to my code to make sure it's rounding up to the nearest whole number before moving the background somehow.
 

Nocturne

Friendly Tyrant
Forum Staff
Admin
So if I just made a background layer with black selected that would be enough to fix the issue with garbage sprite data that's usually behind the background layer being visible?
Yes.

I could add a function to my code to make sure it's rounding up to the nearest whole number before moving the background somehow.
Nooooo... that's what I'm saying. GM automatically rounds the background x/y position which is possibly why you're seeing the issue you're seeing.
 
Nooooo... that's what I'm saying. GM automatically rounds the background x/y position which is possibly why you're seeing the issue you're seeing.
So, would changing the method to drawing the background as a sprite on a blank layer below everything but the background layer fix that?
 
camera_set_view_pos()
So how do I return the ID of a camera that's already created by the room to use with that function?

Edit: I got it, I forgot about the default view_camera options for a minute


Edit 2: Okay, I'm on to something here with that but I'm not sure how to go about makiing sure the camera doesn't pan outside the room boundry
 
Last edited:

Nocturne

Friendly Tyrant
Forum Staff
Admin
GML:
var _xx = camera_get_view_x(view_camera[0]);
var _yy = camera_get_view_y(view_camera[0]);
var _ww = camera_get_view_width(view_camera[0]);
var _hh = camera_get_view_height(view_camera[0]);

// Set _xx/_yy to the position you want based on the player here along with offsets etc...

_xx = clamp(_xx, 0, room_width - _ww);
_yy = clamp(_yy, 0, room_height - _hh);

camera_set_view_pos(view_camera[0], _xx, _yy);
That's how I'd do it. :)
 
GML:
var _xx = camera_get_view_x(view_camera[0]);
var _yy = camera_get_view_y(view_camera[0]);
var _ww = camera_get_view_width(view_camera[0]);
var _hh = camera_get_view_height(view_camera[0]);

// Set _xx/_yy to the position you want based on the player here along with offsets etc...

_xx = clamp(_xx, 0, room_width - _ww);
_yy = clamp(_yy, 0, room_height - _hh);

camera_set_view_pos(view_camera[0], _xx, _yy);
That's how I'd do it. :)
After playing a bit and asking for advice I finally figured out a method, but thanks for the alternate suggestion

GML:
//set starting variable for the player tracking camera

cam_mov_x = Sarah_Obj.x-185;
cam_mov_y = Sarah_Obj.y-190;


//override and stop horizontal camera if at edge of room
if Sarah_Obj.x < 185{
cam_mov_x = 0;
}

if Sarah_Obj.x > room_width-185{
cam_mov_x = room_width-370;
}

//set camera
camera_set_view_pos(view_camera[0], cam_mov_x, cam_mov_y);
Seems the way everything is setup I didn't need a vertical camera stop yet because the camera is high enough to never see below the floor tiles
 

Nocturne

Friendly Tyrant
Forum Staff
Admin
Cool, that's great! It's always a nice feeling to come up with your own answers to a problem... Happens to me all the time! I ask someone about something and 30 seconds later I have solved it myself! "Rubber ducking" at it's finest... :)

On a side note, the code you have can be made a LOT more efficient by using clamp...

GML:
//override and stop horizontal camera if at edge of room
/*
if Sarah_Obj.x < 185{
cam_mov_x = 0;
}

if Sarah_Obj.x > room_width-185{
cam_mov_x = room_width-370;
}
*/
cam_mov_x = clamp(cam_move_x, 0, room_width-370);
 
Cool, that's great! It's always a nice feeling to come up with your own answers to a problem... Happens to me all the time! I ask someone about something and 30 seconds later I have solved it myself! "Rubber ducking" at it's finest... :)

On a side note, the code you have can be made a LOT more efficient by using clamp...

GML:
//override and stop horizontal camera if at edge of room
/*
if Sarah_Obj.x < 185{
cam_mov_x = 0;
}

if Sarah_Obj.x > room_width-185{
cam_mov_x = room_width-370;
}
*/
cam_mov_x = clamp(cam_move_x, 0, room_width-370);
The clamp function is actually something I'm not familiar with, how does it work?
 

Nocturne

Friendly Tyrant
Forum Staff
Admin
It's not a constantly running function, so it's doesn't really "engage" or "disengage".You just call it once when you need it and get a value back from it. It's like any other function that returns a value like angle_difference() or string_length() etc... If you were going to write it yourself you'd have something like this:
GML:
function clamp(val, min_val, max_val) {
if val < min_val return min_val;
if val > max_val return max_val;
return val;
}
Hope that helps you understand what it's doing!
 
It's not a constantly running function, so it's doesn't really "engage" or "disengage".You just call it once when you need it and get a value back from it. It's like any other function that returns a value like angle_difference() or string_length() etc... If you were going to write it yourself you'd have something like this:
GML:
function clamp(val, min_val, max_val) {
if val < min_val return min_val;
if val > max_val return max_val;
return val;
}
Hope that helps you understand what it's doing!
I think it get it now.

It didn't quite click that was taking the already set value of cam_mov_x on a previous line and rounding to be within in the range. So something like
GML:
cam_mov_x = Sarah_Obj.x-185;

cam_mov_x = clamp(cam_mov_x, 0, room_width-370);
 
Top