package game; import game.blocks.BlockManager; import java.awt.Font; import java.io.File; import java.io.InputStream; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import org.lwjgl.LWJGLException; import org.lwjgl.LWJGLUtil; import org.lwjgl.input.Keyboard; import org.lwjgl.input.Mouse; import org.lwjgl.openal.AL; import org.lwjgl.opengl.Display; import org.lwjgl.opengl.GL11; import org.lwjgl.util.glu.GLU; import org.newdawn.slick.Color; import org.newdawn.slick.TrueTypeFont; import org.newdawn.slick.openal.SoundStore; import org.newdawn.slick.opengl.TextureImpl; import org.newdawn.slick.util.ResourceLoader; public class Game { private static final float MOUSE_SPEED_SCALE = 0.1f; private static final float MOVEMENT_SPEED = 0.085f; private static final float MOVEMENT_SPEED_FLYMODE = 0.17f; private static final float FALSE_GRAVITY_SPEED = 0.035f; private static final float FOV = 90.0f; public static final int CHUNK_SIZE = 16; public static final int CHUNK_HEIGHT = 128; public static final int TEXT_LINE_HEIGHT = 18; public static int fps; public static int ups; private static final boolean FULLSCREEN = false; private static final boolean VSYNC = false; public static final boolean TEXTURES = true; private TrueTypeFont font; public static BlockManager blockManager = new BlockManager(); public static Vector4f AMBIENCE_COLOR = new Vector4f(0.05f, 0.05f, 0.05f, 1.0f); private long startTime; // Game components private Camera camera; private ChunkManager terrain; // Toggles private boolean flyMode = false; private boolean doCollisionChecking = true; private boolean renderSkybox = false; private boolean wireframe = false; private boolean isPaused = false; private boolean closeRequested = false; private int displayFps; private int displayUps; private boolean debugScreen = false; public static long deltaTime; private boolean playMusic = true; private boolean pickBlock = false; private boolean placeBlock = false; private int mouseDelayer = 0; public void start() { // Create the display try { Display.setDisplayMode(Display.getDesktopDisplayMode()); Display.setFullscreen(FULLSCREEN); Display.setVSyncEnabled(VSYNC); Display.create(); } catch(LWJGLException e) { e.printStackTrace(); System.exit(0); } Display.setTitle("Craftalike"); initGl(); // Hide the mouse Mouse.setGrabbed(true); // Create the terrain terrain = new ChunkManager(); Vector3f startPos = new Vector3f(8.0f, 129.0f, 8.0f); // Create the camera camera = new Camera(startPos, new Vector3f(0.0f, 0.0f, 0.0f), terrain); GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST); GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_NEAREST); // load font from a .ttf file try { InputStream inputStream = ResourceLoader.getResourceAsStream("res/fonts/Minecraftia.ttf"); Font awtFont = Font.createFont(Font.TRUETYPE_FONT, inputStream); awtFont = awtFont.deriveFont(16f); // set font size font = new TrueTypeFont(awtFont, false); } catch (Exception e) { e.printStackTrace(); } if (playMusic) Music.playMusic(); startTime = System.currentTimeMillis(); long lastTime = System.nanoTime(); long timer = System.currentTimeMillis(); final double ns = 1000000000.0 / 60.0; double delta = 0; fps = 0; ups = 0; displayUps = 0; displayFps = 0; while(!Display.isCloseRequested()) { long now = System.nanoTime(); delta += (now - lastTime) / ns; lastTime = now; while (delta >= 1) { if (!isPaused) { update(); } ups++; SoundStore.get().poll(0); delta--; } render(); fps++; if (System.currentTimeMillis() - timer > 1000) { timer += 1000; displayFps = fps; displayUps = ups; //frame.setTitle(Game.title + " | " + updates + " ups, " + frames + " fps"); ups = 0; fps = 0; } // Check for pressed keys while (Keyboard.next()) { if (Keyboard.getEventKeyState()) { if (Keyboard.getEventKey() == Keyboard.KEY_F) { flyMode = !flyMode; } else if (Keyboard.getEventKey() == Keyboard.KEY_C) { doCollisionChecking = !doCollisionChecking; } else if (Keyboard.getEventKey() == Keyboard.KEY_B) { renderSkybox = !renderSkybox; } else if (Keyboard.getEventKey() == Keyboard.KEY_V) { wireframe = !wireframe; } else if (Keyboard.getEventKey() == Keyboard.KEY_ESCAPE) { isPaused = !isPaused; Mouse.setGrabbed(!Mouse.isGrabbed()); } else if (Keyboard.getEventKey() == Keyboard.KEY_P) { debugScreen = !debugScreen; } else if (Keyboard.getEventKey() == Keyboard.KEY_1) { ItemBox.setSelectedIndex(0); } else if (Keyboard.getEventKey() == Keyboard.KEY_2) { ItemBox.setSelectedIndex(1); } else if (Keyboard.getEventKey() == Keyboard.KEY_3) { ItemBox.setSelectedIndex(2); } else if (Keyboard.getEventKey() == Keyboard.KEY_4) { ItemBox.setSelectedIndex(3); } else if (Keyboard.getEventKey() == Keyboard.KEY_5) { ItemBox.setSelectedIndex(4); } else if (Keyboard.getEventKey() == Keyboard.KEY_6) { ItemBox.setSelectedIndex(5); } else if (Keyboard.getEventKey() == Keyboard.KEY_7) { ItemBox.setSelectedIndex(6); } else if (Keyboard.getEventKey() == Keyboard.KEY_8) { ItemBox.setSelectedIndex(7); } else if (Keyboard.getEventKey() == Keyboard.KEY_9) { ItemBox.setSelectedIndex(8); } } } if (closeRequested) break; } // Cleanup terrain.release(); Display.destroy(); } public static void main(String[] args) { switch (LWJGLUtil.getPlatform()) { case LWJGLUtil.PLATFORM_MACOSX: addLibraryPath(new File("libs/lwjgl-2.8.4/native/macosx")); break; case LWJGLUtil.PLATFORM_LINUX: addLibraryPath(new File("libs/lwjgl-2.8.4/native/linux")); if (System.getProperty("os.arch").contains("64")) { System.loadLibrary("openal64"); } else { System.loadLibrary("openal"); } break; case LWJGLUtil.PLATFORM_WINDOWS: addLibraryPath(new File("libs/lwjgl-2.8.4/native/windows")); if (System.getProperty("os.arch").contains("64")) { System.loadLibrary("OpenAL64"); } else { System.loadLibrary("OpenAL32"); } break; default: System.out.println("Unsupported operating system: {}"); System.exit(1); } Game cubeGame = new Game(); cubeGame.start(); } public void finalize() { terrain.release(); AL.destroy(); Display.destroy(); } public void update() { camera.hasGravitiedThisFrame = false; Lighting.setIsUnderwater(terrain.getCubeTypeAtVector(camera.coordinates) == BlockManager.TYPE_WATER); float movementSpeed = flyMode ? MOVEMENT_SPEED_FLYMODE : MOVEMENT_SPEED; if (Lighting.isUnderwater) movementSpeed *= 0.3; // Handle mouse movement camera.addRotation(new Vector3f(Mouse.getDY() * MOUSE_SPEED_SCALE, -Mouse.getDX() * MOUSE_SPEED_SCALE, 0.0f)); // Handle keypresses if(Keyboard.isKeyDown(Keyboard.KEY_W)) camera.move(movementSpeed, Camera.FORWARD, 0, doCollisionChecking, flyMode); if(Keyboard.isKeyDown(Keyboard.KEY_S)) camera.move(movementSpeed, Camera.BACKWARD, 0, doCollisionChecking, flyMode); if(Keyboard.isKeyDown(Keyboard.KEY_A)) camera.move(movementSpeed / 2, Camera.LEFT, 0, doCollisionChecking, flyMode); if(Keyboard.isKeyDown(Keyboard.KEY_D)) camera.move(movementSpeed / 2, Camera.RIGHT, 0, doCollisionChecking, flyMode); if(Keyboard.isKeyDown(Keyboard.KEY_SPACE)) { if (camera.grounded) { camera.gravitySpeed = -0.18f; camera.grounded = false; } } else { if (camera.gravitySpeed < 0.0f) camera.gravitySpeed = 0.0f; } if(Keyboard.isKeyDown(Keyboard.KEY_LCONTROL)) camera.move(0, Camera.RIGHT, FALSE_GRAVITY_SPEED * 2, doCollisionChecking, flyMode); // handle mouse clicks if (Mouse.isButtonDown(0) && (mouseDelayer == 0)) { pickBlock = true; mouseDelayer = 20; } else if (Mouse.isButtonDown(1) && (mouseDelayer == 0)) { placeBlock = true; mouseDelayer = 20; } //System.out.println(Mouse.getDWheel()); int dwheel = Mouse.getDWheel(); if (dwheel < 0) { ItemBox.setSelectedIndex(ItemBox.getSelectedIndex() + 1); } else if (dwheel > 0) { ItemBox.setSelectedIndex(ItemBox.getSelectedIndex() - 1); } if (mouseDelayer > 0) mouseDelayer--; // Apply gravity if(!flyMode) { camera.move(0, Camera.FORWARD, camera.gravitySpeed, doCollisionChecking, flyMode); camera.updateGravity(); } camera.updateLookingAt(); terrain.updateVisibleChunks(camera.coordinates); long timeElapsed = System.currentTimeMillis() - startTime; float sinPos = (float) Math.sin((timeElapsed / 80000.0f) % (2.0f * Math.PI) ); sinPos = ( (sinPos + 1) / 2); if (sinPos < 0.4f) sinPos = 0.4f; if (sinPos > 0.6f) sinPos = 0.6f; sinPos = (sinPos - 0.4f) * 4.0f + 0.2f; AMBIENCE_COLOR.x = sinPos - 0.4f; AMBIENCE_COLOR.y = sinPos - 0.4f; AMBIENCE_COLOR.z = sinPos - 0.2f; if (pickBlock) { pickBlock = false; if (camera.hasTarget) terrain.deleteBlockAt(camera.target); } if (placeBlock ) { placeBlock = false; if (camera.hasTarget) terrain.placeBlockAt(camera.coordinates, camera.target); } } public void initGl() { GL11.glEnable(GL11.GL_TEXTURE_2D); GL11.glEnable(GL11.GL_DEPTH_TEST); GL11.glEnable(GL11.GL_CULL_FACE); GL11.glEnable(GL11.GL_LIGHTING); GL11.glShadeModel(GL11.GL_SMOOTH); GL11.glEnable(GL11.GL_BLEND); GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_NEAREST); GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST); } public void render3d() { if(wireframe) GL11.glPolygonMode(GL11.GL_FRONT_AND_BACK, GL11.GL_LINE); else GL11.glPolygonMode(GL11.GL_FRONT_AND_BACK, GL11.GL_FILL); // Apply the camera matrix camera.applyMatrix(); // Render the terrain terrain.render(); } public void renderTextLine(int lineNum, String string) { renderTextLine(lineNum, string, 0); } public void renderTextLine(int lineNum, String string, int offsetX) { font.drawString(offsetX + 2, lineNum * TEXT_LINE_HEIGHT + 2, string, Color.black); font.drawString(offsetX, lineNum * TEXT_LINE_HEIGHT, string, Color.white); } public void render2d() { if (isPaused) { // set the color of the quad (R,G,B,A) GL11.glEnable(GL11.GL_BLEND); GL11.glColor4f(0.3f, 0.3f, 0.3f,0.7f); // draw quad GL11.glBegin(GL11.GL_QUADS); GL11.glVertex2f(0,0); GL11.glVertex2f(Display.getDesktopDisplayMode().getWidth(),0); GL11.glVertex2f(Display.getDesktopDisplayMode().getWidth(),Display.getDesktopDisplayMode().getHeight()); GL11.glVertex2f(0,Display.getDesktopDisplayMode().getHeight()); GL11.glEnd(); GL11.glDisable(GL11.GL_BLEND); } GL11.glEnable(GL11.GL_TEXTURE_2D); GL11.glEnable(GL11.GL_BLEND); GL11.glShadeModel(GL11.GL_SMOOTH); ItemBox.render(); TextureImpl.unbind(); if (debugScreen) { int i = 0; renderTextLine(i++, "x: " + camera.coordinates.x ); renderTextLine(i++, "y: " + camera.coordinates.y ); renderTextLine(i++, "z: " + camera.coordinates.z ); renderTextLine(i++, displayFps + " fps, " + displayUps + " ups"); int totalMem = (int) Runtime.getRuntime().totalMemory() / (1000000); int usedMem = totalMem - ((int) Runtime.getRuntime().freeMemory() / (1000000)); renderTextLine(i++, "mem/total: " + usedMem + "/" + totalMem); } GL11.glDisable(GL11.GL_BLEND); GL11.glDisable(GL11.GL_TEXTURE_2D); } public void render() { Lighting.initLighting(); Lighting.initFog(); int width = Display.getDesktopDisplayMode().getWidth(); int height = Display.getDesktopDisplayMode().getHeight(); GL11.glMatrixMode(GL11.GL_PROJECTION); GL11.glLoadIdentity(); float ratio = ((float)Display.getDisplayMode().getWidth())/((float)Display.getDisplayMode().getHeight()); GLU.gluPerspective(FOV, ratio, 0.1f, 160f); GL11.glMatrixMode(GL11.GL_MODELVIEW); if (!Lighting.isUnderwater) { GL11.glClearColor(AMBIENCE_COLOR.x, AMBIENCE_COLOR.y, AMBIENCE_COLOR.z, AMBIENCE_COLOR.a); } else { GL11.glClearColor(AMBIENCE_COLOR.x - 0.7f, AMBIENCE_COLOR.y - 0.7f, AMBIENCE_COLOR.z - 0.6f, AMBIENCE_COLOR.a); } GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT); GL11.glPushMatrix(); render3d(); GL11.glPopMatrix(); GL11.glMatrixMode(GL11.GL_PROJECTION); GL11.glLoadIdentity(); GL11.glOrtho(0, width, height, 0, 1, -1); GL11.glMatrixMode(GL11.GL_MODELVIEW); GL11.glDisable( GL11.GL_DEPTH_TEST ); GL11.glDisable(GL11.GL_LIGHTING); GL11.glDisable(GL11.GL_CULL_FACE); GL11.glPushMatrix(); render2d(); GL11.glPopMatrix(); GL11.glEnable(GL11.GL_CULL_FACE); GL11.glEnable(GL11.GL_LIGHTING); GL11.glEnable(GL11.GL_DEPTH_TEST); Display.update(); } private static void addLibraryPath(File libPath) { try { String envPath = System.getProperty("java.library.path"); if (envPath == null || envPath.isEmpty()) { System.setProperty("java.library.path", libPath.getAbsolutePath()); } else { System.setProperty("java.library.path", envPath + File.pathSeparator + libPath.getAbsolutePath()); } final Field usrPathsField = ClassLoader.class.getDeclaredField("usr_paths"); usrPathsField.setAccessible(true); List<String> paths = new ArrayList<String>(Arrays.asList((String[]) usrPathsField.get(null))); if (paths.contains(libPath.getAbsolutePath())) { return; } paths.add(0, libPath.getAbsolutePath()); // Add to beginning, to override system libraries usrPathsField.set(null, paths.toArray(new String[paths.size()])); } catch (Exception e) { System.out.println("Couldn't link static libraries."); System.exit(1); } } }