WIP: Basic 2D game board #23
3 changed files with 313 additions and 4 deletions
86
src/components/GameBoard/Zone.vue
Normal file
86
src/components/GameBoard/Zone.vue
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
<template>
|
||||||
|
<section
|
||||||
|
:class="zoneClass"
|
||||||
|
@dragenter.prevent="dragenter"
|
||||||
|
@dragleave.prevent="dragleave"
|
||||||
|
>
|
||||||
|
<CardImage
|
||||||
|
class="ccgcard"
|
||||||
|
v-for="(card, i) in cards"
|
||||||
|
:key="i + card.ID"
|
||||||
|
:id="card.ID"
|
||||||
|
/>
|
||||||
|
</section>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.zone {
|
||||||
|
border: 2px solid rgba(255, 255, 255, 0.2);
|
||||||
|
margin: 2px;
|
||||||
|
padding: 4px;
|
||||||
|
border-radius: 5px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ccgcard {
|
||||||
|
cursor: grab;
|
||||||
|
transition: all 100ms;
|
||||||
|
max-width: none;
|
||||||
|
width: auto;
|
||||||
|
max-height: 100%;
|
||||||
|
margin: 0 10px;
|
||||||
|
&:active {
|
||||||
|
cursor: grabbing;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.dragging {
|
||||||
|
background: rgba(255, 255, 255, 0.3);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { Component, Vue, Prop } from "vue-property-decorator";
|
||||||
|
import { cardImageURL, Card } from "@/mlpccg";
|
||||||
|
import CardImage from "@/components/Cards/CardImage.vue";
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
components: {
|
||||||
|
CardImage
|
||||||
|
}
|
||||||
|
})
|
||||||
|
export default class Zone extends Vue {
|
||||||
|
@Prop({
|
||||||
|
default: []
|
||||||
|
})
|
||||||
|
private cards!: Card[];
|
||||||
|
|
||||||
|
private dragging!: boolean;
|
||||||
|
|
||||||
|
private data() {
|
||||||
|
return {
|
||||||
|
dragging: false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private imageURL(id: string) {
|
||||||
|
return cardImageURL(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
private dragenter(e: DragEvent) {
|
||||||
|
this.dragging = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private dragleave(e: DragEvent) {
|
||||||
|
this.dragging = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private get zoneClass() {
|
||||||
|
return {
|
||||||
|
zone: true,
|
||||||
|
dragging: this.dragging
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -54,6 +54,8 @@ $border-opacity: 0.6;
|
||||||
|
|
||||||
.draftview {
|
.draftview {
|
||||||
background: url("../assets/images/backgrounds/draftbg.webp") center;
|
background: url("../assets/images/backgrounds/draftbg.webp") center;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-size: cover;
|
||||||
display: grid;
|
display: grid;
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
gap: 10px;
|
gap: 10px;
|
||||||
|
|
|
@ -1,14 +1,235 @@
|
||||||
<template>
|
<template>
|
||||||
<section class="game"></section>
|
<section class="game">
|
||||||
|
<section class="topbar"></section>
|
||||||
|
<section class="board">
|
||||||
|
<Zone class="opp-zone" :cards="zones['opp-home']" id="opp-home" />
|
||||||
|
<section class="problems">
|
||||||
|
<section class="problem own-problem">
|
||||||
|
<Zone
|
||||||
|
class="opp-zone"
|
||||||
|
:cards="zones['own-problem-opp-zone']"
|
||||||
|
id="pown-opp-zone"
|
||||||
|
/>
|
||||||
|
<section class="problem-card opp-zone">
|
||||||
|
<CardImage
|
||||||
|
v-if="problems['own-problem']"
|
||||||
|
:id="problems['own-problem'].ID"
|
||||||
|
/>
|
||||||
|
</section>
|
||||||
|
<Zone
|
||||||
|
class="own-zone"
|
||||||
|
:cards="zones['own-problem-own-zone']"
|
||||||
|
id="pown-own-zone"
|
||||||
|
/>
|
||||||
|
</section>
|
||||||
|
<section class="problem opp-problem">
|
||||||
|
<Zone
|
||||||
|
class="opp-zone"
|
||||||
|
:cards="zones['opp-problem-opp-zone']"
|
||||||
|
id="popp-opp-zone"
|
||||||
|
/>
|
||||||
|
<section class="problem-card">
|
||||||
|
<CardImage
|
||||||
|
v-if="problems['opp-problem']"
|
||||||
|
:id="problems['opp-problem'].ID"
|
||||||
|
/>
|
||||||
|
</section>
|
||||||
|
<Zone
|
||||||
|
class="own-zone"
|
||||||
|
:cards="zones['opp-problem-own-zone']"
|
||||||
|
id="popp-own-zone"
|
||||||
|
/>
|
||||||
|
</section>
|
||||||
|
</section>
|
||||||
|
<Zone class="own-zone" :cards="zones['own-home']" id="own-home" />
|
||||||
|
</section>
|
||||||
|
<section class="hand">
|
||||||
|
<article
|
||||||
|
draggable="true"
|
||||||
|
v-for="(card, i) in hand"
|
||||||
|
:key="i + card.ID"
|
||||||
|
@dragstart="dragStartCard.bind(this, card)"
|
||||||
|
>
|
||||||
|
<CardImage :id="card.ID" />
|
||||||
|
</article>
|
||||||
|
</section>
|
||||||
|
</section>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="scss" scoped></style>
|
<style lang="scss" scoped>
|
||||||
|
$zone-gap: 5px;
|
||||||
|
$card-gap: 5px;
|
||||||
|
$side-min-size: 250px;
|
||||||
|
$top-bar-height: 50px;
|
||||||
|
$hand-min-height: 100px;
|
||||||
|
$hand-max-height: 150px;
|
||||||
|
|
||||||
|
.game {
|
||||||
|
background: url("../assets/images/backgrounds/boardbg.webp") center;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-size: cover;
|
||||||
|
height: 100vh;
|
||||||
|
display: grid;
|
||||||
|
gap: $zone-gap;
|
||||||
|
grid:
|
||||||
|
$top-bar-height 2fr minmax($hand-min-height, $hand-max-height) / minmax(
|
||||||
|
$side-min-size,
|
||||||
|
1fr
|
||||||
|
)
|
||||||
|
5fr minmax($side-min-size, 1fr);
|
||||||
|
}
|
||||||
|
|
||||||
|
.topbar {
|
||||||
|
grid-column: 1/4;
|
||||||
|
grid-row: 1;
|
||||||
|
background: linear-gradient(
|
||||||
|
to bottom,
|
||||||
|
rgba(0, 0, 30, 0.9),
|
||||||
|
rgba(0, 0, 50, 0.6)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
.board {
|
||||||
|
grid-column: 2/3;
|
||||||
|
grid-row: 2;
|
||||||
|
display: grid;
|
||||||
|
grid: 1fr 2.5fr 1fr / 1fr;
|
||||||
|
max-height: 100vh;
|
||||||
|
|
||||||
|
.problems {
|
||||||
|
display: flex;
|
||||||
|
flex: 1;
|
||||||
|
flex-flow: row;
|
||||||
|
|
||||||
|
.problem {
|
||||||
|
display: grid;
|
||||||
|
grid: 1.5fr 0.2fr 1fr 0.2fr 1.5fr / 1fr 1.5fr 1fr;
|
||||||
|
flex: 1;
|
||||||
|
|
||||||
|
.own-zone {
|
||||||
|
grid-row: 4/6;
|
||||||
|
grid-column: 1/4;
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
.opp-zone {
|
||||||
|
grid-row: 1/3;
|
||||||
|
grid-column: 1/4;
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
.problem-card {
|
||||||
|
grid-row: 2/5;
|
||||||
|
grid-column: 2;
|
||||||
|
z-index: 1;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
img {
|
||||||
|
height: auto;
|
||||||
|
max-height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.hand {
|
||||||
|
grid-column: 2;
|
||||||
|
grid-row: 3;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(10px, max-content));
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
padding-right: 100px;
|
||||||
|
article {
|
||||||
|
margin: $card-gap;
|
||||||
|
margin-bottom: 0;
|
||||||
|
overflow-y: hidden;
|
||||||
|
cursor: grab;
|
||||||
|
transition: all 100ms;
|
||||||
|
min-width: 150px;
|
||||||
|
max-width: 200px;
|
||||||
|
&:hover {
|
||||||
|
margin-top: $card-gap - 30px;
|
||||||
|
}
|
||||||
|
&:active {
|
||||||
|
cursor: grabbing;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
overflow: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
.opp-zone {
|
||||||
|
transform: rotate(180deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 1200px) {
|
||||||
|
.game {
|
||||||
|
grid-template-columns: $side-min-size 5fr;
|
||||||
|
}
|
||||||
|
.hand {
|
||||||
|
grid-column: 1/3;
|
||||||
|
padding: 0 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Component, Vue } from "vue-property-decorator";
|
import { Component, Vue } from "vue-property-decorator";
|
||||||
|
import { Card, cardImageURL, getCards } from "@/mlpccg";
|
||||||
|
import Zone from "@/components/GameBoard/Zone.vue";
|
||||||
|
import CardImage from "@/components/Cards/CardImage.vue";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
components: {}
|
components: {
|
||||||
|
CardImage,
|
||||||
|
Zone
|
||||||
|
}
|
||||||
})
|
})
|
||||||
export default class GameView extends Vue {}
|
export default class GameView extends Vue {
|
||||||
|
private hand!: Card[];
|
||||||
|
private zones!: Record<string, Card[]>;
|
||||||
|
private problems!: Record<string, Card | null>;
|
||||||
|
|
||||||
|
private data() {
|
||||||
|
return {
|
||||||
|
hand: [],
|
||||||
|
zones: {
|
||||||
|
"own-home": [],
|
||||||
|
"opp-home": [],
|
||||||
|
"own-problem-own-zone": [],
|
||||||
|
"own-problem-opp-zone": [],
|
||||||
|
"opp-problem-own-zone": [],
|
||||||
|
"opp-problem-opp-zone": []
|
||||||
|
},
|
||||||
|
problems: {
|
||||||
|
"own-problem": null,
|
||||||
|
"opp-problem": null
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private async mounted() {
|
||||||
|
const cards = await getCards({ Sets: ["FF"] });
|
||||||
|
this.hand = cards.slice(0, 9);
|
||||||
|
this.zones["own-home"] = cards.slice(0, 3);
|
||||||
|
this.zones["own-problem-opp-zone"] = cards.slice(10, 11);
|
||||||
|
this.zones["opp-home"] = cards.slice(20, 23);
|
||||||
|
console.log(cards);
|
||||||
|
const problem = cards.find(c => c.ID == "ff130");
|
||||||
|
this.problems["own-problem"] = problem!;
|
||||||
|
this.problems["opp-problem"] = problem!;
|
||||||
|
}
|
||||||
|
|
||||||
|
private imageURL(id: string) {
|
||||||
|
return cardImageURL(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
private dragStartCard(card: Card, e: DragEvent) {
|
||||||
|
if (e.dataTransfer) {
|
||||||
|
e.dataTransfer.setData("id", card.ID);
|
||||||
|
e.dataTransfer.dropEffect = "move";
|
||||||
|
e.dataTransfer.effectAllowed = "all";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
Loading…
Reference in a new issue