var canvas; var context; var lastTime; var updateIntervalId; var camera = { x: 0, y: 0, center: { x: 0, y: 0 }, movementSpeed: 3 }; var isDragging = false; var dragCompleted = false; var startDrag = { x: 0, y: 0 }; var dragDelta = { x: 0, y: 0 }; var keys = []; var server; var socketHandler = { onmessage: (message) => { console.log(message);}, onopen: (data) => { console.log(data);}, onclose: (data) => { console.log(data);}, onError: (data) => { console.error(data);}, }; var spritesheet; var sprites; var background; var room = { width: 2048, height: 1440, center: { x: 1024, y: 720 }, tileSize: { width: 16, height: 16 }, }; var player = { x: 3 * room.tileSize.width, y: 3 * room.tileSize.height, width: room.tileSize.width, height: room.tileSize.height, center: { x: room.tileSize.width / 2, y: room.tileSize.height / 2 }, angle: 90 * Math.PI / 180, rotationSpeed: 3 * Math.PI / 180, movementSpeed: 3, target: { x: 3 * room.tileSize.width, y: 3 * room.tileSize.height }, }; var floater = { position: { x: 0, y: 0, }, width: room.tileSize.width, height: room.tileSize.height, center: { x: room.tileSize.width / 2, y: room.tileSize.height / 2 }, }; var tweenId = -1; function animate() { context.save(); context.translate(0.5, 0.5); clearFrame(context); draw(context); context.restore(); requestAnimationFrame(animate); } function clearFrame(context) { context.fillStyle = "#283848"; context.beginPath(); context.rect(0, 0, canvas.width, canvas.height); context.fill(); } function init() { lastTime = new Date().getUTCMilliseconds(); context = canvas.getContext('2d'); keys = []; for (let i = 0; i < 256; i++) { keys[i] = false; } onResize(); initBackground(); initFloater(); } function update(delta) { updateCamera(delta); updateBackground(delta); updatePlayer(delta); updateFloater(delta); Tween.update(); } function draw(context) { context.save(); context.translate(-camera.x + dragDelta.x, -camera.y + dragDelta.y); drawBackground(context); drawPlayer(context); drawFloater(context); context.restore(); } function onResize() { let dpi = window.devicePixelRatio; canvas.width = canvas.clientWidth; canvas.height = canvas.clientHeight; context.width = canvas.clientWidth / dpi; context.height = canvas.clientHeight / dpi; let deltaX = camera.center.x - canvas.width / 2; let deltaY = camera.center.y - canvas.height / 2; camera.center.x = canvas.width / 2; camera.center.y = canvas.height / 2; camera.x += deltaX; camera.y += deltaY; } function onKeyDown(event) { keys[event.keyCode] = true; } function onKeyUp(event) { keys[event.keyCode] = false; } function onMouseMove(event) { if (isDragging) { dragDelta.x = event.clientX - startDrag.x; dragDelta.y = event.clientY - startDrag.y; } } function onMouseDown(event) { if (isDragging) { return; } dragCompleted = false; if (event.button == 0) { isDragging = true; } startDrag.x = event.clientX; startDrag.y = event.clientY; dragDelta.x = 0; dragDelta.y = 0; startDrag.time = new Date().getUTCMilliseconds(); } function onMouseUp(event) { if (event.button == 2) { //startDrag.time + 100 >= new Date().getUTCMilliseconds() player.target.x = (Math.floor((camera.x + startDrag.x) / room.tileSize.width) * room.tileSize.width); player.target.y = (Math.floor((camera.y + startDrag.y) / room.tileSize.height) * room.tileSize.height); return; } if (isDragging) { isDragging = false; dragCompleted = true; } } function onRightClick(event) { event.preventDefault(); } function onTouchStart(event) { if (event.touches.length == 2) { isDragging = true; startDrag.x = parseInt(event.targetTouches[0].clientX); startDrag.y = parseInt(event.targetTouches[0].clientY); dragDelta.x = 0; dragDelta.y = 0; startDrag.time = new Date().getUTCMilliseconds(); } } function onTouchMove(event) { if (event.touches.length == 2) { dragDelta.x = parseInt(event.targetTouches[0].clientX) - startDrag.x; dragDelta.y = parseInt(event.targetTouches[0].clientY) - startDrag.y; } } function onTouchEnd(event) { if (isDragging) { isDragging = false; dragCompleted = true; return; } if (event.touches.length == 0) { //I've let go of all points if (!isDragging && !dragCompleted) { player.target.x = (Math.floor((camera.x + parseInt(event.changedTouches[0].clientX)) / room.tileSize.width) * room.tileSize.width); player.target.y = (Math.floor((camera.y + parseInt(event.changedTouches[0].clientY)) / room.tileSize.height) * room.tileSize.height); } } } document.addEventListener("DOMContentLoaded", event => { canvas = document.createElement("canvas"); document.getElementById("game").appendChild(canvas); server = new Server( `http://roguelike.eyeofmidas.net:8080`, `ws://roguelike.eyeofmidas.net:14700`, ); server.attachWebsocketHandler(socketHandler); spritesheet = new Spritesheet("./assets", "Tilesheet/monochrome_transparent_packed.png", room.tileSize.width, room.tileSize.height, 0); spritesheet.load().then(() => { sprites = new ColorSpriteCache(spritesheet); buildSprites(); init(); animate(); server.websocketConnect(); }) updateIntervalId = setInterval(() => { let currentTime = new Date().getUTCMilliseconds(); update(1 + ((currentTime - lastTime) / 1000)); lastTime = currentTime; }, 16); }); window.addEventListener("resize", onResize); window.addEventListener("keydown", onKeyDown); window.addEventListener("keyup", onKeyUp); window.addEventListener("mousedown", onMouseDown); window.addEventListener("mousemove", onMouseMove); window.addEventListener("mouseup", onMouseUp); window.addEventListener("contextmenu", onRightClick); window.addEventListener("touchstart", onTouchStart); window.addEventListener("touchmove", onTouchMove); window.addEventListener("touchend", onTouchEnd); function updateCamera(delta) { if (keys[KeyCode.Up]) { camera.y += -camera.movementSpeed * delta; } if (keys[KeyCode.Down]) { camera.y += camera.movementSpeed * delta; } if (keys[KeyCode.Left]) { camera.x += -camera.movementSpeed * delta; } if (keys[KeyCode.Right]) { camera.x += camera.movementSpeed * delta; } } function updateBackground(delta) { let isOutOfBounds = false; if (camera.y + canvas.height > (room.center.y * room.tileSize.height)) { camera.y = (room.center.y * room.tileSize.height) - canvas.height; } if (camera.y < -(room.center.y * room.tileSize.height)) { camera.y = -(room.center.y * room.tileSize.height); } if (camera.x + canvas.width > (room.center.x * room.tileSize.width)) { camera.x = (room.center.x * room.tileSize.width) - canvas.width; } if (camera.x < -(room.center.x * room.tileSize.width)) { camera.x = -(room.center.x * room.tileSize.width); } if ((camera.y + canvas.height) - dragDelta.y > (room.center.y * room.tileSize.height)) { isOutOfBounds = true; } if (camera.y - dragDelta.y < -(room.center.y * room.tileSize.height)) { isOutOfBounds = true; } if ((camera.x + canvas.width) - dragDelta.x > (room.center.x * room.tileSize.width)) { isOutOfBounds = true; } if (camera.x - dragDelta.x < -(room.center.x * room.tileSize.width)) { isOutOfBounds = true; } if (dragCompleted) { if (isOutOfBounds) { camera.x -= dragDelta.x * 0.1; camera.y -= dragDelta.y * 0.1; dragDelta.x = dragDelta.x * 0.90; dragDelta.y = dragDelta.y * 0.90; if (Math.abs(dragDelta.x) <= 1 && Math.abs(dragDelta.y) <= 1) { dragDelta.x = 0; dragDelta.y = 0; dragCompleted = false; } } else { camera.x -= dragDelta.x; camera.y -= dragDelta.y; dragDelta.x = 0; dragDelta.y = 0; dragCompleted = false; } } } SpriteKeys = {}; SpriteKeys.Bat1 = 410; SpriteKeys.Hero1 = 25; SpriteKeys.Grass1 = 5; SpriteKeys.Grass2 = 6; SpriteKeys.Grass3 = 7; SpriteKeys.Floor1 = 2; SpriteKeys.Floor2 = 3; SpriteKeys.Floor3 = 4; SpriteKeys.OutsideWallNW = 640; SpriteKeys.OutsideWallN = 641; SpriteKeys.OutsideWallNE = 642; SpriteKeys.OutsideWallW = 688; SpriteKeys.OutsideWallE = 690; SpriteKeys.OutsideWallSW = 736; SpriteKeys.OutsideWallS = 737; SpriteKeys.OutsideWallSE = 738; ColorSprites = {}; ColorSprites.GreenGrass1 = 1; ColorSprites.GreenGrass2 = 2; ColorSprites.GreenGrass3 = 3; ColorSprites.BrownDirt1 = 4; ColorSprites.BrownDirt2 = 5; ColorSprites.BrownDirt3 = 6; ColorSprites.BlackBat1 = 7; ColorSprites.YellowHero1 = 8; ColorSprites.GrayWallNW = 9; ColorSprites.GrayWallN = 10; ColorSprites.GrayWallNE = 11; ColorSprites.GrayWallW = 12; ColorSprites.GrayWallE = 13; ColorSprites.GrayWallSW = 14; ColorSprites.GrayWallS = 15; ColorSprites.GrayWallSE = 16; function buildSprites() { sprites.add(ColorSprites.GreenGrass1, room.tileSize.width, room.tileSize.height, SpriteKeys.Grass1, "#25591f"); sprites.add(ColorSprites.GreenGrass2, room.tileSize.width, room.tileSize.height, SpriteKeys.Grass2, "#25591f"); sprites.add(ColorSprites.GreenGrass3, room.tileSize.width, room.tileSize.height, SpriteKeys.Grass3, "#25591f"); sprites.add(ColorSprites.BlackBat1, room.tileSize.width, room.tileSize.height, SpriteKeys.Bat1, "#080808"); sprites.add(ColorSprites.YellowHero1, room.tileSize.width, room.tileSize.height, SpriteKeys.Hero1, "#DADA22"); sprites.add(ColorSprites.BrownDirt1, room.tileSize.width, room.tileSize.height, SpriteKeys.Floor1, "#CD853F"); sprites.add(ColorSprites.BrownDirt2, room.tileSize.width, room.tileSize.height, SpriteKeys.Floor2, "#CD853F"); sprites.add(ColorSprites.BrownDirt3, room.tileSize.width, room.tileSize.height, SpriteKeys.Floor3, "#CD853F"); sprites.add(ColorSprites.GrayWallNW, room.tileSize.width, room.tileSize.height, SpriteKeys.OutsideWallNW, "#868686"); sprites.add(ColorSprites.GrayWallN, room.tileSize.width, room.tileSize.height, SpriteKeys.OutsideWallN, "#868686"); sprites.add(ColorSprites.GrayWallNE, room.tileSize.width, room.tileSize.height, SpriteKeys.OutsideWallNE, "#868686"); sprites.add(ColorSprites.GrayWallW, room.tileSize.width, room.tileSize.height, SpriteKeys.OutsideWallW, "#868686"); sprites.add(ColorSprites.GrayWallE, room.tileSize.width, room.tileSize.height, SpriteKeys.OutsideWallE, "#868686"); sprites.add(ColorSprites.GrayWallSW, room.tileSize.width, room.tileSize.height, SpriteKeys.OutsideWallSW, "#868686"); sprites.add(ColorSprites.GrayWallS, room.tileSize.width, room.tileSize.height, SpriteKeys.OutsideWallS, "#868686"); sprites.add(ColorSprites.GrayWallSE, room.tileSize.width, room.tileSize.height, SpriteKeys.OutsideWallSE, "#868686"); } function initBackground() { background = document.createElement("canvas"); background.width = room.width * room.tileSize.width; background.height = room.height * room.tileSize.height; loadRoom(); } async function loadRoom(x = 0, y = 0, z = 0) { let roomData = await server.apiGet(`/room/${x},${y},${z}`); room = roomData.room; background = document.createElement("canvas"); background.width = room.width * room.tileSize.width; background.height = room.height * room.tileSize.height; let backgroundContext = background.getContext("2d"); roomData.backgroundRegions.forEach(region => { backgroundContext.fillStyle = region.color; backgroundContext.beginPath(); backgroundContext.rect(region.x * room.tileSize.width, region.y * room.tileSize.height, region.width * room.tileSize.width, region.height * room.tileSize.height); backgroundContext.fill(); }); for(let x in roomData.backgroundTiles) { for(let y in roomData.backgroundTiles[x]) { sprites.drawOnGrid(backgroundContext, roomData.backgroundTiles[x][y], { x: x, y: y }, room.tileSize); } }; } function drawBackground(context) { context.drawImage(background, -(room.center.x * room.tileSize.width), -(room.center.y * room.tileSize.height)); } function updatePlayer(delta) { if (player.target.y == player.y) { if (keys[KeyCode.W]) { player.target.y += -room.tileSize.height; } if (keys[KeyCode.S]) { player.target.y += room.tileSize.height; } } if (player.target.x == player.x) { if (keys[KeyCode.A]) { player.target.x += -room.tileSize.width; } if (keys[KeyCode.D]) { player.target.x += room.tileSize.width; } } if (Math.abs(player.x - player.target.x) <= player.movementSpeed) { player.x = player.target.x; } if (Math.abs(player.y - player.target.y) <= player.movementSpeed) { player.y = player.target.y; } if (player.target.x != player.x || player.target.y != player.y) { let angle = (Math.atan2(player.target.y - player.y, player.target.x - player.x)); player.x += player.movementSpeed * Math.cos(angle); player.y += player.movementSpeed * Math.sin(angle); } } function drawPlayer(context) { context.save(); context.translate(player.x, player.y); let hero = sprites.get(ColorSprites.YellowHero1); context.drawImage(hero.image, 0, 0); context.restore(); } function initFloater() { floaterToRandomPoint(); } function floaterToRandomPoint() { let randomPoint = {position: { x: 0, y: 0 }}; randomPoint.position.x = Math.floor(Math.floor((320 * Math.random() - 160) / room.tileSize.width) * room.tileSize.width); randomPoint.position.y = Math.floor(Math.floor((320 * Math.random() - 160) / room.tileSize.height) * room.tileSize.height); let distance = Math.sqrt( Math.pow(randomPoint.position.x - floater.position.x, 2) + Math.pow(randomPoint.position.y - floater.position.y, 2) ); tweenId = Tween.create(floater, randomPoint, distance * 8, Tween.Easing.Cubic.EaseInOut, () => { setTimeout(floaterToRandomPoint, Math.floor(5 * Math.random() + 1) * 1000); }); } function updateFloater(delta) { } function drawFloater(context) { context.save(); context.translate(floater.position.x, floater.position.y); let bat = sprites.get(ColorSprites.BlackBat1); context.drawImage(bat.image, 0, 0); context.restore(); }