0
\$\begingroup\$

DodgeRollGames, the developers of Enter the Gungeon, tweeted that the game was in fact made in 3D

Screenshot of 3D map from tweet

They tried to explain how they set their camera in this reddit post. Basically what they said was :

so the walls are tilted 45 degrees toward the camera, and the floors are tilted 45 degrees away from the camera, meaning that each should experience sqrt(2) distortion because of the additional length along the z-axis. However, the vertical (y-axis) floor length shouldn't be perceptually changed.

The camera is not tilted at all.

Camera: 0 degree tilt.

Walls: +45 degrees tilt.

Floor: -45 degrees tilt.

My question is : What do they mean by "However, the vertical (y-axis) floor length shouldn't be perceptually changed". If I tilt the walls and floors by 45 degrees and -45 degrees as said, the sqrt(2) distorted walls (the walls have Z depth and are perpendicular to the ground) line up nicely, but the ground gets distorted (obviously). So I distort the ground tiles by sqrt(2) but this essentially stretches the ground by 40% so every vertical movement now has to be increased by 40%.

Can somebody explain what's going on? Any help would be highly appreciated.

\$\endgroup\$

2 Answers 2

1
\$\begingroup\$

I'd say it's easier to keep all your content arranged orthogonally, tilt the camera 45°, and then just correct for the foreshortening in your camera projection. Here's an example (using Kenney's Tiny Dungeon tileset):

Dungeon scene setup

You can see all the floor/roof tiles are sitting flat in the horizontal (XZ) plane, and the walls/characters are standing straight upright in the XY plane. The camera looks down on them at a 45° angle, so normally it would see them foreshortened.

Foreshortened vs Corrected

To counter this, we slap this little script on the camera:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[ExecuteInEditMode]
[RequireComponent(typeof(Camera))]
public class AntiForeshorten : MonoBehaviour
{
    [SerializeField, HideInInspector]
    Camera _camera;

    void OnValidate() {
        TryGetComponent(out _camera);
    }

    // Technically this only needs to happen once at start-up,
    // or when the window is being resized, but it's cheap
    // enough to do every frame in the absence of a built-in
    // OnProjectionChanged event.
    void LateUpdate() {
        // Get the default projection matrix for this camera.
        _camera.ResetProjectionMatrix();
        var mat = _camera.projectionMatrix;

        // Scale the vertical axis by 1/sin(angle).
        mat[1, 1] *= Mathf.Sqrt(2);

        // Use our modified matrix.
        _camera.projectionMatrix = mat;
    }
}

This applies the correction factor on the GPU during rendering, so we don't need to complicate any of our level layout or gameplay scripts with correction factors. The projection matrix is already used during rendering anyway, so we have not added any extra cost to the rendering pipeline - just the miniscule cost to update the matrix once per frame (which you can even eliminate if you're on a platform without a resizable window, like mobile or console)

Now 1 unit along the X axis, 1 unit along the Y axis, and 1 unit along the Z axis are all the same on-screen distance for that oblique top-down look, and none of the angles, scales, or movement speeds in your game world need to be fudged to fit. Positioning objects remains easy: want to place a crate two tiles ahead of the player? That's just z = player_z + 2 - no need to break out the trigonometry or nested coordinate spaces.

\$\endgroup\$
0
\$\begingroup\$

I'm missing a bit on how player movement works, but this image further down the reddit thread clarifies the setup a lot for me. When they say that the floor is tilted 45 degrees away from the camera, that's referring to the floor plane of the entire world, not individual tiles or sections.

enter image description here

Now as for the stretching issue, the easiest way to understand might be to look at this for yourself in Unity. Set up a test scene with a plane perpendicular to an orthographic camera, and some textured cubes for walls. As you rotate the camera, the walls will become distorted. You need to figure out how to un-distort them. They appear shorter so you need to stretch the height. sqrt(2) is the amount referenced because that's the length of the diagonal (i.e. 45 degrees) of a 1x1 square. So a wall at 0 or 90 degrees in relation to the camera would be our reference point for the wall's size, in other words wallsize * 1. Stretching the height of the quad by 1.4142... should therefore appear to be the correct height.

Here's a horrible paint illustration if that isn't clear:

enter image description here

The part I'm unclear on is exactly how the player moves, but they could just be moving in local space relative to the floor plane, or they could be doing the math manually, or something else.

You should also note that as they said, they started developing the game when Unity's 2D tools were just getting started (over five years ago now), so there may be much easier ways to achieve the same effects now, depending on exactly what you're trying to replicate.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .