Commit 67516e9a authored by timel's avatar timel

feat: ui block

parent 860d5508
......@@ -67,6 +67,38 @@ section#mat {
}
}
}
// 下面应该和moveToOutside、moveToGround对应
.bg-other-blocks {
&.op {
transform: rotate(180deg);
}
position: absolute;
--height: var(--card-height-o);
--width: calc(var(--height) * var(--card-ratio));
--left: calc(
var(--col-gap) * 2 + var(--block-width) * 2.5 +
var(--block-outside-offset-x) + var(--width) / 2
);
--top: calc(
var(--row-gap) + var(--block-height-m) +
(var(--block-height-m) - var(--height)) / 2
);
.block {
position: absolute;
transform: translate(-50%, -50%);
height: var(--height);
width: var(--width);
top: var(--top);
left: var(--left);
}
.field {
left: calc(-1 * var(--left));
}
.banish {
top: calc(var(--top) - var(--row-gap) - var(--height));
}
}
}
// 被禁用的样式
......
......@@ -5,12 +5,19 @@ import { type INTERNAL_Snapshot as Snapshot, useSnapshot } from "valtio";
import { sendSelectPlaceResponse, ygopro } from "@/api";
import {
BlockState,
type BlockState,
cardStore,
type PlaceInteractivity,
placeStore,
} from "@/stores";
const BgBlock: React.FC<React.HTMLProps<HTMLDivElement>> = (props) => (
<div {...props} className={classnames("block", props.className)}>
{<DecoTriangles />}
{<DisabledCross />}
</div>
);
const BgExtraRow: React.FC<{
meSnap: Snapshot<BlockState[]>;
opSnap: Snapshot<BlockState[]>;
......@@ -18,9 +25,9 @@ const BgExtraRow: React.FC<{
return (
<div className={classnames("bg-row")}>
{Array.from({ length: 2 }).map((_, i) => (
<div
<BgBlock
key={i}
className={classnames("block", "extra", {
className={classnames("extra", {
highlight: !!meSnap[i].interactivity || !!opSnap[i].interactivity,
disabled: meSnap[i].disabled || opSnap[i].disabled,
})}
......@@ -28,10 +35,7 @@ const BgExtraRow: React.FC<{
onBlockClick(meSnap[i].interactivity);
onBlockClick(opSnap[i].interactivity);
}}
>
{<DecoTriangles />}
{<DisabledCross />}
</div>
/>
))}
</div>
);
......@@ -44,22 +48,27 @@ const BgRow: React.FC<{
}> = ({ isSzone = false, opponent = false, snap }) => (
<div className={classnames("bg-row", { opponent })}>
{Array.from({ length: 5 }).map((_, i) => (
<div
<BgBlock
key={i}
className={classnames("block", {
className={classnames({
szone: isSzone,
highlight: !!snap[i].interactivity,
disabled: snap[i].disabled,
})}
onClick={() => onBlockClick(snap[i].interactivity)}
>
{<DecoTriangles />}
{<DisabledCross />}
</div>
/>
))}
</div>
);
const BgOtherBlocks: React.FC<{ className?: string }> = ({ className }) => (
<div className={classnames("bg-other-blocks", className)}>
<BgBlock className="banish" />
<BgBlock className="graveyard" />
<BgBlock className="field" />
</div>
);
export const Bg: React.FC = () => {
const snap = useSnapshot(placeStore.inner);
return (
......@@ -72,6 +81,8 @@ export const Bg: React.FC = () => {
/>
<BgRow snap={snap[ygopro.CardZone.MZONE].me} />
<BgRow snap={snap[ygopro.CardZone.SZONE].me} isSzone />
<BgOtherBlocks className="me" />
<BgOtherBlocks className="op" />
</div>
);
};
......
......@@ -57,6 +57,7 @@ export const Card: React.FC<{ idx: number }> = React.memo(({ idx }) => {
focusDisplay: "none",
focusOpacity: 1,
subZ: 0,
opacity: 1,
} satisfies SpringApiProps)
);
......@@ -310,6 +311,7 @@ export const Card: React.FC<{ idx: number }> = React.memo(({ idx }) => {
"--focus-scale": styles.focusScale,
"--focus-display": styles.focusDisplay,
"--focus-opacity": styles.focusOpacity,
opacity: styles.opacity,
} as any as CSSProperties
}
onClick={onClick}
......
......@@ -13,6 +13,8 @@ const {
CARD_RATIO,
COL_GAP,
ROW_GAP,
BLOCK_OUTSIDE_OFFSET_X,
CARD_HEIGHT_O,
} = matConfig;
const { MZONE, SZONE, TZONE } = ygopro.CardZone;
......@@ -36,9 +38,15 @@ export const moveToGround: MoveFunc = async (props) => {
switch (zone) {
case SZONE: {
if (sequence === 5) {
height = CARD_HEIGHT_O;
// 场地魔法
x = -(3 * (BLOCK_WIDTH + COL_GAP) - (BLOCK_WIDTH - cardWidth) / 2);
y = BLOCK_HEIGHT_M + ROW_GAP;
x = -(
BLOCK_WIDTH * 2.5 +
COL_GAP * 2 +
BLOCK_OUTSIDE_OFFSET_X +
CARD_HEIGHT_O * CARD_RATIO * 0.5
);
y = ROW_GAP + BLOCK_HEIGHT_M + (BLOCK_HEIGHT_M - CARD_HEIGHT_O) / 2;
} else {
x = (sequence - 2) * (BLOCK_WIDTH + COL_GAP);
y =
......
......@@ -4,18 +4,30 @@ import { isMe } from "@/stores";
import { matConfig } from "@/ui/Shared";
import { asyncStart, type MoveFunc } from "./utils";
const { BLOCK_WIDTH, BLOCK_HEIGHT_M, BLOCK_HEIGHT_S, COL_GAP, ROW_GAP } =
matConfig;
const {
BLOCK_WIDTH,
BLOCK_HEIGHT_M,
BLOCK_HEIGHT_S,
COL_GAP,
ROW_GAP,
CARD_HEIGHT_O,
BLOCK_OUTSIDE_OFFSET_X,
CARD_RATIO,
} = matConfig;
const { GRAVE } = ygopro.CardZone;
const { REMOVED } = ygopro.CardZone;
export const moveToOutside: MoveFunc = async (props) => {
const { card, api } = props;
// report
const { zone, controller, position, sequence } = card.location;
let x = (BLOCK_WIDTH + COL_GAP) * 3,
y = zone === GRAVE ? BLOCK_HEIGHT_M + ROW_GAP : 0;
let x =
BLOCK_WIDTH * 2.5 +
COL_GAP * 2 +
BLOCK_OUTSIDE_OFFSET_X +
CARD_HEIGHT_O * CARD_RATIO * 0.5,
y = ROW_GAP + BLOCK_HEIGHT_M + (BLOCK_HEIGHT_M - CARD_HEIGHT_O) / 2;
if (zone === REMOVED) y -= ROW_GAP + CARD_HEIGHT_O;
if (!isMe(controller)) {
x = -x;
y = -y;
......@@ -24,7 +36,7 @@ export const moveToOutside: MoveFunc = async (props) => {
x,
y,
z: 0,
height: BLOCK_HEIGHT_S,
height: CARD_HEIGHT_O,
rz: isMe(controller) ? 0 : 180,
ry: [ygopro.CardPosition.FACEDOWN].includes(position) ? 180 : 0,
subZ: 100,
......
......@@ -4,5 +4,7 @@ export const moveToToken: MoveFunc = async (props) => {
const { api } = props;
await asyncStart(api)({
height: 0,
opacity: 0,
});
api.set({ opacity: 1 });
};
......@@ -9,6 +9,7 @@ export interface SpringApiProps {
rz: number;
zIndex: number;
height: number;
opacity: number;
// >>> focus
focusScale: number;
focusDisplay: string;
......
......@@ -22,7 +22,7 @@ enum UNIT {
NONE = "",
}
const matConfigWithUnit: CSSConfig = {
const matConfigWithUnit = {
PERSPECTIVE: [1500, UNIT.PX],
PLANE_ROTATE_X: [0, UNIT.DEG],
BLOCK_WIDTH: [120, UNIT.PX],
......@@ -38,12 +38,18 @@ const matConfigWithUnit: CSSConfig = {
DECK_OFFSET_Y: [80, UNIT.PX],
DECK_ROTATE_Z: [30, UNIT.DEG],
DECK_CARD_HEIGHT: [120, UNIT.PX],
};
CARD_HEIGHT_O: [100, UNIT.PX], // 场地魔法/墓地/除外的卡片高度
BLOCK_OUTSIDE_OFFSET_X: [15, UNIT.PX],
} satisfies CSSConfig;
export const matConfig = Object.keys(matConfigWithUnit).reduce(
(prev, key) => ({ ...prev, [key]: matConfigWithUnit[key][0] }),
(prev, key) => ({
...prev,
// @ts-ignore
[key]: matConfigWithUnit[key][0],
}),
{} as Record<string, number>
);
) as Record<keyof typeof matConfigWithUnit, number>;
toCssProperties(matConfigWithUnit).forEach(([k, v]) => {
document.body.style.setProperty(k, v);
......
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