diff --git a/index.html b/index.html index 5bf17e6..c972a8f 100644 --- a/index.html +++ b/index.html @@ -5,8 +5,14 @@ -
-Loading page... + +
+ +
+
+ Loading page... +
+ diff --git a/src/js/net/minecraft/client/GameWindow.js b/src/js/net/minecraft/client/GameWindow.js index 744f1a8..80b3c87 100644 --- a/src/js/net/minecraft/client/GameWindow.js +++ b/src/js/net/minecraft/client/GameWindow.js @@ -1,6 +1,7 @@ window.GameWindow = class { constructor(minecraft, canvasWrapperId) { + this.minecraft = minecraft; this.canvasWrapperId = canvasWrapperId; this.mouseMotionX = 0; @@ -30,14 +31,31 @@ window.GameWindow = class { // Mouse buttons document.addEventListener('click', event => minecraft.onMouseClicked(event.button), false); + // Keyboard interaction with screen + window.addEventListener('keydown', function (event) { + if (!(minecraft.currentScreen === null)) { + // Handle key type on screen + let consumed = minecraft.currentScreen.keyTyped(event.code); + + if (consumed) { + // Cancel browser interaction + event.preventDefault(); + } + } + }); + // Create keyboard Keyboard.create(); } + requestFocus() { + this.renderer.canvasElement.requestPointerLock(); + } + loadRenderer(renderer) { this.renderer = renderer; - let canvas = renderer.canvasElement; + let canvas = this.renderer.canvasElement; // Add web renderer canvas to wrapper this.wrapper.appendChild(canvas); @@ -46,8 +64,11 @@ window.GameWindow = class { this.onResize(); // Request focus + let minecraft = this.minecraft; canvas.onclick = function () { - canvas.requestPointerLock(); + if (minecraft.currentScreen === null) { + canvas.requestPointerLock(); + } } } @@ -66,15 +87,26 @@ window.GameWindow = class { // Reinitialize gui this.renderer.initializeGui(); + + // Reinitialize current screen + if (!(this.minecraft.currentScreen === null)) { + this.minecraft.currentScreen.init(this.minecraft, this.width, this.height); + } } onFocusChanged() { this.mouseLocked = document.pointerLockElement === this.renderer.canvasElement; + + // Open in-game menu + if (!this.mouseLocked && this.minecraft.currentScreen === null) { + this.minecraft.displayScreen(new GuiIngameMenu()); + } } onMouseMove(event) { this.mouseMotionX = event.movementX; this.mouseMotionY = -event.movementY; + this.mouseX = event.clientX; this.mouseY = event.clientY; } diff --git a/src/js/net/minecraft/client/Minecraft.js b/src/js/net/minecraft/client/Minecraft.js index 73221cb..8ec1ec5 100644 --- a/src/js/net/minecraft/client/Minecraft.js +++ b/src/js/net/minecraft/client/Minecraft.js @@ -4,10 +4,22 @@ window.Minecraft = class { * Create Minecraft instance and render it on a canvas */ constructor(canvasWrapperId) { + this.currentScreen = null; + this.loadingScreen = null; + + // Create window and world renderer this.window = new GameWindow(this, canvasWrapperId); this.worldRenderer = new WorldRenderer(this, this.window); this.timer = new Timer(20); + // Create current screen and overlay + this.ingameOverlay = new IngameOverlay(this.window); + + // Display loading screen + this.loadingScreen = new GuiLoadingScreen(); + this.loadingScreen.setTitle("Building terrain..."); + this.displayScreen(this.loadingScreen); + this.frames = 0; this.lastTime = Date.now(); @@ -22,10 +34,6 @@ window.Minecraft = class { this.player = new Player(this.world); this.pickedBlock = 1; - // Create current screen and overlay - this.ingameOverlay = new IngameOverlay(this.window); - this.currentScreen = null; - // Initialize this.init(); } @@ -80,25 +88,52 @@ window.Minecraft = class { onRender(partialTicks) { // Player rotation - if (this.window.mouseLocked) { + if (this.window.mouseLocked && !(this.currentScreen === "null")) { this.player.turn(this.window.mouseMotionX, this.window.mouseMotionY); this.window.mouseMotionX = 0; this.window.mouseMotionY = 0; } - while (this.world.updateLights()) ; + // Update lights + while (this.world.updateLights()) { + // Empty + } // Render the game this.worldRenderer.render(partialTicks); } + displayScreen(screen) { + // Switch screen + this.currentScreen = screen; + + // Initialize new screen + if (screen === null) { + this.window.requestFocus(); + } else { + screen.init(this, this.window.width, this.window.height); + } + } + onTick() { // Tick world this.world.onTick(); // Tick the player this.player.onTick(); + + // Update loading progress + if (!(this.loadingScreen === null)) { + let progress = Math.max(0, 1 - this.world.lightUpdateQueue.length / 10000); + this.loadingScreen.setProgress(progress); + + // Finish loading + if (progress >= 1) { + this.loadingScreen = null; + this.displayScreen(null); + } + } } onMouseClicked(button) { diff --git a/src/js/net/minecraft/client/gui/Gui.js b/src/js/net/minecraft/client/gui/Gui.js index 96f5f81..ae0d777 100644 --- a/src/js/net/minecraft/client/gui/Gui.js +++ b/src/js/net/minecraft/client/gui/Gui.js @@ -1,10 +1,23 @@ window.Gui = class { drawRect(stack, left, top, right, bottom, color, alpha = 1) { + stack.save(); stack.fillStyle = color; stack.globalAlpha = alpha; stack.fillRect(left, top, right - left, bottom - top); - stack.globalAlpha = alpha; + stack.restore(); + } + + drawString(stack, string, x, y, color) { + this._drawString(stack, string, x, y, color, 0, false); + } + + _drawString(stack, string, x, y, color, alignment, bold) { + let size = 24; + stack.font = (bold ? "bold" : "normal") + " " + size + "px Minecraftia"; + stack.fillStyle = color; + stack.textAlign = alignment === 0 ? "center" : alignment < 0 ? "left" : "right"; + stack.fillText(string, x, y); } drawTexture(stack, texture, x, y, width, height, alpha = 1.0) { @@ -12,9 +25,21 @@ window.Gui = class { } drawSprite(stack, texture, spriteX, spriteY, spriteWidth, spriteHeight, x, y, width, height, alpha = 1.0) { + stack.save(); stack.globalAlpha = alpha; stack.drawImage(texture, spriteX, spriteY, spriteWidth, spriteHeight, x, y, width, height); - stack.globalAlpha = 1.0; + stack.restore(); + } + + drawBackground(stack, texture, width, height, scale = 8) { + let pattern = stack.createPattern(texture, "repeat"); + stack.save(); + stack.filter = "brightness(50%)"; + stack.scale(scale, scale); + stack.rect(0, 0, width / scale, height / scale); + stack.fillStyle = pattern; + stack.fill(); + stack.restore(); } loadTexture(path) { diff --git a/src/js/net/minecraft/client/gui/GuiScreen.js b/src/js/net/minecraft/client/gui/GuiScreen.js index f723ed1..f802d7d 100644 --- a/src/js/net/minecraft/client/gui/GuiScreen.js +++ b/src/js/net/minecraft/client/gui/GuiScreen.js @@ -1,5 +1,21 @@ -window.GuiScreen = class { +window.GuiScreen = class extends Gui { + init(minecraft, width, height) { + this.minecraft = minecraft; + this.width = width; + this.height = height; + } + drawScreen(stack, mouseX, mouseY, partialTicks) { + + } + + keyTyped(code) { + if (code === "Escape") { + this.minecraft.displayScreen(null); + return true; + } + return false; + } } \ No newline at end of file diff --git a/src/js/net/minecraft/client/gui/screens/GuiIngameMenu.js b/src/js/net/minecraft/client/gui/screens/GuiIngameMenu.js new file mode 100644 index 0000000..fe80bac --- /dev/null +++ b/src/js/net/minecraft/client/gui/screens/GuiIngameMenu.js @@ -0,0 +1,11 @@ +window.GuiIngameMenu = class extends GuiScreen { + + constructor() { + super(); + } + + drawScreen(stack, mouseX, mouseY, partialTicks) { + + } + +} \ No newline at end of file diff --git a/src/js/net/minecraft/client/gui/screens/GuiLoadingScreen.js b/src/js/net/minecraft/client/gui/screens/GuiLoadingScreen.js new file mode 100644 index 0000000..4007f75 --- /dev/null +++ b/src/js/net/minecraft/client/gui/screens/GuiLoadingScreen.js @@ -0,0 +1,48 @@ +window.GuiLoadingScreen = class extends GuiScreen { + + constructor() { + super(); + + this.textureBackground = this.loadTexture("background.png"); + } + + drawScreen(stack, mouseX, mouseY, partialTicks) { + // Render dirt background + this.drawBackground(stack, this.textureBackground, this.width, this.height); + + // Render title + this.drawString(stack, this.title, this.width / 2, this.height / 2 - 20, '#FFFFFF'); + + let progressWidth = 300; + let progressHeight = 5; + + // Render background of progress + this.drawRect( + stack, + this.width / 2 - progressWidth / 2, + this.height / 2 - progressHeight / 2, + this.width / 2 + progressWidth / 2, + this.height / 2 + progressHeight / 2, + '#808080', + ); + + // Render progress + this.drawRect( + stack, + this.width / 2 - progressWidth / 2, + this.height / 2 - progressHeight / 2, + this.width / 2 - progressWidth / 2 + progressWidth * this.progress, + this.height / 2 + progressHeight / 2, + '#80ff80', + ); + } + + setTitle(title) { + this.title = title; + } + + setProgress(progress) { + this.progress = progress; + } + +} \ No newline at end of file diff --git a/src/js/net/minecraft/client/render/WorldRenderer.js b/src/js/net/minecraft/client/render/WorldRenderer.js index 4c67a6a..7d70a09 100644 --- a/src/js/net/minecraft/client/render/WorldRenderer.js +++ b/src/js/net/minecraft/client/render/WorldRenderer.js @@ -120,6 +120,11 @@ window.WorldRenderer = class { let mouseY = this.minecraft.window.mouseY; this.minecraft.ingameOverlay.render(this.stack2d, mouseX, mouseY, partialTicks); + // Render current screen + if (!(this.minecraft.currentScreen === null)) { + this.minecraft.currentScreen.drawScreen(this.stack2d, mouseX, mouseY, partialTicks); + } + // Render actual scene and hud this.webRenderer.render(this.scene, this.camera); this.webRenderer.render(this.scene2d, this.camera2d); diff --git a/src/resources/background.png b/src/resources/background.png new file mode 100644 index 0000000..8e03ddb Binary files /dev/null and b/src/resources/background.png differ diff --git a/src/resources/font.ttf b/src/resources/font.ttf new file mode 100644 index 0000000..7247ad7 Binary files /dev/null and b/src/resources/font.ttf differ diff --git a/src/start.js b/src/start.js index b716e6a..84a2ccc 100644 --- a/src/start.js +++ b/src/start.js @@ -62,6 +62,8 @@ loadScripts([ "src/js/net/minecraft/client/gui/Gui.js", "src/js/net/minecraft/client/gui/GuiScreen.js", "src/js/net/minecraft/client/gui/IngameOverlay.js", + "src/js/net/minecraft/client/gui/screens/GuiLoadingScreen.js", + "src/js/net/minecraft/client/gui/screens/GuiIngameMenu.js", "src/js/net/minecraft/client/GameWindow.js", "src/js/net/minecraft/client/world/block/Block.js", "src/js/net/minecraft/client/world/block/BlockStone.js", diff --git a/style.css b/style.css index a9b4712..2ce76c1 100644 --- a/style.css +++ b/style.css @@ -1,6 +1,17 @@ +@font-face { + font-family: "Minecraftia"; + src: url(src/resources/font.ttf); +} + body { margin: 0; - background-color: black; +} + +#background { + background-image: url(background.png); + background-size: 128px 128px; + image-rendering: pixelated; + filter: brightness(0.5); } #pre-status { @@ -16,19 +27,22 @@ body { -khtml-user-select: none; /* Konqueror HTML */ -moz-user-select: none; /* Old versions of Firefox */ -ms-user-select: none; /* Internet Explorer/Edge */ - user-select: none; /* Non-prefixed version, currently - supported by Chrome, Edge, Opera and Firefox */ + user-select: none; + /* Non-prefixed version, currently + supported by Chrome, Edge, Opera and Firefox */ /* No overflow */ white-space: nowrap; overflow: hidden; /* Font */ font-size: 25px; - font-family: "FoundryGridnik", serif; + font-family: "Minecraftia", sans-serif; color: white; } -#canvas-container { +.fullscreen { + position: absolute; + float: left; display: block; width: 100%; height: 100%;