initiates central physics handling

This commit is contained in:
koehr 2019-06-11 16:49:25 +02:00
parent 7c6e716875
commit 59ac454bc5
5 changed files with 90 additions and 60 deletions

View file

@ -19,7 +19,9 @@ export default {
<style> <style>
html,body,#app { html,body,#app {
display: block; display: flex;
flex-flow: column nowrap;
justify-content: center;
width: 100vw; width: 100vw;
height: 100vh; height: 100vh;
background: black; background: black;
@ -27,5 +29,4 @@ html,body,#app {
padding: 0; padding: 0;
overflow: hidden; overflow: hidden;
} }
</style> </style>

View file

@ -4,6 +4,7 @@
<script> <script>
import solarQuartet from './solar-quartet' import solarQuartet from './solar-quartet'
import { BLOCK_SIZE, STAGE_WIDTH, STAGE_HEIGHT } from './level/def'
export default { export default {
name: 'background', name: 'background',
@ -21,18 +22,16 @@ export default {
time () { this.refresh() } time () { this.refresh() }
}, },
mounted () { mounted () {
const canvasSize = 512
const godraysSize = 128
const canvas = this.$refs.canvas const canvas = this.$refs.canvas
const godraysCanvas = document.createElement('canvas') const godraysCanvas = document.createElement('canvas')
canvas.width = canvasSize canvas.width = STAGE_WIDTH * BLOCK_SIZE
canvas.height = canvasSize canvas.height = STAGE_HEIGHT * BLOCK_SIZE
godraysCanvas.width = godraysSize godraysCanvas.width = ~~(canvas.width / 8.0)
godraysCanvas.height = godraysSize godraysCanvas.height = ~~(canvas.height / 8.0)
this.redraw = solarQuartet.bind( this.redraw = solarQuartet.bind(
null, null,
canvas, canvas.getContext('2d'), canvasSize, canvasSize, canvas, canvas.getContext('2d'), ~~(canvas.width / 2.0), ~~(canvas.height / 2.0),
godraysCanvas, godraysCanvas.getContext('2d'), godraysSize, godraysSize, godraysCanvas, godraysCanvas.getContext('2d'), godraysCanvas.width, godraysCanvas.height,
) )
this.refresh() this.refresh()
}, },
@ -65,8 +64,8 @@ export default {
<style> <style>
#background { #background {
display: block; display: block;
width: 100%; width: var(--field-width);
height: 100%; height: var(--field-height);
object-fit: contain; object-fit: contain;
background: black; background: black;
} }

View file

@ -1,13 +1,14 @@
<template> <template>
<div id="field" :class="daytimeClass"> <div id="field" :class="daytimeClass">
<input v-keep-focussed type="text" <input v-keep-focussed type="text"
@keydown.up="jump = jump || !blocked.down ? jump : 20" @keydown.up="inputY = -1"
@keydown.down="moveTo = 'down'" @keydown.down="inputY = 1"
@keydown.right="moveTo = 'right'" @keydown.right="inputX = -1"
@keydown.left="moveTo = 'left'" @keydown.left="inputX = 1"
@keyup.down="moveTo = null" @keyup.up="inputY = inputY === -1 ? 0 : 1"
@keyup.right="moveTo = null" @keyup.down="inputY = inputY === 1 ? 0 : 1"
@keyup.left="moveTo = null" @keyup.right="inputX = inputX === -1 ? 0 : 1"
@keyup.left="inputX = inputX === 1 ? 0: -1"
@keypress.p="togglePause" @keypress.p="togglePause"
@keydown.space="digging = true" @keydown.space="digging = true"
@keyup.space="digging = false" @keyup.space="digging = false"
@ -18,7 +19,7 @@
<div v-for="(block, x) in row" class="block" :class="[block.type]" /> <div v-for="(block, x) in row" class="block" :class="[block.type]" />
</template> </template>
</div> </div>
<div id="player" :class="[playerDirection]" /> <div id="player" :class="[player.direction]" />
<div id="level-indicator"> <div id="level-indicator">
x:{{ floorX }}, y:{{ floorY }} x:{{ floorX }}, y:{{ floorY }}
<template v-if="moving !== false">({{clock}})</template> <template v-if="moving !== false">({{clock}})</template>
@ -29,36 +30,39 @@
<script> <script>
// import throttle from 'lodash/throttle' // import throttle from 'lodash/throttle'
import Level from './level'
import MountainBackground from './Background' import MountainBackground from './Background'
import Level from './level'
import { Moveable } from './physics'
import {
BLOCK_SIZE,
RECIPROCAL,
STAGE_WIDTH,
STAGE_HEIGHT,
PLAYER_X,
PLAYER_Y
} from './level/def'
const BLOCK_SIZE = 32 const level = new Level(STAGE_WIDTH + 2, STAGE_HEIGHT + 2)
const RECIPROCAL = 1 / BLOCK_SIZE const player = new Moveable(PLAYER_X, PLAYER_Y)
const PLAYER_X = ~~(BLOCK_SIZE / 2) + 1
const PLAYER_Y = BLOCK_SIZE - 15
const PLAYER_MAX_VELOCITY = 32
const level = new Level(BLOCK_SIZE + 2, BLOCK_SIZE + 2)
export default { export default {
name: 'field', name: 'field',
components: { MountainBackground }, components: { MountainBackground },
data () { data () {
return { return {
player,
x: 0, x: 0,
y: 0, y: 12,
playerDirection: 'left', inputX: 0,
playerVelocityX: 0, inputY: 0,
playerVelocityY: 8, time: 250,
moveTo: null,
jump: 0,
digging: false,
gravity: 8.0 / 20,
moving: false, moving: false,
time: 250 lastTick: 0
} }
}, },
mounted () { mounted () {
this.move() this.lastTick = performance.now()
this.move(this.lastTick)
}, },
computed: { computed: {
rows () { return level.grid(this.floorX, this.floorY) }, rows () { return level.grid(this.floorX, this.floorY) },
@ -110,28 +114,21 @@ export default {
} }
}, },
methods: { methods: {
move () { move (thisTick) {
this.moving = requestAnimationFrame(this.move)
// keep roughly 20 fps
if (thisTick - this.lastTick < 50) return
// set time of day in ticks // set time of day in ticks
this.time = (this.time + 0.1) % 1000 this.time = (this.time + 0.1) % 1000
const x = this.x const player = this.player
const y = this.y const x = player.x
const y = player.y
if (this.moveTo !== null) this.playerDirection = this.moveTo let dx = player.vx * player.dir * RECIPROCAL
let dy = player.vy * RECIPROCAL
if (this.moveTo === 'right') {
this.playerVelocityX = 8
} else if (this.moveTo === 'left') {
this.playerVelocityX = -8
} else {
this.playerVelocityX = 0
}
// this.player_velocity_y += this.gravity
let dx = this.playerVelocityX * RECIPROCAL
let dy = (this.playerVelocityY - this.jump) * RECIPROCAL
if (this.jump > 0) this.jump -= 2
// don't walk / fall into blocks // don't walk / fall into blocks
if (dx > 0 && this.blocked.right) dx = 0 if (dx > 0 && this.blocked.right) dx = 0
@ -140,14 +137,14 @@ export default {
if (dy < 0 && this.blocked.up) dy = 0 if (dy < 0 && this.blocked.up) dy = 0
// don't walk, work! // don't walk, work!
if (!this.jump && this.digging) { if (!this.inputY && this.digging) {
dx = 0 dx = 0
this.dig() this.dig()
} }
this.x += dx this.x += dx
this.y += dy this.y += dy
this.moving = setTimeout(() => this.move(), 64) // roughly every 4 frames this.lastTick = thisTick
}, },
dig () { dig () {
console.log('dig', this.playerDirection, this.surroundings[this.playerDirection]) console.log('dig', this.playerDirection, this.surroundings[this.playerDirection])
@ -163,10 +160,9 @@ export default {
}, },
togglePause () { togglePause () {
if (this.moving === false) { // is paused if (this.moving === false) { // is paused
this.moving = true // avoid (unlikely) race condition
this.move() this.move()
} else { } else {
clearTimeout(this.moving) cancelAnimationFrame(this.moving)
this.moving = false this.moving = false
} }
} }
@ -179,7 +175,7 @@ export default {
:root { :root {
--block-size: 32px; --block-size: 32px;
--field-width: 1024px; --field-width: 1024px;
--field-height: 1024px; --field-height: 576px;
--spare-blocks: 2; --spare-blocks: 2;
} }

View file

@ -1,3 +1,15 @@
export const BLOCK_SIZE = 32 // each block is 32̨̣̌̇x32 pixel in size and equals 1m
export const RECIPROCAL = 1 / BLOCK_SIZE
export const STAGE_WIDTH = 32 // 32*32 = 1024 pixel wide stage
export const STAGE_HEIGHT = ~~(STAGE_WIDTH * 0.5625) // 16:9 😎
// the player position is fixed to the middle of the x axis
export const PLAYER_X = ~~(STAGE_WIDTH / 2) + 1
export const PLAYER_Y = ~~(STAGE_HEIGHT * 0.5) // fall from the center
export const GRAVITY = 10 // blocks per second
export const type = { export const type = {
air: {type: 'air', hp: Infinity, walkable: true}, air: {type: 'air', hp: Infinity, walkable: true},
grass: {type: 'grass', hp: 1, walkable: false}, grass: {type: 'grass', hp: 1, walkable: false},

22
src/physics.js Normal file
View file

@ -0,0 +1,22 @@
import { GRAVITY } from './level/def'
/** physics gets input like
instance of Moveable,
position: [x, y],
surroundings: [top, right, bottom, left] where each is a block type
and updates the Moveable instance values accordingly
*/
export class Moveable {
constructor (x, y, direction = 1) {
this.x = x
this.y = y
this.dir = direction
this.vx = 0
this.vy = 0
}
get direction () {
return this.dir > 0 ? 'left' : 'right'
}
}