Enable interpolation and scale the sprites. It won’t preserve the SNES style pixelized style, but it will make it look really smooth and nice IMO and it works perfectly with floating point coordinates scaled to any resolution. You’ll need a transparent border around your 2D images to avoid aliasing. For a 2D game I made earlier, I decided on an ‘internal’ resolution and aspect ratio. When the screen size changed I calculated values to send to glOrtho() to keep the aspect ratio of the game by adding black borders, and then used the scissor test to disable drawing into these borders. However, to the internal functions of the game I had a constant resolution. Now, I’m assuming you’re using OpenGL since you mentioned 3D, so here’s the function I made:
private static final int INTERNAL_WIDTH = 800, INTERNAL_HEIGHT = 600;
private static final double INTERNAL_ASPECT = (double) INTERNAL_WIDTH / INTERNAL_HEIGHT;
private void setWindowSettings(int screenWidth, int screenHeight) {
double aspectRatio = (double) screenWidth / screenHeight;
if (aspectRatio > INTERNAL_ASPECT) {
double width = INTERNAL_HEIGHT * aspectRatio;
double displacement = (INTERNAL_WIDTH - width) * 0.5;
GL11.glOrtho(displacement, width + displacement, INTERNAL_HEIGHT, 0, -1, 1);
} else {
double height = INTERNAL_WIDTH / aspectRatio;
double displacement = (INTERNAL_HEIGHT - height) * 0.5;
GL11.glOrtho(0, INTERNAL_WIDTH , height + displacement, displacement, -1, 1);
}
GL11.glViewport(0, 0, screenWidth, screenHeight);
GL11.glEnable(GL11.GL_SCISSOR_TEST);
if (aspectRatio > INTERNAL_ASPECT) {
int padding = (int) (screenWidth - screenHeight * INTERNAL_ASPECT) / 2;
GL11.glScissor(padding, 0, screenWidth - padding * 2, screenHeight);
inputManager.update(padding, 0, screenWidth - padding * 2, screenHeight);
} else {
int padding = (int) (screenHeight - screenWidth / INTERNAL_ASPECT) / 2;
GL11.glScissor(0, padding, screenWidth, screenHeight - padding * 2);
inputManager.update(0, padding, screenWidth, screenHeight - padding * 2);
}
}
The first part (the glOrtho() part) is pretty straightforward, but the scissor test part is pretty messy IMO. ._. The point of this method is that it allows you to draw to any resolution without having to scale your coordinates manually like when drawing in 3D. The position at (INTERNAL_WIDTH / 2, INTERNAL_HEIGHT / 2) = (400, 300) will always be the center of the screen, regardless of the screen’s (or window’s) actual aspect ratio or resolutions. Oh, and inputManager is just a class that handles input and translates screen coordinates to the internal resolution.