0
\$\begingroup\$

I was wondering what would be the best approach for a game with a perspective like Resogun, where the world wraps around in a cylinder:

Resogun screenshot

In my opinion, the easiest approach is to:

  • have a "Center Parent" for each moving object

  • Offset the child object by the wanted radius

  • Rotate the parent

=> The objects will move, though this will become super limited very quickly, especially if you want to do any sort of physics.

The 2nd approach is math:

x = centerX + cos(angle)*radius;
x = centerY + sin(angle)*radius;

Now i wonder if there is another way, I was thinking of another method which basically consist of changing the Forward direction of the moving objects based on their position in "the circle", so basically the objects always move forward but adjust their rotation according to their position so they are always facing the right angle.

My main question is that if you want to create a puzzle platformer game like Limbo for example, but in a "cylindrical" map like Resogun, how would you tackle it ?

Thanks!

\$\endgroup\$
1
\$\begingroup\$

One way is to internally handle everything in 2D, and remap the x-coordinate into a cylindrical space for your graphics.

Here's a very simple example. Attach this to an object that moves in 2D space to have it move a corresponding mesh renderer in cylinder space.

public class CylinderSpaceObject : MonoBehaviour {
    [SerializeField] private Transform cylinderCenter;
    [SerializeField] private float cylinderRadius = 5;
    [SerializeField] private GameObject renderer;

    void LateUpdate() {
        float rads = GetPositionRads();

        //convert rotation to cylinder space
        renderer.transform.rotation = transform.rotation * Quaternion.Euler(0, Mathf.Rad2Deg * rads, 0);

        //convert position to cylinder space
        //note we negate the value here so positive x values move counter-clockwise
        //we also add 90 degrees so our renderer is towards the camera when x = 0
        float positionRads = -rads + Mathf.PI / 2f;
        float x = Mathf.Cos(positionRads) * cylinderRadius;
        float z = Mathf.Sin(positionRads) * cylinderRadius;
        var offset = new Vector3(x, transform.localPosition.y, z);
        renderer.transform.position = cylinderCenter.position + offset;
    }

    float GetPositionRads() {
        float rads = transform.localPosition.x / cylinderRadius;
        return rads;
    }
}

Using this approach, all of your gameplay components (such as rigidbodies, colliders, etc) would be attached to the GameObject that has the CylinderSpaceObject component. The renderer would be a separate GameObject containing only rendering components.

\$\endgroup\$
8
  • 2
    \$\begingroup\$ You could even leave the wrapping to the vertex shader, so the level itself is actually flat, and only bent for presentation. I notice Resogun's foreground fades away into fog before you can see it wrap around all the way, with a tall tower completely blocking where the seam would be, so it's hard to rule out whether they're doing it this way. \$\endgroup\$ – DMGregory Apr 8 at 22:20
  • \$\begingroup\$ @Kevin This is interesting, the first question that comes to mind though is "why?", you already done the math to perfectly line up the graphics, why not use that to directly move the rigidbody whether by using the x and z as velocity and rotate the object graphic afterward, or make the rigidbody face the x and z and move it forward, is there any benefits of using your approach ? thanks! \$\endgroup\$ – alaslipknot Apr 9 at 11:48
  • 1
    \$\begingroup\$ In many cases, you never need to warp back at all. You can do it infinite runner style where you just tile the world when you get close to the edge. You might eventually want to re-center if your player can go so far from the origin that floating point precision limits start to bite, but that can be much more rare than once every 360°. And that means you can use ordinary planar physics constraints because your physics world remains simple and flat. It also lets you make a non-Euclidean world if you want, where you can go 360° and yet not come back to the exact same place... \$\endgroup\$ – DMGregory Apr 9 at 11:58
  • 1
    \$\begingroup\$ If you feel that way is more straightforward, then do it that way. All we're doing here is suggesting possibilities. At the end of the day, this is your game, not ours. Make it the way that makes sense to you. \$\endgroup\$ – DMGregory Apr 9 at 12:15
  • 1
    \$\begingroup\$ @alaslipknot My approach is simple and works with either the 2D or 3D physics engine (if using 3D, just set the Rigidbody constraints to not allow motion on the z-axis). Otherwise you're going to have a hell of a time getting the built-in physics to work with the cylindrical motion (unless all you're using physics for is collision detection). \$\endgroup\$ – Kevin Apr 9 at 22:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.