Commit 4f120d4d authored by Chunchi Che's avatar Chunchi Che

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

Feat/ui/plate

See merge request mycard/Neos!15
parents 40f7217e 3516fc7d
Pipeline #17837 passed with stages
in 3 minutes and 4 seconds
// 测试用的Babylon.js demo页面
import React, { useEffect, useRef } from "react";
import * as BABYLON from "@babylonjs/core";
export default function () {
const canvasRef = useRef<HTMLCanvasElement>(null);
useEffect(() => {
if (canvasRef.current) {
const canvasCurrent = canvasRef.current;
const engine = new BABYLON.Engine(canvasCurrent, true);
const scene = new BABYLON.Scene(engine);
const camera = new BABYLON.FreeCamera(
"camera1",
new BABYLON.Vector3(0, 5, -10),
scene
);
camera.setTarget(BABYLON.Vector3.Zero());
camera.attachControl(canvasCurrent, true);
const light = new BABYLON.HemisphericLight(
"light",
new BABYLON.Vector3(0, 1, 0),
scene
);
light.intensity = 0.7;
const sphere = BABYLON.MeshBuilder.CreateSphere(
"sphere",
{ diameter: 2, segments: 32 },
scene
);
sphere.position.y = 1;
const ground = BABYLON.MeshBuilder.CreateGround(
"ground",
{ width: 6, height: 6 },
scene
);
engine.runRenderLoop(() => {
scene.render();
});
}
}, [canvasRef]);
return <canvas ref={canvasRef} />;
}
......@@ -3,7 +3,7 @@
*
* */
import SimpleDuelPlateImpl from "./simpleDuel";
import SimpleDuelPlateImpl from "./simpleDuel/mod";
export default function Duel() {
return new SimpleDuelPlateImpl().render();
......
/*
* 一个简洁的决斗界面实现
*
* */
import { IDuelPlate, TypeSelector } from "./duel";
import * as DuelData from "./data";
import { useAppSelector } from "../../hook";
import React from "react";
import type { RootState } from "../../store";
export default class SimpleDuelPlateImpl implements IDuelPlate {
handsSelector?: TypeSelector<DuelData.Card[]>;
constructor() {}
render(): React.ReactElement {
// 默认的手牌Selector,返回三个code为-1的Card。
const defaultHandsSelector = (_: RootState) => {
return new Array(5).fill({ code: -1 });
};
const hands = useAppSelector(this.handsSelector || defaultHandsSelector);
return (
<div>
<table border={1}>
<tr>
{hands.map((hand) => (
<td>{hand.code}</td>
))}
</tr>
</table>
</div>
);
}
registerHands(selector: TypeSelector<DuelData.Card[]>): void {
this.handsSelector = selector;
}
}
/*
* SimpleDuelPlateImpl的一些配置
*
* */
import * as BABYLON from "@babylonjs/core";
export const GroundShape = () => {
return { width: 6, height: 6 };
};
export const CardSlotShape = () => {
return { width: 0.5, height: 0.75, depth: 0.05 };
};
export const CardSlotRotation = () => {
return new BABYLON.Vector3(1.5, 0, 0);
};
// 手牌
export const HandShape = () => {
return { width: 0.5, height: 0.75 };
};
export const HandColor = () => {
return BABYLON.Color3.White();
};
// 怪兽区
export const MonsterColor = () => {
return BABYLON.Color3.Red();
};
// 额外怪兽区
export const extraMonsterColor = () => {
return BABYLON.Color3.Yellow();
};
// 魔法陷阱区
export const MagicColor = () => {
return BABYLON.Color3.Blue();
};
import * as BABYLON from "@babylonjs/core";
import * as CONFIG from "./config";
export default (scene: BABYLON.Scene) => {
const xs = [-1, 1];
for (let i in xs) {
const slot = BABYLON.MeshBuilder.CreateBox(
`extraMonster${i}`,
CONFIG.CardSlotShape(),
scene
);
// 位置
slot.position = new BABYLON.Vector3(xs[i], 0.5, -1);
// 旋转
slot.rotation = CONFIG.CardSlotRotation();
// 材质
const extraMonsterMaterial = new BABYLON.StandardMaterial(
"extraMonsterMaterial",
scene
);
extraMonsterMaterial.diffuseColor = CONFIG.extraMonsterColor();
slot.material = extraMonsterMaterial;
}
};
import { Card } from "../data";
import * as BABYLON from "@babylonjs/core";
import * as CONFIG from "./config";
export default (hands: Card[], scene: BABYLON.Scene) => {
const groundShape = CONFIG.GroundShape();
const handShape = CONFIG.HandShape();
const gap = groundShape.width / hands.length;
const left = -(groundShape.width / 2);
hands.forEach((item, idx, _) => {
const hand = BABYLON.MeshBuilder.CreatePlane(
`hand${idx}`,
handShape,
scene
);
// 位置
hand.position = new BABYLON.Vector3(
left + gap * idx,
handShape.height / 2,
-(groundShape.height / 2) - 1
);
// 材质
const handMaterial = new BABYLON.StandardMaterial("handMaterial", scene);
// 材质颜色
handMaterial.diffuseColor = CONFIG.HandColor();
hand.material = handMaterial;
// 事件管理
hand.actionManager = new BABYLON.ActionManager(scene);
// 监听点击事件
hand.actionManager.registerAction(
new BABYLON.ExecuteCodeAction(
BABYLON.ActionManager.OnPickTrigger,
(event) => {
console.log(`<Click>hand: ${idx}`, "card:", item, "event:", event);
}
)
);
});
};
import * as BABYLON from "@babylonjs/core";
import * as CONFIG from "./config";
export default (scene: BABYLON.Scene) => {
const left = -2;
const gap = 1;
for (let i = 0; i < 5; i++) {
const slot = BABYLON.MeshBuilder.CreateBox(
`magic${i}`,
CONFIG.CardSlotShape(),
scene
);
// 位置
slot.position = new BABYLON.Vector3(left + gap * i, 0.5, -3);
// 旋转
slot.rotation = CONFIG.CardSlotRotation();
// 材质
const magicMaterial = new BABYLON.StandardMaterial("magicMaterial", scene);
magicMaterial.diffuseColor = CONFIG.MagicColor();
slot.material = magicMaterial;
}
};
/*
* 一个简洁的决斗界面实现
*
* */
import { IDuelPlate, TypeSelector } from "../duel";
import * as DuelData from "../data";
import { useAppSelector } from "../../../hook";
import React, { useEffect, useRef } from "react";
import type { RootState } from "../../../store";
import * as BABYLON from "@babylonjs/core";
import renderHands from "./hands";
import renderMonsters from "./monsters";
import renderExtraMonsters from "./extraMonsters";
import renderMagics from "./magics";
import * as CONFIG from "./config";
// CONFIG
export default class SimpleDuelPlateImpl implements IDuelPlate {
handsSelector?: TypeSelector<DuelData.Card[]>;
constructor() {}
render(): React.ReactElement {
// ----- 数据获取 -----
// 默认的手牌Selector,返回三个code为-1的Card。
const defaultHandsSelector = (_: RootState) => {
return new Array(5).fill({ code: -1 });
};
const hands = useAppSelector(this.handsSelector || defaultHandsSelector);
// ----- WebGL渲染 -----
const canvasRef = useRef<HTMLCanvasElement>(null);
useEffect(() => {
// 初始化Scene
const canvasCurrent = canvasRef.current;
const engine = new BABYLON.Engine(canvasCurrent, true);
const scene = new BABYLON.Scene(engine);
// 创建Camera
const camera = new BABYLON.FreeCamera(
"camera1",
new BABYLON.Vector3(0, 5, -10), // 俯视方向
scene
);
camera.setTarget(BABYLON.Vector3.Zero()); // 俯视向前
camera.attachControl(canvasCurrent, true);
// 创建光源
const light = new BABYLON.HemisphericLight(
"light",
new BABYLON.Vector3(1, 2.5, 1),
scene
);
light.intensity = 0.7;
// 魔法陷阱区
renderMagics(scene);
// 怪兽区
renderMonsters(scene);
// 创建额外怪兽区
renderExtraMonsters(scene);
// 创建手牌
renderHands(hands, scene);
// 创建地板
const ground = BABYLON.MeshBuilder.CreateGround(
"ground",
CONFIG.GroundShape(),
scene
);
// 渲染循环
engine.runRenderLoop(() => {
scene.render();
});
}, [canvasRef]);
return (
<canvas
width={window.innerWidth}
height={window.innerHeight}
ref={canvasRef}
/>
);
}
registerHands(selector: TypeSelector<DuelData.Card[]>): void {
this.handsSelector = selector;
}
}
import * as BABYLON from "@babylonjs/core";
import * as CONFIG from "./config";
export default (scene: BABYLON.Scene) => {
const left = -2;
const gap = 1;
for (let i = 0; i < 5; i++) {
const slot = BABYLON.MeshBuilder.CreateBox(
`monster${i}`,
CONFIG.CardSlotShape(),
scene
);
// 位置
slot.position = new BABYLON.Vector3(left + gap * i, 0.5, -2);
// 旋转
slot.rotation = CONFIG.CardSlotRotation();
// 材质
const monsterMaterial = new BABYLON.StandardMaterial(
"monsterMaterial",
scene
);
monsterMaterial.diffuseColor = CONFIG.MonsterColor();
slot.material = monsterMaterial;
}
};
......@@ -2,7 +2,6 @@ import React from "react";
import JoinRoom from "./JoinRoom";
import WaitRoom from "./WaitRoom";
import ThreeJs from "./ThreeJs";
import BabylonJs from "./BabylonJs";
import { Routes, Route } from "react-router-dom";
import Mora from "./Mora";
import Duel from "./Duel/main";
......@@ -16,7 +15,6 @@ export default function () {
<Route path="/mora" element={<Mora />} />
<Route path="/duel" element={<Duel />} />
<Route path="/three" element={<ThreeJs />} />
<Route path="/babylon" element={<BabylonJs />} />
</Routes>
);
}
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