Commit f334f373 authored by Chunchi Che's avatar Chunchi Che

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

Feat/duel/slice

See merge request mycard/Neos!26
parents cd0de481 85edf087
import axios from "axios"; import axios from "axios";
export interface CardMeta { interface CardMeta {
id: number; id: number;
data: { data: {
ot?: number; ot?: number;
...@@ -19,6 +19,27 @@ export interface CardMeta { ...@@ -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 { ...@@ -6,10 +6,11 @@ import {
} from "@reduxjs/toolkit"; } from "@reduxjs/toolkit";
import { DuelState } from "./mod"; import { DuelState } from "./mod";
import { RootState } from "../../store"; 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 { export interface Hands {
cards: CardMeta[]; cards: Card[];
} }
// 自己增加手牌 // 自己增加手牌
...@@ -18,13 +19,16 @@ export const meAddHandsImpl: CaseReducer<DuelState, PayloadAction<number[]>> = ( ...@@ -18,13 +19,16 @@ export const meAddHandsImpl: CaseReducer<DuelState, PayloadAction<number[]>> = (
action action
) => { ) => {
const cards = action.payload.map((id) => { const cards = action.payload.map((id) => {
return { id, data: {}, text: {} }; return { meta: { id, data: {}, text: {} }, transform: {} };
}); });
if (state.meHands) { if (state.meHands) {
state.meHands.cards = state.meHands.cards.concat(cards); state.meHands.cards = state.meHands.cards.concat(cards);
} else { } else {
state.meHands = { cards }; state.meHands = { cards };
} }
setHandsTransform(state.meHands.cards);
}; };
// 对手增加手牌 // 对手增加手牌
...@@ -33,7 +37,7 @@ export const opAddHandsImpl: CaseReducer<DuelState, PayloadAction<number[]>> = ( ...@@ -33,7 +37,7 @@ export const opAddHandsImpl: CaseReducer<DuelState, PayloadAction<number[]>> = (
action action
) => { ) => {
const cards = action.payload.map((id) => { const cards = action.payload.map((id) => {
return { id, data: {}, text: {} }; return { meta: { id, data: {}, text: {} }, transform: {} };
}); });
if (state.opHands) { if (state.opHands) {
state.opHands.cards = state.opHands.cards.concat(cards); state.opHands.cards = state.opHands.cards.concat(cards);
...@@ -56,15 +60,47 @@ export const fetchMeHandsMeta = createAsyncThunk( ...@@ -56,15 +60,47 @@ export const fetchMeHandsMeta = createAsyncThunk(
export const meHandsCase = (builder: ActionReducerMapBuilder<DuelState>) => { export const meHandsCase = (builder: ActionReducerMapBuilder<DuelState>) => {
builder.addCase(fetchMeHandsMeta.fulfilled, (state, action) => { builder.addCase(fetchMeHandsMeta.fulfilled, (state, action) => {
// TODO: 合法性校验 // TODO: 合法性校验
const cards = action.payload; const cardMetas = action.payload;
if (state.meHands) { 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 { } 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) => export const selectMeHands = (state: RootState) =>
state.duel.meHands || { cards: [] }; state.duel.meHands || { cards: [] };
export const selectOpHands = (state: RootState) => export const selectOpHands = (state: RootState) =>
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
import React from "react"; import React from "react";
import type { RootState } from "../../store"; import type { RootState } from "../../store";
import { CardMeta } from "../../api/cards"; import { Card } from "../../api/cards";
/* /*
* 通用的决斗界面抽象接口 * 通用的决斗界面抽象接口
...@@ -26,7 +26,7 @@ export interface IDuelPlate { ...@@ -26,7 +26,7 @@ export interface IDuelPlate {
// 渲染接口,返回一个React组件 // 渲染接口,返回一个React组件
render(): React.ReactElement; render(): React.ReactElement;
// 注册手牌selector // 注册手牌selector
registerHands(selector: TypeSelector<CardMeta[]>): void; registerHands(selector: TypeSelector<Card[]>): void;
} }
export interface TypeSelector<T> { export interface TypeSelector<T> {
......
import * as BABYLON from "@babylonjs/core"; import * as BABYLON from "@babylonjs/core";
import * as CONFIG from "./config"; import * as CONFIG from "../../../config/ui";
export default (scene: BABYLON.Scene) => { export default (scene: BABYLON.Scene) => {
// 墓地 // 墓地
......
import * as BABYLON from "@babylonjs/core"; import * as BABYLON from "@babylonjs/core";
import * as CONFIG from "./config"; import * as CONFIG from "../../../config/ui";
export default (scene: BABYLON.Scene) => { export default (scene: BABYLON.Scene) => {
// 卡组 // 卡组
......
import * as BABYLON from "@babylonjs/core"; import * as BABYLON from "@babylonjs/core";
import * as CONFIG from "./config"; import * as CONFIG from "../../../config/ui";
export default (scene: BABYLON.Scene) => { export default (scene: BABYLON.Scene) => {
// 除外区 // 除外区
......
import * as BABYLON from "@babylonjs/core"; import * as BABYLON from "@babylonjs/core";
import * as CONFIG from "./config"; import * as CONFIG from "../../../config/ui";
export default (scene: BABYLON.Scene) => { export default (scene: BABYLON.Scene) => {
const xs = [-1.1, 1]; const xs = [-1.1, 1];
......
import * as BABYLON from "@babylonjs/core"; import * as BABYLON from "@babylonjs/core";
import * as CONFIG from "./config"; import * as CONFIG from "../../../config/ui";
export default (scene: BABYLON.Scene) => { export default (scene: BABYLON.Scene) => {
// 墓地 // 墓地
......
import * as BABYLON from "@babylonjs/core"; import * as BABYLON from "@babylonjs/core";
import * as CONFIG from "./config"; import * as CONFIG from "../../../config/ui";
import { CardMeta } from "../../../api/cards"; import { Card } from "../../../api/cards";
export default (hands: CardMeta[], scene: BABYLON.Scene) => { export default (hands: Card[], scene: BABYLON.Scene) => {
const groundShape = CONFIG.GroundShape();
const handShape = CONFIG.HandShape(); const handShape = CONFIG.HandShape();
const gap = groundShape.width / (hands.length - 1);
const left = -(groundShape.width / 2);
hands.forEach((item, idx, _) => { hands.forEach((item, idx, _) => {
const hand = BABYLON.MeshBuilder.CreatePlane( const hand = BABYLON.MeshBuilder.CreatePlane(
`hand${idx}`, `hand${idx}`,
...@@ -15,16 +12,20 @@ export default (hands: CardMeta[], scene: BABYLON.Scene) => { ...@@ -15,16 +12,20 @@ export default (hands: CardMeta[], scene: BABYLON.Scene) => {
); );
// 位置 // 位置
hand.position = new BABYLON.Vector3( hand.position = new BABYLON.Vector3(
left + gap * idx, item.transform.position?.x,
handShape.height / 2, item.transform.position?.y,
-(groundShape.height / 2) - 1 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); const handMaterial = new BABYLON.StandardMaterial("handMaterial", scene);
// 材质贴纸 // 材质贴纸
handMaterial.diffuseTexture = new BABYLON.Texture( 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 scene
); );
hand.material = handMaterial; hand.material = handMaterial;
......
import * as BABYLON from "@babylonjs/core"; import * as BABYLON from "@babylonjs/core";
import * as CONFIG from "./config"; import * as CONFIG from "../../../config/ui";
export default (scene: BABYLON.Scene) => { export default (scene: BABYLON.Scene) => {
const left = -2.15; const left = -2.15;
......
...@@ -16,13 +16,13 @@ import renderDeck from "./deck"; ...@@ -16,13 +16,13 @@ import renderDeck from "./deck";
import renderCemetery from "./cemetery"; import renderCemetery from "./cemetery";
import renderExclusion from "./exclusion"; import renderExclusion from "./exclusion";
import renderField from "./field"; import renderField from "./field";
import * as CONFIG from "./config"; import * as CONFIG from "../../../config/ui";
import { CardMeta } from "../../../api/cards"; import { Card } from "../../../api/cards";
// CONFIG // CONFIG
export default class SimpleDuelPlateImpl implements IDuelPlate { export default class SimpleDuelPlateImpl implements IDuelPlate {
handsSelector?: TypeSelector<CardMeta[]>; handsSelector?: TypeSelector<Card[]>;
constructor() {} constructor() {}
...@@ -110,10 +110,7 @@ export default class SimpleDuelPlateImpl implements IDuelPlate { ...@@ -110,10 +110,7 @@ export default class SimpleDuelPlateImpl implements IDuelPlate {
useEffect(() => { useEffect(() => {
// 监听状态变化,并实现动画 // 监听状态变化,并实现动画
const onHandsChange = ( const onHandsChange = (prev_hands: Card[] | null, cur_hands: Card[]) => {
prev_hands: CardMeta[] | null,
cur_hands: CardMeta[]
) => {
console.log(prev_hands, "change to", cur_hands); console.log(prev_hands, "change to", cur_hands);
}; };
...@@ -136,7 +133,7 @@ export default class SimpleDuelPlateImpl implements IDuelPlate { ...@@ -136,7 +133,7 @@ export default class SimpleDuelPlateImpl implements IDuelPlate {
); );
} }
registerHands(selector: TypeSelector<CardMeta[]>): void { registerHands(selector: TypeSelector<Card[]>): void {
this.handsSelector = selector; this.handsSelector = selector;
} }
} }
import * as BABYLON from "@babylonjs/core"; import * as BABYLON from "@babylonjs/core";
import * as CONFIG from "./config"; import * as CONFIG from "../../../config/ui";
export default (scene: BABYLON.Scene) => { export default (scene: BABYLON.Scene) => {
const left = -2.15; 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