You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

194 lines
6.6 KiB
Vue

<template>
<div id="field">
<input v-keep-focussed type="text"
@keydown.up="player_push_y = -8"
@keydown.down="player_push_y = 8"
@keydown.right="player_push_x = 8"
@keydown.left="player_push_x = -8"
@keyup.up="player_push_y = 0"
@keyup.down="player_push_y = 0"
@keyup.right="player_push_x = 0"
@keyup.left="player_push_x = 0"
/>
<mountain-background :x="128 + x / 8" />
<div id="wrap" :style="{transform: `translate(${tx}px, ${ty}px)`}">
<template v-for="row in rows">
<div v-for="block in row" class="block" :class="[block.type]" />
</template>
</div>
<div id="player" :class="[player_direction]" :data-x="player_x" :data-y="player_y" />
<div id="level-indicator">x:{{ floorX }}, y:{{ floorY }}</div>
</div>
</template>
<script>
import throttle from 'lodash/throttle'
import Level from './level'
import MountainBackground from './Background'
const BLOCK_SIZE = 32
const RECIPROCAL = 1 / BLOCK_SIZE
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 {
name: 'field',
components: { MountainBackground },
data () {
return {
x: 0,
y: 0,
player_x: PLAYER_X,
player_y: PLAYER_Y,
player_direction: 'left',
player_push_x: 0,
player_push_y: 0,
player_velocity_x: 0,
player_velocity_y: 0,
moving: false
}
},
mounted () {
this.player_velocity_y = 8
this.move()
},
watch: {
player_push_x (px) {
if (px === 0) this.player_velocity_x = 0
else this.player_velocity_x = px
},
player_push_y (py) {
if (py === 0) this.player_velocity_y = 8
else this.player_velocity_y = py
}
},
computed: {
blockAtPlayer () { return this.rows[PLAYER_Y][PLAYER_X] },
blockLeftOfPlayer () { return this.rows[PLAYER_Y][PLAYER_X - 1] },
blockRightOfPlayer () { return this.rows[PLAYER_Y][PLAYER_X + 1] },
blockAbovePlayer () { return this.rows[PLAYER_Y - 1][PLAYER_X] },
blockBelowPlayer () { return this.rows[PLAYER_Y + 1][PLAYER_X] },
blockedUp () { return this.cornerY && !this.blockAbovePlayer.walkable },
blockedDown () { return this.cornerY && !this.blockBelowPlayer.walkable },
blockedLeft () { return this.cornerX && !this.blockLeftOfPlayer.walkable },
blockedRight () { return this.cornerX && !this.blockRightOfPlayer.walkable },
cornerX () { return this.x === ~~this.x }, // cornering a block
cornerY () { return this.y === ~~this.y },
floorX () { return Math.floor(this.x) },
floorY () { return Math.floor(this.y) },
tx () { return (this.x - this.floorX) * -BLOCK_SIZE },
ty () { return (this.y - this.floorY) * -BLOCK_SIZE },
rows () { return level.grid(this.floorX, this.floorY) }
},
methods: {
move () {
const x = this.x
const y = this.y
let vx = this.player_velocity_x * RECIPROCAL
let vy = this.player_velocity_y * RECIPROCAL
if (vx < 0) this.player_direction = 'left'
if (vx > 0) this.player_direction = 'right'
if (vx > 0 && this.blockedRight) vx = 0
if (vx < 0 && this.blockedLeft) vx = 0
if (vy > 0 && this.blockedDown) vy = 0
if (vy < 0 && this.blockedUp) vy = 0
this.x += vx
this.y += vy
this.moving = setTimeout(() => this.move(), 50)
},
}
}
</script>
<style>
#field {
position: relative;
width: 1024px;
height: 1024px;
margin: auto;
overflow: hidden;
background-color: #56F;
}
#field > input {
position: absolute;
opacity: 0;
display: block;
width: 1px;
height: 1px;
}
#level-indicator {
position: absolute;
top: 0;
right: 0;
color: white;
}
#player {
position: absolute;
left: calc(32px * 16);
top: calc(32px * 16);
background-image: url(./assets/dwarf_right.png);
}
#player.right { background-image: url(./assets/dwarf_right.png); }
#player.left { background-image: url(./assets/dwarf_left.png); }
#player.up { background-image: url(./assets/dwarf_back.png); }
#player.down { background-image: url(./assets/dwarf_back.png); }
#player, .block {
flex: 0 0 auto;
width: 32px;
height: 32px;
background-color: transparent;
background-size: cover;
background-position: center;
background-repeat: no-repeat;
}
#wrap {
position: absolute;
top: -32px;
left: -32px;
width: 1088px;
height: 1088px;
display: flex;
flex-flow: row wrap;
}
.block.grass { background-image: url(./assets/grass01.png); }
.block.tree_top_left { background-image: url(./assets/tree_top_left.png); }
.block.tree_top_middle { background-image: url(./assets/tree_top_middle.png); }
.block.tree_top_right { background-image: url(./assets/tree_top_right.png); }
.block.tree_crown_left { background-image: url(./assets/tree_crown_left.png); }
.block.tree_crown_middle { background-image: url(./assets/tree_crown_middle.png); }
.block.tree_crown_right { background-image: url(./assets/tree_crown_right.png); }
.block.tree_trunk_left { background-image: url(./assets/tree_trunk_left.png); }
.block.tree_trunk_middle { background-image: url(./assets/tree_trunk_middle.png); }
.block.tree_trunk_right { background-image: url(./assets/tree_trunk_right.png); }
.block.tree_root_left { background-image: url(./assets/tree_root_left.png); }
.block.tree_root_middle { background-image: url(./assets/tree_root_middle.png); }
.block.tree_root_right { background-image: url(./assets/tree_root_right.png); }
.block.tree_top_left_mixed { background-image: url(./assets/tree_top_left_mixed.png); }
.block.tree_crown_left_mixed { background-image: url(./assets/tree_crown_left_mixed.png); }
.block.tree_trunk_left_mixed { background-image: url(./assets/tree_trunk_left_mixed.png); }
.block.tree_root_left_mixed { background-image: url(./assets/tree_root_left_mixed.png); }
.block.tree_top_right_mixed { background-image: url(./assets/tree_top_right_mixed.png); }
.block.tree_crown_right_mixed { background-image: url(./assets/tree_crown_right_mixed.png); }
.block.tree_trunk_right_mixed { background-image: url(./assets/tree_trunk_right_mixed.png); }
.block.tree_root_right_mixed { background-image: url(./assets/tree_root_right_mixed.png); }
.block.soil { background-image: url(./assets/soil.png); }
.block.soil_gravel { background-image: url(./assets/soil_gravel.png); }
.block.stone_gravel { background-image: url(./assets/rock_gravel.png); }
.block.stone { background-image: url(./assets/rock.png); }
.block.bedrock { background-image: url(./assets/bedrock.png); }
.block.cave { background-color: #000; }
.block:hover, .block.highlight { filter: brightness(1.4); }
</style>