How do I create boundaries for a 2D camera? (Godot 3.0 Alpha)

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By PokeJosh
:warning: Old Version Published before Godot 3 was released.

Hello friends!

My question is in two parts. Allow me to explain what I have so far, and the big picture.

I have attached a Camera2D of a certain size to a KineticBody2D that the user controls as the player. It is currently centered. The idea is to structure the world in a Zelda-like grid pattern, where the player can roam within one grid space until he reaches the edge, when the world will shift to the next grid space, and the player can continue seamlessly where he left off.

However, I would like the camera to be smaller than each grid space, so that the user cannot see the entire space on the grid all at once. When the player has moved so that an edge of the centered camera comes in contact with the edge of a grid space, the camera will stop moving even as the player approaches the edge of the space.

  1. How can I create a grid with bounds that can affect the camera movement but Not the player movement?

  2. How can I keep the camera centered on the player only when the conditions of the grid allow the camera to be centered?

I am still learning what functions that the godot 3.0 nodes are capable of, any assistance is greatly appreciated!

-PokeJosh

I know it’s a litle bit late. But I have done such a camera in one of my projects. If there is still need for it I can try to cleanup my code and post it here.

RoniPerson | 2021-01-03 14:09

I would love to learn how to do this! I had forgotten about this problem and was pleasantly surprised to see an email with a response, haha. I never did solve this issue.

PokeJosh | 2021-01-04 01:32

:bust_in_silhouette: Reply From: pospathos

Take a look, i think thats what you are looking for, it’s for Godot 2.1 but I think that you can do the same in Godot 3:

This works for a camera that is the same size as the grid space. However, not quite the solution to my problem! Thanks for the quick response, though.

PokeJosh | 2017-12-19 07:43

:bust_in_silhouette: Reply From: RoniPerson

This script is on a node 2D which has a camera 2d as child.
Each screen is a Node2D whith a tilemap. If you don’t use tilemaps you have to find another weay to get the size of the objects. The screens are added to the screen_objects array. Set your player as target and the script should work.

Note that there may be better ways performance wise as checking for a screen transition every frame.

extends Node2D

const CHANGE_TIME = 0.1 # active screen can not change faster as this (to prevent flickering)
var change_timer = 0

var screen_size
onready var cam = $Camera2D
var screens = []
export(Array) var screen_objects = []
export var active_screen = 0
export(NodePath) var target

# Called when the node enters the scene tree for the first time.
func _ready():
    for screen_object in screen_objects:
        var rects = []
        var children = get_node(screen_object).get_children()
        for child in children:
            # this only works to get the size off the children when they are tilemaps
            if child.has_method("get_used_rect"):
                var t_rect = child.get_used_rect()
                rects.append(Rect2(t_rect.position.x*8, t_rect.position.y*8, t_rect.size.x*8, t_rect.size.y*8))
        if len(rects) > 0:
            var f_rect = rects[0]
            for i in range(1, rects.size()):
                f_rect = f_rect.merge(rects[i])
                screens.append(f_rect)

    target = get_node(target)
    screen_size = get_viewport_rect().size

func _process(delta):
    change_timer -= delta
    change_timer = 0 if change_timer < 0 else change_timer
    if change_timer == 0:
        screen_change()

    # you can implement more advanced camera controlls here. Like smoothing or view direction. Important is to leave the clamp statements at the end.
    cam.position = target.get_center()

    var screen = screens[active_screen]
    cam.position.x = clamp(cam.position.x, screen.position.x+screen_size.x/2, screen.position.x + screen.size.x-screen_size.x/2)
    cam.position.y = clamp(cam.position.y, screen.position.y+screen_size.y/2, screen.position.y + screen.size.y-screen_size.y/2)

func screen_change():
    var i = 0
    for screen in screens:
        if screen.has_point(target.get_center()):		
            if active_screen != i:
                print("change (RoomController)")
                active_screen = i
                change_timer = CHANGE_TIME
                break
        i += 1