Commit f334f373 authored by Chunchi Che's avatar Chunchi Che

Merge branch 'feat/duel/slice' into 'main'

Feat/duel/slice

See merge request !26
parents cd0de481 85edf087
Pipeline #18289 passed with stages
in 2 minutes and 23 seconds
import axios from "axios";
export interface CardMeta {
interface CardMeta {
id: number;
data: {
ot?: number;
......@@ -19,6 +19,27 @@ export interface CardMeta {
};
}
interface CardTransform {
position?: {
x: number;
y: number;
z: number;
};
rotation?: {
x: number;
y: number;
z: number;
};
}
/*
* `Neos`中表示卡牌的通用结构
* */
export interface Card {
meta: CardMeta;
transform: CardTransform;
}
/*
* 返回卡片元数据
*
......
......@@ -6,10 +6,11 @@ import {
} from "@reduxjs/toolkit";
import { DuelState } from "./mod";
import { RootState } from "../../store";
import { CardMeta, fetchCard } from "../../api/cards";
import { Card, fetchCard } from "../../api/cards";
import * as UICONFIG from "../../config/ui";
export interface Hands {
cards: CardMeta[];
cards: Card[];
}
// 自己增加手牌
......@@ -18,13 +19,16 @@ export const meAddHandsImpl: CaseReducer<DuelState, PayloadAction<number[]>> = (
action
) => {
const cards = action.payload.map((id) => {
return { id, data: {}, text: {} };
return { meta: { id, data: {}, text: {} }, transform: {} };
});
if (state.meHands) {
state.meHands.cards = state.meHands.cards.concat(cards);
} else {
state.meHands = { cards };
}
setHandsTransform(state.meHands.cards);
};
// 对手增加手牌
......@@ -33,7 +37,7 @@ export const opAddHandsImpl: CaseReducer<DuelState, PayloadAction<number[]>> = (
action
) => {
const cards = action.payload.map((id) => {
return { id, data: {}, text: {} };
return { meta: { id, data: {}, text: {} }, transform: {} };
});
if (state.opHands) {
state.opHands.cards = state.opHands.cards.concat(cards);
......@@ -56,15 +60,47 @@ export const fetchMeHandsMeta = createAsyncThunk(
export const meHandsCase = (builder: ActionReducerMapBuilder<DuelState>) => {
builder.addCase(fetchMeHandsMeta.fulfilled, (state, action) => {
// TODO: 合法性校验
const cards = action.payload;
const cardMetas = action.payload;
if (state.meHands) {
state.meHands.cards = cards;
for (let meta of cardMetas) {
for (let hand of state.meHands.cards) {
if (hand.meta.id === meta.id) {
hand.meta = meta;
}
}
}
} else {
state.meHands = { cards };
state.meHands = {
cards: cardMetas.map((meta) => {
return { meta, transform: {} };
}),
};
setHandsTransform(state.meHands.cards);
}
});
};
// 更新手牌的位置和旋转信息
function setHandsTransform(hands: Card[]): void {
const groundShape = UICONFIG.GroundShape();
const handShape = UICONFIG.HandShape();
const gap = groundShape.width / (hands.length - 1);
const left = -(groundShape.width / 2);
hands.forEach((hand, idx, _) => {
hand.transform.position = {
x: left + gap * idx,
y: handShape.height / 2,
z: -(groundShape.height / 2) - 1,
};
const rotation = UICONFIG.HandRotation();
hand.transform.rotation = { x: rotation.x, y: rotation.y, z: rotation.z };
});
}
export const selectMeHands = (state: RootState) =>
state.duel.meHands || { cards: [] };
export const selectOpHands = (state: RootState) =>
......
......@@ -16,7 +16,7 @@
import React from "react";
import type { RootState } from "../../store";
import { CardMeta } from "../../api/cards";
import { Card } from "../../api/cards";
/*
* 通用的决斗界面抽象接口
......@@ -26,7 +26,7 @@ export interface IDuelPlate {
// 渲染接口,返回一个React组件
render(): React.ReactElement;
// 注册手牌selector
registerHands(selector: TypeSelector<CardMeta[]>): void;
registerHands(selector: TypeSelector<Card[]>): void;
}
export interface TypeSelector<T> {
......
import * as BABYLON from "@babylonjs/core";
import * as CONFIG from "./config";
import * as CONFIG from "../../../config/ui";
export default (scene: BABYLON.Scene) => {
// 墓地
......
import * as BABYLON from "@babylonjs/core";
import * as CONFIG from "./config";
import * as CONFIG from "../../../config/ui";
export default (scene: BABYLON.Scene) => {
// 卡组
......
import * as BABYLON from "@babylonjs/core";
import * as CONFIG from "./config";
import * as CONFIG from "../../../config/ui";
export default (scene: BABYLON.Scene) => {
// 除外区
......
import * as BABYLON from "@babylonjs/core";
import * as CONFIG from "./config";
import * as CONFIG from "../../../config/ui";
export default (scene: BABYLON.Scene) => {
const xs = [-1.1, 1];
......
import * as BABYLON from "@babylonjs/core";
import * as CONFIG from "./config";
import * as CONFIG from "../../../config/ui";
export default (scene: BABYLON.Scene) => {
// 墓地
......
import * as BABYLON from "@babylonjs/core";
import * as CONFIG from "./config";
import { CardMeta } from "../../../api/cards";
import * as CONFIG from "../../../config/ui";
import { Card } from "../../../api/cards";
export default (hands: CardMeta[], scene: BABYLON.Scene) => {
const groundShape = CONFIG.GroundShape();
export default (hands: Card[], scene: BABYLON.Scene) => {
const handShape = CONFIG.HandShape();
const gap = groundShape.width / (hands.length - 1);
const left = -(groundShape.width / 2);
hands.forEach((item, idx, _) => {
const hand = BABYLON.MeshBuilder.CreatePlane(
`hand${idx}`,
......@@ -15,16 +12,20 @@ export default (hands: CardMeta[], scene: BABYLON.Scene) => {
);
// 位置
hand.position = new BABYLON.Vector3(
left + gap * idx,
handShape.height / 2,
-(groundShape.height / 2) - 1
item.transform.position?.x,
item.transform.position?.y,
item.transform.position?.z
);
hand.rotation = new BABYLON.Vector3(
item.transform.rotation?.x,
item.transform.rotation?.y,
item.transform.rotation?.z
);
hand.rotation = CONFIG.HandRotation();
// 材质
const handMaterial = new BABYLON.StandardMaterial("handMaterial", scene);
// 材质贴纸
handMaterial.diffuseTexture = new BABYLON.Texture(
`https://cdn02.moecube.com:444/images/ygopro-images-zh-CN/${item.id}.jpg`,
`https://cdn02.moecube.com:444/images/ygopro-images-zh-CN/${item.meta.id}.jpg`,
scene
);
hand.material = handMaterial;
......
import * as BABYLON from "@babylonjs/core";
import * as CONFIG from "./config";
import * as CONFIG from "../../../config/ui";
export default (scene: BABYLON.Scene) => {
const left = -2.15;
......
......@@ -16,13 +16,13 @@ import renderDeck from "./deck";
import renderCemetery from "./cemetery";
import renderExclusion from "./exclusion";
import renderField from "./field";
import * as CONFIG from "./config";
import { CardMeta } from "../../../api/cards";
import * as CONFIG from "../../../config/ui";
import { Card } from "../../../api/cards";
// CONFIG
export default class SimpleDuelPlateImpl implements IDuelPlate {
handsSelector?: TypeSelector<CardMeta[]>;
handsSelector?: TypeSelector<Card[]>;
constructor() {}
......@@ -110,10 +110,7 @@ export default class SimpleDuelPlateImpl implements IDuelPlate {
useEffect(() => {
// 监听状态变化,并实现动画
const onHandsChange = (
prev_hands: CardMeta[] | null,
cur_hands: CardMeta[]
) => {
const onHandsChange = (prev_hands: Card[] | null, cur_hands: Card[]) => {
console.log(prev_hands, "change to", cur_hands);
};
......@@ -136,7 +133,7 @@ export default class SimpleDuelPlateImpl implements IDuelPlate {
);
}
registerHands(selector: TypeSelector<CardMeta[]>): void {
registerHands(selector: TypeSelector<Card[]>): void {
this.handsSelector = selector;
}
}
import * as BABYLON from "@babylonjs/core";
import * as CONFIG from "./config";
import * as CONFIG from "../../../config/ui";
export default (scene: BABYLON.Scene) => {
const left = -2.15;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment