简体   繁体   中英

Java - How can I create a screen layer to load UI over my game?

I am creating a 3d game using Java LWJGL and OpenGL. I want to be able to display a players health bar to the screen. I was thinking some kind of screen that I can render after my game is rendered, that will handle all the 2d 'UI-like' elements that need to be rendered to the screen. What is the best practice at doing this? I have tried creating a Screen class and painting using the Graphics class, but I have run into problems with this. I want a simplistic method that will work to render these elements. How is this done??

EDIT:

Here are some files that I think would be useful

MasterRenderer:

package renderEngine;

import java.awt.Graphics;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import models.TexturedModel;

import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.GL11;
import org.lwjgl.util.vector.Matrix4f;

import shaders.StaticShader;
import shaders.TerrainShader;
import terrains.Terrain;
import entities.Camera;
import entities.Entity;
import entities.Light;

public class MasterRenderer {

private static final float FOV = 70;
private static final float NEAR_PLANE = 0.1f;
private static final float FAR_PLANE = 1000;

private static final float RED = 0.5f;
private static final float GREEN = 0.90f;
private static final float BLUE = 0.90f;

private GUI gui = new GUI();


private Matrix4f projectionMatrix;

private StaticShader shader = new StaticShader();
private EntityRenderer renderer;

private Map<TexturedModel, List<Entity>> entities = new HashMap<TexturedModel, List<Entity>>();
private List<Terrain> terrains = new ArrayList<Terrain>();

private TerrainRenderer terrainRenderer;
private TerrainShader terrainShader = new TerrainShader();

public MasterRenderer() {
    enableCulling();

    createProjectionMatrix();
    renderer = new EntityRenderer(shader, projectionMatrix);
    terrainRenderer = new TerrainRenderer(terrainShader, projectionMatrix);

}

public static void enableCulling() {
    GL11.glEnable(GL11.GL_CULL_FACE);
    GL11.glCullFace(GL11.GL_BACK);
}

public static void disableCulling() {
    GL11.glDisable(GL11.GL_CULL_FACE);
}

public void prepare() {
    GL11.glEnable(GL11.GL_DEPTH_TEST);
    GL11.glClear(GL11.GL_COLOR_BUFFER_BIT|GL11.GL_DEPTH_BUFFER_BIT);
    GL11.glClearColor(RED, GREEN, BLUE, 1);

}

public void render(Light sun, Camera camera) {
    prepare();
    shader.start();
    shader.loadSkyColour(RED,GREEN,BLUE);
    shader.loadLight(sun);
    shader.loadViewMatrix(camera);
    renderer.render(entities);
    shader.stop();
    terrainShader.start();
    terrainShader.loadLight(sun);
    terrainShader.loadViewMatrix(camera);
    terrainShader.loadSkyColour(RED,GREEN,BLUE);
    terrainRenderer.render(terrains);
    terrainShader.stop();
    gui.drawRect(100, 100, 300, 300, 0x00000000);
    terrains.clear();
    entities.clear();
}

public void processTerrain(Terrain terrain) {
    terrains.add(terrain);
}

public void processEntity(Entity entity) {
    TexturedModel entityModel = entity.getModel();
    List<Entity> batch = entities.get(entityModel);
    if(batch != null) {
        batch.add(entity);
    } else {
        List<Entity> newBatch = new ArrayList<Entity>();
        newBatch.add(entity);
        entities.put(entityModel, newBatch);
    }
}

private void createProjectionMatrix() {
    float aspectRatio = (float) Display.getWidth() / (float) Display.getHeight();
    float y_scale = (float) ((1f / Math.tan(Math.toRadians(FOV / 2f))) * aspectRatio);
    float x_scale = y_scale / aspectRatio;
    float frustum_length = FAR_PLANE - NEAR_PLANE;

    projectionMatrix = new Matrix4f();
    projectionMatrix.m00 = x_scale;
    projectionMatrix.m11 = y_scale;
    projectionMatrix.m22 = -((FAR_PLANE + NEAR_PLANE) / frustum_length);
    projectionMatrix.m23 = -1;
    projectionMatrix.m32 = -((2 * NEAR_PLANE * FAR_PLANE) / frustum_length);
    projectionMatrix.m33 = 0;
}



public void cleanUp() {
    shader.cleanUp();
    terrainShader.cleanUp();
}

}

Camera.java:

package entities;

import org.lwjgl.input.Mouse;
import org.lwjgl.util.vector.Vector3f;

public class Camera {

private float distanceFromPlayer = 50;
private float angleAroundPlayer = 0;


private Vector3f position = new Vector3f(0,0,0);
private float pitch = 20; //rotation
private float yaw = 0; //left or right
private float roll; //Tilted

private Player player;

public Camera(Player player) {
    this.player = player;
}

public void move() {
    calculateZoom();
    calculatePitch();
    calculateAngleAroundPlayer();

    float horizontalDistance = calculateHorizontalDistance();
    float verticalDistance = calculateVerticalDistance();
    calculateCameraPosition(horizontalDistance, verticalDistance);
    this.yaw = 180 - (player.getRotY() + angleAroundPlayer);
}

public float getAngleAroundPlayer() {
    return angleAroundPlayer;
}

public Vector3f getPosition() {
    return position;
}

public float getPitch() {
    return pitch;
}

public float getYaw() {
    return yaw;
}

public float getRoll() {
    return roll;
}

public void setAngleAroundPlayer(float angleAroundPlayer) {
    this.angleAroundPlayer = angleAroundPlayer;
}

private void calculateCameraPosition(float horizDistance, float verticDistance) {
    float theta = player.getRotY() + angleAroundPlayer;
    float offsetX = (float) (horizDistance * Math.sin(Math.toRadians(theta)));
    float offsetZ = (float) (horizDistance * Math.cos(Math.toRadians(theta)));

    position.x = player.getPosition().x - offsetX;
    position.z = player.getPosition().z - offsetZ;
    position.y = player.getPosition().y + verticDistance + 10;
}

private float calculateHorizontalDistance() {
    return (float) (distanceFromPlayer * Math.cos(Math.toRadians(pitch)));  
}

private float calculateVerticalDistance() {
    return (float) (distanceFromPlayer * Math.sin(Math.toRadians(pitch)));  
}

private void calculateZoom() {
    float zoomLevel = Mouse.getDWheel() * 0.1f;
    distanceFromPlayer -= zoomLevel;
}

private void calculatePitch() {
    if(Mouse.isButtonDown(1)) {
        float pitchChange = Mouse.getDY() * 0.1f;
        pitch -= pitchChange;

        if(pitch < 10) pitch = 10;
        if(pitch > 90) pitch = 90;      
    }
}

private void calculateAngleAroundPlayer() {
    if(Mouse.isButtonDown(0)) {
        float angleChange = Mouse.getDX() * 0.3f;

        if(angleAroundPlayer >= 360) angleAroundPlayer = 0;

        angleAroundPlayer -= angleChange;
    }
}

}

MainGameLoop:

package engineTester;

import java.awt.Graphics;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import models.TexturedModel;

import org.lwjgl.opengl.Display;
import org.lwjgl.util.vector.Vector3f;

import renderEngine.DisplayManager;
import renderEngine.Loader;
import renderEngine.MasterRenderer;
import renderEngine.OBJLoader;
import terrains.Terrain;
import textures.ModelTexture;
import textures.TerrainTexture;
import textures.TerrainTexturePack;
import toolbox.KeyBindings;
import entities.Camera;
import entities.Entity;
import entities.Light;
import entities.Player;

public class MainGameLoop {
public static KeyBindings keyBindings;

public static Camera camera;


public static void main(String[] args) {// TODO Auto-generated method stub
    DisplayManager.createDisplay();
    Loader loader = new Loader();

    //--------------------Terrain Texture------------------//


    TerrainTexture backgroundTexture = new TerrainTexture(loader.loadTexture("grassy2"));
    TerrainTexture rTexture = new TerrainTexture(loader.loadTexture("mud"));
    TerrainTexture gTexture = new TerrainTexture(loader.loadTexture("pinkFlowers"));
    TerrainTexture bTexture = new TerrainTexture(loader.loadTexture("stone"));

    TerrainTexturePack texturePack = new TerrainTexturePack(backgroundTexture, rTexture,
            gTexture, bTexture);

    TerrainTexture blendMap = new TerrainTexture(loader.loadTexture("blendMap"));


    //-----------------------------------------------------//

    ModelTexture fernTextureAtlas = new ModelTexture(loader.loadTexture("fern"));
    fernTextureAtlas.setNumberOfRows(2);

    TexturedModel tree1 = new TexturedModel(OBJLoader.loadObjModel("tree", loader), 
            new ModelTexture(loader.loadTexture("tree")));

    TexturedModel tree2 = new TexturedModel(OBJLoader.loadObjModel("lowPolyTree", loader), 
            new ModelTexture(loader.loadTexture("lowPolyTree")));

    TexturedModel fern = new TexturedModel(OBJLoader.loadObjModel("fern", loader), 
            fernTextureAtlas);

    TexturedModel flower = new TexturedModel(OBJLoader.loadObjModel("grassModel", loader), 
            new ModelTexture(loader.loadTexture("flower")));

    TexturedModel stall = new TexturedModel(OBJLoader.loadObjModel("stall", loader), 
            new ModelTexture(loader.loadTexture("stallTexture")));

    TexturedModel grass = new TexturedModel(OBJLoader.loadObjModel("grassModel", loader), 
            new ModelTexture(loader.loadTexture("grassTexture")));

    TexturedModel playerModel = new TexturedModel(OBJLoader.loadObjModel("person", loader), 
            new ModelTexture(loader.loadTexture("playerTexture")));

    grass.getTexture().setUseFakeLighting(true);
    grass.getTexture().setHasTransparency(true);
    fern.getTexture().setUseFakeLighting(true);
    fern.getTexture().setHasTransparency(true);
    stall.getTexture().setShineDamper(10);
    stall.getTexture().setReflectivity(1);
    tree1.getTexture().setShineDamper(10);


    Light light = new Light(new Vector3f(0, 20000, 20000), new Vector3f(1,1,1));

    Terrain terrain = new Terrain(0, 0, loader, texturePack, blendMap, "heightMap");

    List<Entity> entities = new ArrayList<Entity>();

    Random random = new Random();

    for (int i = 0; i < 400; i++) {
        if (i % 2 == 0) {
            float x = random.nextFloat() * 800;
            float z = random.nextFloat() * 600;
            float y = terrain.getHeightOfTerrain(x, z);
            entities.add(new Entity(fern, random.nextInt(4), new Vector3f(x, y, z), 0, random.nextFloat() * 360, 0, 0.9f));
        }
        if (i % 5 == 0) {
            float x = random.nextFloat() * 800;
            float z = random.nextFloat() * 600;
            float y = terrain.getHeightOfTerrain(x, z);
            entities.add(new Entity(tree1, new Vector3f(x, y, z), 0, random.nextFloat() * 360, 0, random.nextFloat() * 1 + 4));

            x = random.nextFloat() * 800;
            z = random.nextFloat() * 600;
            y = terrain.getHeightOfTerrain(x, z);
            entities.add(new Entity(tree2, new Vector3f(x, y, z), 0, random.nextFloat() * 360, 0, random.nextFloat() * 0.1f + 0.6f));
        }
        if (i % 4 == 0) {
            float x = random.nextFloat() * 800;
            float z = random.nextFloat() * 600;
            float y = terrain.getHeightOfTerrain(x, z);
            entities.add(new Entity(grass, new Vector3f(x, y, z), 0, 0, 0, 1.5f));

            x = random.nextFloat() * 800;
            z = random.nextFloat() * 600;
            y = terrain.getHeightOfTerrain(x, z);
            entities.add(new Entity(flower, new Vector3f(x, y, z), 0, 0, 0, 1.5f));
        }

    }

    MasterRenderer renderer = new MasterRenderer();

    Player.parsePlayerData();
    float terrainHeight = Player.getTerrainHeight(terrain, Player.PLAYER_X, Player.PLAYER_Z);
    Player player = new Player(playerModel, new Vector3f(Player.PLAYER_X, terrainHeight, Player.PLAYER_Z), 0, 0, 0, 1);

    camera = new Camera(player);



    while (!Display.isCloseRequested()) {

        camera.move();
        player.move(terrain);
        renderer.processEntity(player);
        renderer.processTerrain(terrain);

        for(Entity entity : entities) {
            renderer.processEntity(entity);
        }

        renderer.render(light, camera);

        DisplayManager.updateDisplay();
        keyBindings.run();

    }



    renderer.cleanUp();
    loader.cleanUp();
    Player.savePlayerData(player/*new Vector3f(player.getPosition().x, terrainHeight, player.getPosition().z)*/);
    DisplayManager.closeDisplay();

}

}

Once you're done rendering your 3D scene with perspective projection, you switch to orthographic projection and render your 2D graphics on top of everything else. In your case Screen class would be a good fit for UI rendering.

Game.render(); //Set Persp Proj; Render 3D world (terrain, meshes & models)
Screen.render(); //Set Orhto Proj; Render UI elements on top (textures, fonts)

Really the idea is quite simple, the hard part dwells within the implementation details of your OpenGL version and programming language.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM