Commit 890d930a authored by Chunchi Che's avatar Chunchi Che

Merge branch 'feat/ui/magic' into 'main'

Feat/ui/magic

See merge request mycard/Neos!53
parents e1e017de 44c8a183
import { judgeSelf, Magic, InteractType } from "./util";
import { PayloadAction, CaseReducer } from "@reduxjs/toolkit";
import { DuelState } from "./mod";
import { ygopro } from "../../api/ocgcore/idl/ocgcore";
import { RootState } from "../../store";
export interface MagicState {
magics: Magic[];
}
// 初始化自己的魔法陷阱区状态
export const initMagicsImpl: CaseReducer<DuelState, PayloadAction<number>> = (
state,
action
) => {
const player = action.payload;
const magics = {
magics: [
{
sequence: 0,
},
{
sequence: 1,
},
{
sequence: 2,
},
{
sequence: 3,
},
{
sequence: 4,
},
],
};
if (judgeSelf(player, state)) {
state.meMagics = magics;
} else {
state.opMagics = magics;
}
};
export const addMagicPlaceSelectAbleImpl: CaseReducer<
DuelState,
PayloadAction<[number, number]>
> = (state, action) => {
const controler = action.payload[0];
const sequence = action.payload[1];
const magics = judgeSelf(controler, state) ? state.meMagics : state.opMagics;
if (magics) {
for (const magic of magics.magics) {
if (magic.sequence == sequence) {
magic.selectInfo = {
interactType: InteractType.PLACE_SELECTABLE,
response: {
controler,
zone: ygopro.CardZone.SZONE,
sequence,
},
};
}
}
}
};
export const clearMagicSelectInfoImpl: CaseReducer<
DuelState,
PayloadAction<number>
> = (state, action) => {
const player = action.payload;
const magics = judgeSelf(player, state) ? state.meMagics : state.opMagics;
if (magics) {
magics.magics = [];
}
};
export const selectMeMagics = (state: RootState) =>
state.duel.meMagics || { magics: [] };
......@@ -29,6 +29,12 @@ import {
addMonsterPlaceSelectAbleImpl,
clearMonsterSelectInfoImpl,
} from "./monstersSlice";
import {
MagicState,
initMagicsImpl,
addMagicPlaceSelectAbleImpl,
clearMagicSelectInfoImpl,
} from "./magicSlice";
export interface DuelState {
selfType?: number;
......@@ -41,6 +47,9 @@ export interface DuelState {
meMonsters?: MonsterState; // 自己的怪兽区状态
opMonsters?: MonsterState; // 对手的怪兽区状态
meMagics?: MagicState; // 自己的魔法陷阱区状态
opMagics?: MagicState; // 对手的魔法陷阱区状态
meTimeLimit?: TimeLimit; // 自己的计时
opTimeLimit?: TimeLimit; // 对手的计时
......@@ -81,6 +90,11 @@ const duelSlice = createSlice({
addMonsterPlaceSelectAble: addMonsterPlaceSelectAbleImpl,
clearMonsterSelectInfo: clearMonsterSelectInfoImpl,
// 魔法陷阱区相关`Reducer`
initMagics: initMagicsImpl,
addMagicPlaceSelectAble: addMagicPlaceSelectAbleImpl,
clearMagicSelectInfo: clearMagicSelectInfoImpl,
// UI相关`Reducer`
setCardModalIsOpen: setCardModalIsOpenImpl,
setCardModalText: setCardModalTextImpl,
......@@ -108,6 +122,9 @@ export const {
initMonsters,
addMonsterPlaceSelectAble,
clearMonsterSelectInfo,
initMagics,
addMagicPlaceSelectAble,
clearMagicSelectInfo,
} = duelSlice.actions;
export const selectDuelHsStart = (state: RootState) => {
return state.duel.meInitInfo != null;
......
......@@ -72,7 +72,7 @@ export interface Interactivity<T> {
response: T;
}
export interface Monster {
export interface SlotState {
sequence: number;
occupant?: CardMeta;
selectInfo?: Interactivity<{
......@@ -81,3 +81,7 @@ export interface Monster {
sequence: number;
}>;
}
export type Monster = SlotState;
export type Magic = SlotState;
import { ygopro } from "../../api/ocgcore/idl/ocgcore";
import { AppDispatch } from "../../store";
import MsgSelectPlace = ygopro.StocGameMessage.MsgSelectPlace;
import { addMonsterPlaceSelectAble } from "../../reducers/duel/mod";
import {
addMonsterPlaceSelectAble,
addMagicPlaceSelectAble,
} from "../../reducers/duel/mod";
export default (selectPlace: MsgSelectPlace, dispatch: AppDispatch) => {
if (selectPlace.count != 1) {
......@@ -17,6 +20,11 @@ export default (selectPlace: MsgSelectPlace, dispatch: AppDispatch) => {
break;
}
case ygopro.CardZone.SZONE: {
dispatch(addMagicPlaceSelectAble([place.controler, place.sequence]));
break;
}
default: {
console.warn(`Unhandled zoneType: ${place.zone}`);
}
......
import { ygopro } from "../../api/ocgcore/idl/ocgcore";
import { AppDispatch } from "../../store";
import { infoInit, setSelfType, initMonsters } from "../../reducers/duel/mod";
import {
infoInit,
setSelfType,
initMonsters,
initMagics,
} from "../../reducers/duel/mod";
export default (
start: ygopro.StocGameMessage.MsgStart,
......@@ -29,4 +34,6 @@ export default (
);
dispatch(initMonsters(0));
dispatch(initMonsters(1));
dispatch(initMagics(0));
dispatch(initMagics(1));
};
import * as BABYLON from "@babylonjs/core";
import * as CONFIG from "../../config/ui";
import { selectMeMagics } from "../../reducers/duel/magicSlice";
import { useClick } from "./hook";
import { Magic } from "../../reducers/duel/util";
import { store } from "../../store";
import { useAppSelector } from "../../hook";
import { useRef } from "react";
import { sendSelectPlaceResponse } from "../../api/ocgcore/ocgHelper";
import { clearMagicSelectInfo } from "../../reducers/duel/mod";
// TODO: use config
const left = -2.15;
const gap = 1.05;
const Magics = () => {
const magics = useAppSelector(selectMeMagics).magics;
return (
<>
{[0, 1, 2, 3, 4].map((idx) => {
return <Magic idx={idx} />;
{magics.map((magic) => {
return <CMagic state={magic} />;
})}
</>
);
};
const Magic = (props: { idx: number }) => {
const CMagic = (props: { state: Magic }) => {
const state = props.state;
const planeRef = useRef(null);
const shape = CONFIG.CardSlotShape();
const position = new BABYLON.Vector3(
left + gap * props.idx,
left + gap * state.sequence,
shape.depth / 2 + CONFIG.Floating,
-2.6
);
const rotation = CONFIG.CardSlotRotation();
const edgesWidth = 2.0;
const edgesColor = BABYLON.Color4.FromColor3(BABYLON.Color3.Yellow());
const dispatch = store.dispatch;
useClick(
(_event) => {
if (state.selectInfo) {
sendSelectPlaceResponse(state.selectInfo.response);
dispatch(clearMagicSelectInfo(0));
dispatch(clearMagicSelectInfo(1));
}
},
planeRef,
[state]
);
return (
<plane
name={`magic-${props.idx}`}
name={`magic-${state.sequence}`}
ref={planeRef}
width={shape.width}
height={shape.height}
position={position}
rotation={rotation}
enableEdgesRendering
edgesWidth={state.selectInfo ? edgesWidth : 0}
edgesColor={edgesColor}
>
<standardMaterial
name={`magic-mat-${props.idx}`}
name={`magic-mat-${props.state.sequence}`}
diffuseTexture={
new BABYLON.Texture(`http://localhost:3030/images/card_slot.png`)
state.occupant
? new BABYLON.Texture(`http://localhost:3030/images/card_back.jpg`)
: new BABYLON.Texture(`http://localhost:3030/images/card_slot.png`)
}
alpha={0.2}
></standardMaterial>
......
......@@ -42,7 +42,7 @@ const CommonMonster = (props: { state: Monster }) => {
useClick(
(_event) => {
if (props.state.selectInfo) {
sendSelectPlaceResponse(props.state.selectInfo?.response);
sendSelectPlaceResponse(props.state.selectInfo.response);
dispatch(clearMonsterSelectInfo(0));
dispatch(clearMonsterSelectInfo(1));
}
......
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