From 4c545ecb13785f7bf443ec401f2097af7f4ce555 Mon Sep 17 00:00:00 2001 From: Florrie Date: Thu, 23 Aug 2018 23:11:38 -0300 Subject: More coordinate redesign/refactor, more or less --- index.js | 153 +++++++++++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 111 insertions(+), 42 deletions(-) diff --git a/index.js b/index.js index 30e17cc..f9269a4 100644 --- a/index.js +++ b/index.js @@ -47,7 +47,12 @@ const isHealingAction = action => { class Sprite { constructor() { - // X is left/right, Z is forwards/backwards, Y is up/down. + // Coordinates of the BASE of the sprite. Typically, this is the middle of + // the bottom of the sprite's canvas's display rectangle. + // X is right/left, Z is forwards/backwards, Y is up/down. + // +X: Right, -X: Left + // +Z: Closer, -Z: Further + // +Y: Higher, -Y: Lower this.x = 0 this.y = 0 this.z = 0 @@ -70,15 +75,89 @@ class Sprite { } } + getBaseCoordinates() { + // BASE of the sprite. Typically, this is the middle of the bottom of the + // sprite's canvas's display rectangle. This is equivalent to the built-in + // x/y/z properties of the sprite, but usually getBaseCoordinates() should + // be used instead, so that code is more explicit and easy to reason about. + + return { + x: this.x, + y: this.y, + z: this.z + } + } + + getCenterCoordinates() { + // CENTER of the sprite. Typically, this is the center of the sprite's + // canvas's display rectangle. + + const base = this.getBaseCoordinates() + + return { + x: base.x, + y: base.y + this.canvas.height / 2, + z: base.z + } + } + + getDrawCoordinates(camera) { + // DRAW/RENDER position of the sprite. These are the coordinates of where + // the sprite's canvas can directly be drawn onto the screen, in 2D space. + // Since where a sprite is drawn is based on the position of the camera, + // this function requires a camera to be passed. + // Also returned are the 2D draw/render coordinates of the center of the + // sprite (ala getCenterCoordinates) and the width and height of the canvas + // adjusted to the scale ratio (i.e. the actual size at which the canvas + // should be drawn). + + const base = this.getBaseCoordinates() + + const cameraOffsetX = base.x - camera.x + const cameraOffsetY = camera.y - base.y + const cameraOffsetZ = base.z - camera.z + + const scaleRatio = camera.getScaleRatio(cameraOffsetZ) + const drawX = scaleRatio * cameraOffsetX + camera.width * 0.5 + const drawY = scaleRatio * cameraOffsetY + camera.height * 0.5 + + const drawW = this.canvas.width * scaleRatio + const drawH = this.canvas.height * scaleRatio + + const canvasOffsetDrawX = drawX - drawW * 0.5 + const canvasOffsetDrawY = drawY - drawH + + return { + x: canvasOffsetDrawX, + y: canvasOffsetDrawY, + centerX: drawX, + centerY: drawY - drawH * 0.5, + drawW, + drawH + } + } + applySpriteEffects(ctx) {} } class Backdrop extends Sprite { constructor() { super() - // this.image.src = 'img/bg.png' this.image.src = 'img/xy-grid.gif' } + + getBaseCoordinates() { + // Base coordinates of the backdrop are its center. + return this.getCenterCoordinates() + } + + getCenterCoordinates() { + return { + x: this.x, + y: this.y - this.canvas.height / 2, + z: this.z + } + } } class ATBBar { @@ -931,37 +1010,21 @@ class Battle { return a.z < b.z ? 1 : a.z > b.z ? -1 : 0 }) - const spriteData = [] - for (const sprite of allSprites) { + const spriteData = allSprites.map(sprite => { sprite.draw() - - const cameraOffsetX = sprite.x - camera.x - const cameraOffsetY = camera.y - sprite.y - const cameraOffsetZ = sprite.z - camera.z - const scaleRatio = camera.getScaleRatio(cameraOffsetZ) - // const scaleRatio = 1 - const drawX = scaleRatio * cameraOffsetX + camera.width / 2 - const drawY = scaleRatio * cameraOffsetY + camera.height / 2 - - const drawW = sprite.canvas.width * scaleRatio - const drawH = sprite.canvas.height * scaleRatio - - const canvasOffsetDrawX = drawX - drawW / 2 - const canvasOffsetDrawY = drawY - drawH / 2 - - spriteData.push({drawX, drawY, canvasOffsetDrawX, canvasOffsetDrawY, drawW, drawH, scaleRatio, sprite}) - } + return Object.assign({sprite}, sprite.getDrawCoordinates(camera)) + }) window.spriteData = spriteData - for (const { canvasOffsetDrawX, canvasOffsetDrawY, drawW, drawH, sprite } of spriteData) { - ctx.drawImage(sprite.canvas, canvasOffsetDrawX, canvasOffsetDrawY, drawW, drawH) + for (const { x, y, drawW, drawH, sprite } of spriteData) { + ctx.drawImage(sprite.canvas, x, y, drawW, drawH) } - for (const { drawX, canvasOffsetDrawY, sprite } of spriteData) { + for (const { centerX, y, sprite } of spriteData) { const overlayHPBar = overlayHPBars.find(o => o.battleCharacter === sprite) if (overlayHPBar) { - overlayHPBar.x = drawX - overlayHPBar.y = canvasOffsetDrawY + overlayHPBar.x = centerX + overlayHPBar.y = y } } @@ -1061,12 +1124,10 @@ class Battle { } for (const { x, y, battleCharacter } of overlayHPBars) { - const { drawX: spriteX, canvasOffsetDrawY: spriteY } = spriteData.find(o => o.sprite === battleCharacter) - const hpBar = battleCharacter.hpBar hpBar.draw() - const drawX = Math.min(this.canvas.width - 10 - hpBar.canvas.width, Math.max(10 + hpBar.labelCanvas.width, Math.round(spriteX - hpBar.canvas.width / 2))) - const drawY = Math.min(this.canvas.height - 20, Math.max(10, Math.round(spriteY - hpBar.canvas.height))) + const drawX = Math.min(this.canvas.width - 10 - hpBar.canvas.width, Math.max(10 + hpBar.labelCanvas.width, Math.round(x - hpBar.canvas.width / 2))) + const drawY = Math.min(this.canvas.height - 20, Math.max(10, Math.round(y - hpBar.canvas.height))) ctx.drawImage(hpBar.canvas, drawX, drawY) ctx.drawImage(hpBar.labelCanvas, drawX - hpBar.labelCanvas.width - 2, drawY - 1) } @@ -1299,11 +1360,14 @@ class BattleCamera extends Camera { } } -class MagicProjectile { +class MagicProjectile extends Sprite { constructor(caster, target, action) { - this.x = caster.x - this.y = caster.y - this.z = caster.z + super() + + const center = caster.getCenterCoordinates() + this.x = center.x + this.y = center.y + this.z = center.z this.target = target this.action = action @@ -1311,18 +1375,21 @@ class MagicProjectile { this.canvas = document.createElement('canvas') this.canvas.width = 8 this.canvas.height = 8 + + delete this.image } update(dt) { // TODO: Good animation, make distance affect acceleration, not velocity - const xvel = 5 * (this.target.x - this.x) - const yvel = 5 * (this.target.y - this.y) - const zvel = 5 * (this.target.z - this.z) + const target = this.target.getCenterCoordinates() + const xvel = 5 * (target.x - this.x) + const yvel = 5 * (target.y - this.y) + const zvel = 5 * (target.z - this.z) this.x += dt * xvel this.y += dt * yvel this.z += dt * zvel - if (Math.abs(this.target.x - this.x) <= 5 && Math.abs(this.target.y - this.y) <= 5 && Math.abs(this.target.z - this.z) <= 5) { + if (Math.abs(target.x - this.x) <= 5 && Math.abs(target.y - this.y) <= 5 && Math.abs(target.z - this.z) <= 5) { if (this.action.target === 'enemy') { if (this.action.damage) this.target.takeDamage(this.action.damage) if (this.action.stun) this.target.addStunTime(this.action.stun || 0) @@ -1457,11 +1524,11 @@ const basicAI = function() { const battle = new Battle({ teamData: [ {characterData: [ - {x: -50, y: 30, name: 'Ren', hp: 400, maxHP: 400, knownActions: ['fire', 'fira', 'firaga', 'blizz', 'blizzara', 'cure'], determineChain: basicAI}, - {x: -75, y: 30, name: 'Fie', hp: 375, maxHP: 375, knownActions: ['fire', 'blizz', 'blizzara', 'blizzaga', 'aqua', 'aquara', 'curasa'], determineChain: basicAI} + {x: -50, y: 0, z: 10, name: 'Ren', hp: 400, maxHP: 400, knownActions: ['fire', 'fira', 'firaga', 'blizz', 'blizzara', 'cure'], determineChain: basicAI}, + {x: -75, y: 0, z: -10, name: 'Fie', hp: 375, maxHP: 375, knownActions: ['fire', 'blizz', 'blizzara', 'blizzaga', 'aqua', 'aquara', 'curasa'], determineChain: basicAI} ]}, {characterData: [ - {x: 75, y: 40, name: 'Manasvin Warmech', hp: 1200, maxHP: 1200, knownActions: ['aqua', 'aquaga', 'manasvinSwipe', 'manasvinRecover'], determineChain: basicAI, knockbackMultiplier: 0} + {x: 75, y: 0, z: 0, name: 'Manasvin Warmech', hp: 1200, maxHP: 1200, knownActions: ['aqua', 'aquaga', 'manasvinSwipe', 'manasvinRecover'], determineChain: basicAI, knockbackMultiplier: 0} ]} ] }) @@ -1475,7 +1542,7 @@ camera.width = canvas.width camera.height = canvas.height // camera.warpTo(battle.playerCharacter) camera.x = 0 -camera.y = 0 +camera.y = 40 camera.z = 0 for (let i = 0; i < 5 + 10 * Math.random(); i++) { @@ -1490,6 +1557,8 @@ battle.canvas.width = canvas.width battle.canvas.height = canvas.height battle.backdrop.z = 80 +battle.backdrop.y = 80 +battle.backdrop.image.src = 'img/bg.png' let lastTime = Date.now() -- cgit 1.3.0-6-gf8a5