WIP: Basic 2D game board #23

Draft
hamcha wants to merge 6 commits from feature/board into master
3 changed files with 313 additions and 4 deletions

View 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>

View File

@ -54,6 +54,8 @@ $border-opacity: 0.6;
.draftview {
background: url("../assets/images/backgrounds/draftbg.webp") center;
background-repeat: no-repeat;
background-size: cover;
display: grid;
height: 100vh;
gap: 10px;

View File

@ -1,14 +1,235 @@
<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>
<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">
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({
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>