Rendercam > How to make the camera move inside a popup?

Hello!

I have a tilemap that I’d like to scroll inside a popup.

Not sure how I should handle the camera (via rendercam - so this is a question for @ross.grams :see_no_evil: or anyone being experienced with rendercam)

I tried two approaches:


Approach 1 (the dirty one? I don’t know)
1/ I keep the focus on the main_scene (monarch - not important here but just to mentioned it)

(not sure which box I should have checked so… I checked both :monkey:)

2/ In the main scene scripts, I add the same condition here and there to make sure all the interactions are disabled (except the camera scrolling) if the popup is displayed above. And then, since the tilemap is in the world view, I can scroll it using the main scene’s camera (rendercam).

This approach is not super elegant but more natural to me (because it’s not rendercam-specific) and seems to work fine (so if I can’t find anything better. I’ll go for it), but this is probably not the best option in terms of flexibility/maintainability/etc. (if I add new interactions, use the popup in different contexts/scenes etc.)


Approach 2
In this case, I’d like to have a camera in the popup collection.

1/ I disable the focus (monarch - not important here but just to mentioned it)
image

2/ I copy the camera game object containing the rendercam script (and rename it, just in case)
image

So I have a similar camera object in the main_scene collection and the popup collection.

3/ But… looks like there is a conflict somewhere :sweat_smile: (I’m probably not supposed to have 2 rendercam scripts running simultaneously)

To be honest, I’m not really sure what I’m doing with the second approach, but I feel this would be cleaner if properly executed (maybe I’m wrong though).


What is the best approach/method to scroll the camera inside a popup?

What are you doing right now, that appears to work? I’m not quite sure what is actually not working for you, besides the issue with multiple cameras.

How are you rendering the tilemap in the popup? Did you make a separate render predicate for it?

How are you scrolling the regular game view? Are you moving the camera, or moving the world?

Two cameras should work just fine with RenderCam. They do need to have different paths, but there should be an error message in the console if this happens.

Are there any warning or error messages from RenderCam in the console?

Does the popup stay loaded, or is it unloaded or deleted when it is closed?

If you decide to use two cameras, when you close the popup, you will need to re-activate the original camera, using rendercam.activate_camera(id).

Unless you want to have different camera settings for viewing the regular game view vs. the map view, it should be fine to do this with either one camera or two, it’s up to you.

1 Like

Thank you for your answer, that confirms how unclear my message was :see_no_evil:

Currently (approach 1) I have
1/ a camera object in my main scene (including the rendercam script).
image
2/ “if popup not displayed” conditions here and there to enable/disable the interactions with the main scene’s objects.

When displaying the popup (via monarch), the interactions are just disabled, except the camera which is the only thing that can still be moved. So I can move it even when the popup is displayed (and this way I should be able to scroll the tilemap).

Since I don’t know how to do it (yet :nerd_face:), this is just a regular tilemap in a game object.
image

I’m moving the camera object.

By “different paths”, do you mean different game objects? Or different rendercam scripts? Or both?
(or just the camera object id?)
image
image

If game objects, do you mean something like that?

Main scene
image

Popup
image

Not for now, I did not go far enough to get the error messages :monkey:

The popup is unloaded when closed (so I don’t get why the main scene camera doesn’t work at this moment), but even before that, there seems to be something wrong when the popup is displayed.

That’s what I thought I should do, but how to deactivate an activated camera? With msg.post(…,“disable”)?
(I tried this but did not manage to make it work, so I quickly gave up.

In the documentation, I only found how to reactivate it.

As mentioned above, one camera works fine for now but it seems to be less flexible and maintainable if I want to trigger the popup from any scene (but from a user perspective it doesn’t make a difference, for sure).

I just made a super quick test to learn how to activate inactive cameras, but did not manage to make it work… :

1/ I deactivate the main scene camera:
image

image

:arrow_down:
2/ Then I activate it in a script when the main scene is loaded:
image

image

:arrow_down:
3/ But the camera doesn’t seem to exist
image

Just in case, I tried to replace the ID with “/camera_001”, “/camera/camera_1.go”, “/camera_001#script” but it doesn’t make sense and of course, it did not work.

I also tried to delay the camera activation by 1-2 frames just in case everything is not “available” yet. No difference.

Did I miss something? :thinking:

Sorry, I didn’t get around to this. Just a few quick comments now and I’ll answer more tomorrow if need be.

Just using one camera should be just fine. All you need to do is store the scroll/camera position for the main screen and for each popup that uses it, so you can reset it back to where it should be on each “Screen”. Seems perfectly “elegant” to me.

Short answer: Just the game object’s ID.
Long answer: Actually, the IDs can sometimes be the same, if they are in different collections. The main part of the objects URL in your bootstrap collection would just be “camera”. If there’s another one in the root level of a proxy collection, that will also just be “camera”, and there will be a conflict. However, if one of those is in a sub-collection, that part of the URL would be “sub_collection/camera”—different and therefore not a problem.

Do not modify the RenderCam camera.script, or obviously, I can’t guarantee that it works, and you’re on your own. :grin:

There is no way to deactivate the RenderCam camera, because you never need it. RenderCam can only handle one active camera at a time, so when you activate a different one, the last one is no longer used. If no camera exists, then it uses some generic fallback camera settings.

The “Active” checkbox on the camera script is only for initialization. If I recall correctly, changing that property at runtime does nothing. :no_mouth:

Regarding the ID: the camera.script has this:

-- From the camera script component:
self.id = go.get_id()

So whatever go.get_id() gives you for the object that the camera script is on, that should be the “cam_id” that rendercam.activate_camera() wants.

But my advice is: Just stick with one camera. That already works, it’s easy, less management stuff.

1 Like

Thank you for the advice (and the rest of the message that helped me a lot), I understand it but I’m a bit stubborn… and since I’m still learning, I wanted to give the “2 cameras” option a try.


And after struggling (way more than expected :grin: as usual) to make it work, it’s now functional.

Well… almost functional because a “tiny little thing” is killing me (and has nothing to do, at least directly, with the camera). I don’t like when simple things don’t work exactly as they should, and this one is pretty annoying in terms of user experience.

As you can see in the video, there is some sort of “latency” with the GUI stuff (level buttons & path dots)… They look ~1 frame late compared to the “world view” elements (tilemap, debugdraw circles…).

Why is that? I’m not 100% sure but here is what I do:

1/ I create and position the level stuff in GUI (buttons + path dots) - in the editor.
image

2/ To make sure I’ll be able to move these GUI buttons consistently with the camera, I create game objects at the same initial position (in the init function of the GUI script).
image
=> These game objects will “naturally” move with the camera so I’ll use them to get the world>screen coordinates for my GUI buttons etc. (they are invisible but I use debugdraw to show them)

3/ In the script of the game objects in question, I update the positions and share them via a lua module:
image

4/ And finally I use these positions to move my GUI stuff along with the camera:
image

In theory, it seemed ok. In practice it’s almost ok. Almost!

In this case, it seems that…I don’t know, there is something I can’t control, like the order in which scripts and GUI scripts are read. Like if the GUI script was 1 frame late compared to the game objects.


So my 1st question is : is there a way to control the script “interpretation” order? If not, I’m trapped.

And if I’m trapped, I see 2 options:
1/ Turn the GUI level buttons and path dots into game objects… so at least everything will be moving super synchronously with the camera (but maybe there are reasons not to have the level button as game objects? I don’t know)
2/ Get back to the 1st approach (of my 1st message) :sweat_smile: I would work but at this point, I feel like option 1 would be easier/faster (not 100% sure though) and slightly less discouraging.


What do you think? :thinking:

1 Like

Ah, yes. This problem was brought up not too long ago. You can check this thread for some explanation, but in short—I can’t fix it. There’s no way to manually update the world transform of the camera after you move it, so screen_to_world_2d will be using an out-of-date transform.

As long as you don’t need to put your camera on a transformed parent though, there is an easy enough workaround—you just assume that local pos is the same as world pos. I posted a sample project in that other thread, and here are the relevant functions from there:

-- `cam` must be the URL to the camera -script- component.
local function getRealCamScale(cam)
	local window = rendercam.window
	local orthoScale = rendercam.get_ortho_scale()
	local scaledViewArea = go.get(cam, "viewArea") * orthoScale
	local scale = scaledViewArea.x / window.x
	return scale
end

local function simpleScreenToWorld(x, y, cam, isDelta)
	if not isDelta then
		local window = rendercam.window
		x, y = x - window.x/2, y - window.y/2
	end
	local scale = getRealCamScale(cam)
	x, y = x * scale, y * scale
	if not isDelta then
		local camPos = go.get_position(cam)
		x, y = x + camPos.x, y + camPos.y
	end
	return x, y
end

local function simpleWorldToScreen(x, y, cam, isDelta)
	if not isDelta then
		local camPos = go.get_position(cam)
		x, y = x - camPos.x, y - camPos.y
	end
	local scale = getRealCamScale(cam)
	x, y = x / scale, y / scale
	if not isDelta then
		local window = rendercam.window
		x, y = x + window.x/2, y + window.y/2
	end
	return x, y
end

Just use those instead of the usual rendercam.screen_to_world_2d, etc., and I believe it should work, since the local position is updated instantly.

If you need to have a sort of “post-update” function, you can do this by sending a message to a script (probably ‘yourself’) on every update. That’s what the camera does as well. The on_message response will be triggered just after all scripts have been updated.

1 Like

I tried to use these functions in the game object script (to share the screen positions with the gui script)

but I get an error message

referring to this
image

Is there a link with this?
image

image

(just in case, I tried to activate the "view area "thing, replace “viewArea” by “View Area” but nothing changed)

The script properties are on the script component. Make sure to target the script component in the url

-- I'm not sure which one of the below to property ids are correct. check the render cam script!
go.get("go_id#script_id", "viewArea")
go.get("go_id#script_id", "view_area")

1 Like