Let's say I have an object outside of camera3D view on the left. I then script the camera to move to the left and I want the camera to stop moving when left side of camera's view hits that object . (doesn't matter if the object is in the view, I only want that object to be a stop marker) How would I do that?

Thanks.

  • Tomcat and xyz replied to this.
  • The easiest way is to just use camera frustum planes. To constrain camera between two limiter Node3D origins simply check if one of them is in the frustum and push camera to left/right for distance that's equal to limiter node's distance to corresponding frustum plane (projected onto camera's left-right basis vector). This will work for ortho as well as perspective cameras. Just make sure that camera never sees both limiters.

    func constrain_camera_left_right(camera: Camera3D, left: Node3D, right: Node3D) -> void :
    	var frustum = camera.get_frustum()
    	var left_plane = frustum[2]
    	var right_plane = frustum[4]
    	var d = min(0, left_plane.distance_to(left.global_position))
    	camera.translate_object_local(Vector3.RIGHT * (d/left_plane.normal.dot(camera.global_transform.basis.x)))
    	d = min(0, right_plane.distance_to(right.global_position))
    	camera.translate_object_local(Vector3.RIGHT * (d/right_plane.normal.dot(camera.global_transform.basis.x)))

    Exactly the same approach can be applied to keep a player inside camera frustum, just use opposite sides of frustum planes, i.e. invert the plane normals and move the player instead of camera.

    Gowydot I then script the camera to move to the left and I want the camera to stop moving when left side of camera's view hits that object .

    How far away is the subject from the camera?

    You can make a collision shape by camera's gaze and track the collision.

    Gowydot I then script the camera to move to the left and I want the camera to stop moving when left side of camera's view hits that object

    Why? What do you need this for?

    @Tomcat @xyz

    Sorry, I sort of make it work by clamping the position.x of camera. But now I have another related question - How can I stop my characters to go out of camera view

    Some background on this project:
    I'm making a "3D" fighting game and now trying to figure out how fighting game's camera works. I based my project on Street Fighter 6 camera. It is not a true 3D camera eg. no need for camera rotation, just move x,y and a bit of z

    I have orthogonal camera3D following the center of the screen (+). It expands the view based on the length between the fighters then I clamp the camera max/min size.

    	cam.size = lerp(cam.size + cam_size, (p1.global_position.x-p2.global_position.x)/2, 0.5)
    	if cam.size < 5.2:
    		cam.size = 5.2
    	if cam.size > 6.7:
    		cam.size = 6.7

    But during Maximum view each fighters still able to move out of the camera's view left and right. How can I stop them from moving out of view? (In the game the fighter will just keep playing "waking back" animation but never leave the view)

      Gowydot Maybe you could add some invisible walls to left and right side.

      Gowydot How can I stop them from moving out of view?

      Since you have a camera limited in motion, creating, shape over the camera view space and then limiting collisions seems like a simple and quite workable option.

      Yeah, it's like creating walls, but tied to the camera.

      • Toxe replied to this.

        Tomcat Or the other way around. An "empty" scene that contains just two invisible walls on each side and the camera. Depending on camera distance or some other factor the walls could narrow or widen.

          Gowydot Will you be using orthographic camera only?

          Toxe I think they don't necessarily need to move the "walls" with respect to each other. The walls just need to follow the camera, equidistant on each side at some max distance which will be suitable for when the camera is fully zoomed out, since they aren't necessary when the camera is zoomed in.

          The easiest way is to just use camera frustum planes. To constrain camera between two limiter Node3D origins simply check if one of them is in the frustum and push camera to left/right for distance that's equal to limiter node's distance to corresponding frustum plane (projected onto camera's left-right basis vector). This will work for ortho as well as perspective cameras. Just make sure that camera never sees both limiters.

          func constrain_camera_left_right(camera: Camera3D, left: Node3D, right: Node3D) -> void :
          	var frustum = camera.get_frustum()
          	var left_plane = frustum[2]
          	var right_plane = frustum[4]
          	var d = min(0, left_plane.distance_to(left.global_position))
          	camera.translate_object_local(Vector3.RIGHT * (d/left_plane.normal.dot(camera.global_transform.basis.x)))
          	d = min(0, right_plane.distance_to(right.global_position))
          	camera.translate_object_local(Vector3.RIGHT * (d/right_plane.normal.dot(camera.global_transform.basis.x)))

          Exactly the same approach can be applied to keep a player inside camera frustum, just use opposite sides of frustum planes, i.e. invert the plane normals and move the player instead of camera.

          @Tomcat @Toxe @award
          Yea I think creating collision walls is the most straight forward solution. However, I will give xyz's solution a go as I've never done it before.

          @xyz
          I got the constrain_camera_left_right working so thanks so much! But..

          same approach can be applied to keep a player inside camera frustum, just use opposite sides of frustum planes

          func constrain_player_left_right(player: CharacterBody3D) -> void :
          	var frustum = cam.get_frustum()
          	var left_plane = frustum[2]
          	var right_plane = frustum[4]
          	player.translate_object_local(Vector3.LEFT * (-left_plane.normal.dot(global_transform.basis.x)))
          	player.translate_object_local(Vector3.LEFT * (-right_plane.normal.dot(global_transform.basis.x)))

          This is not working as I have no clue what I'm doing.
          Can you give me an example code on constraining players inside? I would like to see a working example and try to understand it after.

          Will you be using orthographic camera only?

          My plan is to have orthographic camera for players and perspective camera for background and somehow sync them. I did try it using subviewport and it kind of worked but also with errors, but that's another question for later 😆

          • xyz replied to this.

            Gowydot This is not working as I have no clue what I'm doing.
            Can you give me an example code on constraining players inside? I would like to see a working example and try to understand it after.

            Sometimes I feel I'm just being used on this forum for code solicitation when ChatGPT fails to produce copy-pastable results. Sigh 😔

            I'll knock you up an example. Stay tuned. In the meantime maybe work on getting some clues about how this works. Being clueless is not a good place to be for a game developer 🥸

            Btw doing it via frustum planes is much more elegant and clean than managing colliders. Especially if you use perspective camera.

            Gowydot There you go:

            func constrain_node_to_camera_left_right(node: Node3D, camera: Camera3D, margin: float) -> void:
            	var frustum = camera.get_frustum()
            	var left_plane = frustum[2]
            	var right_plane = frustum[4]
            	var d = max(0, left_plane.distance_to(node.global_position) + margin)
            	node.translate_object_local(Vector3.RIGHT * (-d/left_plane.normal.dot(node.global_transform.basis.x)))
            	d = max(0, right_plane.distance_to(node.global_position) + margin)
            	node.translate_object_local(Vector3.RIGHT * (-d/right_plane.normal.dot(node.global_transform.basis.x)))

            Note that this expects node to move along its local x axis so it will constrain that axis only. It can be generalized for an arbitrary axis but I won't go into it here since you probably won't ever need it for this type of game.

            @xyz

            First of all thanks for the code, I really appreciated. When I tried it although it works as intended it also introduces other problems like my expanding camera no longer works or the player can drag the other player along with the camera. I'm gonna have to look deeper into it over the weekend. I agreed that using frustum is more elegant but I've never work with it before so it gonna take some times to learn.

            Sometimes I feel I'm just being used

            Sorry that was not my intention. As I said in another thread somewhere the way I learn is to see a working example and then go back to learn it myself one line at a time. If it makes you feel any better I've never used ChatGpt for anything 😃 I did try to do it myself several times before asking for an example code. 😉

            • xyz replied to this.

              Gowydot it also introduces other problems like my expanding camera no longer works or the player can drag the other player along with the camera

              That has nothing to do with code I posted. You should make sure that the rest of your code and setup function properly and that constrains are applied in appropriate order. And remember, you asked for code examples that you can learn from. So try to understand what the code does and adapt it to your specific needs.