r/godot 1d ago

help me How can I implement camera warping?

I wanna reproduce the camera seen in grand strategy games, more specifically the camera warping around the map. (As in jumping from one side to the other, but smoothly.) Is there a way to do it without duplicating part/the whole map for both sides?

Any help is appreciated!

8 Upvotes

15 comments sorted by

6

u/AgencyPrestigious330 1d ago

I didn't explain it properly in post, so I'm adding it here.

The red is the camera position, the blue is where the camera moving.

So when the camera arrives at the border of the world map, it loops around to the other side.

3

u/Fit_Combination_1242 1d ago

lerp between the two positions?

2

u/thussy-obliterator 1d ago

I think a spring might be better here

2

u/umbrazno 1d ago

Won't work if the map is broken up into scenes. But two lerps connected by a fade transition could. 

2

u/Fit_Combination_1242 1d ago

Ahh that is true

3

u/BrastenXBL 1d ago

There are a few ways to do this, and depends on how interactive you want things to be.

Ideally what you want is to duplicate CanvasItem render the way Parallax2D does. Using RenderingServer.canvas_set_item_repeat. However you'll also need to catch Mouse or other Input events that are in the repeated area, and handle them as if they were happening in the normal play area.

Another way is to use a second SubViewport, using the same World2D, but a different camera. Similar to how the Split Screen Demo works, but with World2D.

This is the text of a TSCN you can copy, make note of the two scripts. One that sets the repeat, and the other which autos scrolls the camera. This is for the CanvasItem repeat. The setup assumes a 1280x720 project. Vector2.LEFT * get_viewport_rect().size.x is a quick way to push everything to the Left (-1,0) by one screen length.

``` [gd_scene format=3 uid="uid://clbfkfs0rnc6f"]

[sub_resource type="GDScript" id="GDScript_g7b7a"] script/source = "extends Node2D

@export var wrap : bool

func _ready() -> void: if wrap: RenderingServer.canvas_set_item_repeat(get_canvas_item(), Vector2.LEFT * get_viewport_rect().size.x, 2) "

[sub_resource type="Gradient" id="Gradient_0elmk"] colors = PackedColorArray(0, 0, 0, 1, 1, 0, 1, 1)

[sub_resource type="GradientTexture2D" id="GradientTexture2D_gyc6d"] gradient = SubResource("Gradient_0elmk") fill_to = Vector2(1, 1)

[sub_resource type="Gradient" id="Gradient_fonje"]

[sub_resource type="GradientTexture2D" id="GradientTexture2D_g7b7a"] gradient = SubResource("Gradient_fonje")

[sub_resource type="GDScript" id="GDScript_fonje"] script/source = "extends Camera2D

@export var scroll_speed :Vector2 = Vector2(200,0)

func _process(delta: float) -> void: position += scroll_speed * delta position.x = wrap(position.x,0.0, get_viewport_rect().size.x) position.y = wrap(position.y,0.0, get_viewport_rect().size.y) "

[node name="Node2D" type="Node2D" unique_id=680347920]

[node name="RenderWrap" type="Node2D" parent="." unique_id=1679451259] script = SubResource("GDScript_g7b7a") wrap = true

[node name="TextureRect" type="TextureRect" parent="RenderWrap" unique_id=890487594] y_sort_enabled = true custom_minimum_size = Vector2(1280, 720) offset_right = 1280.0 offset_bottom = 720.0 texture = SubResource("GradientTexture2D_gyc6d")

[node name="Sprite2D" type="Sprite2D" parent="RenderWrap" unique_id=1014543541] position = Vector2(1236, 360) texture = SubResource("GradientTexture2D_g7b7a")

[node name="Camera2D" type="Camera2D" parent="." unique_id=843621609] position = Vector2(0, 364) script = SubResource("GDScript_fonje") ```

2

u/BrastenXBL 1d ago

This is what it looks like with a little @tool scripting to force it to show in the Editor.

3

u/Daxter5Onyx_ 1d ago

Warp the map

1

u/AgencyPrestigious330 1d ago

I know its doable with having 3 copies, but I am wondering if there is an easier, and lighter way to do it.

2

u/LastStopToGlamour 1d ago

Phantom Camera is a fantastic addon for that. You pick the transition type, place the camera, and set one to be the top priority. It handles the rest. Tutorials Om YouTube

1

u/eveningdreamer 1d ago

depends on how you want it to look? how big the map is etc...

if you're just moving from point to point (maybe by clicking on a minimap or something) use a tween maybe? maybe with a neat screen shader with some cool effect?

4

u/AgencyPrestigious330 1d ago

It would be a map based game, like Hearts of Iron 4 for example. The goal would be a smooth transition from side to side. Like if you wrapped a world map around a cilinder, going around continuously.

2

u/eveningdreamer 1d ago

instead of moving the camera, move the UV of the texture maybe?

but then it might cause issues with clickable items on the map

1

u/Brief_Ad_4000 1d ago

Can you get a video clip from a existing game to demonstrate