233 lines
8.7 KiB
TypeScript
233 lines
8.7 KiB
TypeScript
import { instantiate, Node, sp, Sprite, SpriteFrame, Texture2D } from "cc";
|
||
import { DRESS_PART, DRESS_SOURCE_TYPE, IDressInfo, SPINE_SLOT, SPINE_SOCKET } from "./Types";
|
||
import ResManager from "@max-studio/core/res/ResManager";
|
||
import { loadDressSocketNode } from "./PetUtils";
|
||
import { StringUtils } from "@max-studio/core/utils/StringUtils";
|
||
|
||
export class BasePart {
|
||
protected skeleton: sp.Skeleton = null;
|
||
protected info: IDressInfo = null;
|
||
protected socketName: string = null;
|
||
protected part: DRESS_PART = null;
|
||
protected faceSkeleton: sp.Skeleton = null;
|
||
protected socketMountNode: Node = null;
|
||
protected socketCache: Map<string, sp.SpineSocket> = new Map();
|
||
protected socketNode: Node = null;
|
||
|
||
constructor(ske: sp.Skeleton, part: DRESS_PART) {
|
||
this.skeleton = ske;
|
||
this.part = part;
|
||
this.socketName = SPINE_SOCKET[part];
|
||
this.faceSkeleton = ske.node.getChildByName("face")?.getComponent(sp.Skeleton);
|
||
}
|
||
|
||
public async putOn(info: IDressInfo) {
|
||
this.takeOff();
|
||
this.info = info;
|
||
if (info.sourceLocationType == DRESS_SOURCE_TYPE.SLOT) {
|
||
await this.putOnBySlot(info);
|
||
} else {
|
||
await this.putOnBySocket(info);
|
||
}
|
||
}
|
||
public takeOff() {
|
||
if (this.info == null) {
|
||
return;
|
||
}
|
||
const partSkeleton = this.getPartSkeleton();
|
||
if (this.info.sourceLocationType == DRESS_SOURCE_TYPE.SLOT) {
|
||
const slotName = SPINE_SLOT[this.part];
|
||
if (StringUtils.isEmpty(slotName) || partSkeleton == null) {
|
||
console.error("宠物_槽位_空", slotName);
|
||
return;
|
||
}
|
||
const slot = partSkeleton.findSlot(slotName);
|
||
if (!slot) {
|
||
console.error("宠物_槽位_不存在", slotName);
|
||
return;
|
||
}
|
||
if (slot.texture) {
|
||
ResManager.getInstance().releaseAsset(slot.texture);
|
||
slot.texture = null;
|
||
}
|
||
partSkeleton.setSlotTexture(slotName, null, true);
|
||
} else {
|
||
if (!this.socketNode) {
|
||
return;
|
||
}
|
||
const socketSprite = this.socketNode.getOrAddComponent(Sprite, "Texture");
|
||
if (socketSprite && socketSprite.spriteFrame) {
|
||
ResManager.getInstance().releaseAsset(socketSprite.spriteFrame);
|
||
socketSprite.spriteFrame = null;
|
||
}
|
||
const spine = this.socketNode.getOrAddComponent(sp.Skeleton, "Spine");
|
||
if (spine && spine.skeletonData) {
|
||
ResManager.getInstance().releaseAsset(spine.skeletonData);
|
||
spine.skeletonData = undefined;
|
||
spine.animation = undefined;
|
||
}
|
||
}
|
||
this.info = null;
|
||
}
|
||
|
||
private getPartSkeleton() {
|
||
if (
|
||
this.part == DRESS_PART.GLASSES ||
|
||
this.part == DRESS_PART.ACCESS ||
|
||
this.info.sourceLocationType == DRESS_SOURCE_TYPE.SOCKET_TEX_FACE ||
|
||
this.info.sourceLocationType == DRESS_SOURCE_TYPE.SOCKET_SPINE_FACE
|
||
) {
|
||
return this.faceSkeleton;
|
||
}
|
||
return this.skeleton;
|
||
}
|
||
|
||
private getPartBonePath(skeleton: sp.Skeleton, name: string) {
|
||
let path = "";
|
||
console.log("获取宠物_骨骼_路径:", name);
|
||
let bone = skeleton.findBone(name);
|
||
if (bone) {
|
||
path = bone.data.name;
|
||
while (bone.parent) {
|
||
bone = bone.parent;
|
||
path = `${bone.data.name}/${path}`;
|
||
if ("root" == bone.data.name) {
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
return path;
|
||
}
|
||
|
||
private getSocketNode(ske: sp.Skeleton, path: string): sp.SpineSocket {
|
||
let socket = this.socketCache.get(path);
|
||
if (socket == null) {
|
||
const sockets = ske.sockets as sp.SpineSocket[];
|
||
socket = sockets.find((s) => s.path == path);
|
||
if (!socket) {
|
||
console.error("宠物_挂点_不存在 创建挂点:", path);
|
||
socket = new sp.SpineSocket(path);
|
||
sockets.push(socket);
|
||
ske.sockets = sockets;
|
||
}
|
||
this.socketCache.set(path, socket);
|
||
}
|
||
return socket;
|
||
}
|
||
|
||
private async putOnBySlot(info: IDressInfo) {
|
||
const partSkeleton = this.getPartSkeleton();
|
||
const slotName = SPINE_SLOT[this.part];
|
||
if (StringUtils.isEmpty(slotName) || partSkeleton == null) {
|
||
console.error("宠物_槽位_空", slotName);
|
||
return;
|
||
}
|
||
const slot = partSkeleton.findSlot(slotName);
|
||
if (!slot) {
|
||
console.error("宠物_槽位_不存在", slotName);
|
||
return;
|
||
}
|
||
if (!info) {
|
||
if (slot.texture) {
|
||
ResManager.getInstance().releaseAsset(slot.texture);
|
||
slot.texture = null;
|
||
}
|
||
partSkeleton.setSlotTexture(slotName, null, true);
|
||
return;
|
||
}
|
||
const { err, asset } = await ResManager.getInstance().loadAsset({
|
||
bundle: "dress-spine",
|
||
path: `DressTexture/${info.sourceName}`,
|
||
type: Texture2D,
|
||
});
|
||
if (err) {
|
||
console.error("加载宠物_槽位_失败", err);
|
||
return;
|
||
}
|
||
if (this.info != info) {
|
||
ResManager.getInstance().releaseAsset(asset);
|
||
return;
|
||
}
|
||
if (slot.texture != null) {
|
||
ResManager.getInstance().releaseAsset(slot.texture);
|
||
slot.texture = null;
|
||
}
|
||
|
||
slot.texture = asset;
|
||
partSkeleton.setSlotTexture(slotName, asset, true);
|
||
}
|
||
|
||
private async putOnBySocket(info: IDressInfo) {
|
||
const partSkeleton = this.getPartSkeleton();
|
||
const bonePath = this.getPartBonePath(partSkeleton, this.socketName);
|
||
if (this.socketNode == null) {
|
||
const socketPrefab = await loadDressSocketNode();
|
||
if (socketPrefab == null) {
|
||
return;
|
||
}
|
||
this.socketNode = instantiate(socketPrefab);
|
||
}
|
||
|
||
if (
|
||
info.sourceLocationType == DRESS_SOURCE_TYPE.SOCKET_TEX_FACE ||
|
||
info.sourceLocationType == DRESS_SOURCE_TYPE.SOCKET_TEX
|
||
) {
|
||
const loadInfo = await ResManager.getInstance().loadAsset({
|
||
bundle: "dress-spine",
|
||
path: `DressTexture/${info.sourceName}`,
|
||
type: SpriteFrame,
|
||
});
|
||
if (loadInfo.err) {
|
||
console.error("加载宠物_socket_tex失败", loadInfo.err);
|
||
} else {
|
||
if (this.info == info) {
|
||
const socketSprite = this.socketNode.getOrAddComponent(Sprite, "Texture");
|
||
socketSprite.spriteFrame = loadInfo.asset as SpriteFrame;
|
||
} else {
|
||
console.warn("加载宠物_socket_tex失败,但是不是当前宠物");
|
||
ResManager.getInstance().releaseAsset(loadInfo.asset);
|
||
}
|
||
}
|
||
} else if (
|
||
info.sourceLocationType == DRESS_SOURCE_TYPE.SOCKET_SPINE ||
|
||
info.sourceLocationType == DRESS_SOURCE_TYPE.SOCKET_SPINE_FACE
|
||
) {
|
||
const loadInfo = await ResManager.getInstance().loadAsset({
|
||
bundle: "dress-spine",
|
||
path: `DressSpine/${info.sourceName}/${info.sourceName}`,
|
||
type: sp.SkeletonData,
|
||
});
|
||
if (loadInfo.err) {
|
||
console.error("加载宠物_socket_spine失败", loadInfo.err);
|
||
} else {
|
||
if (this.info == info) {
|
||
const spine = this.socketNode.getOrAddComponent(sp.Skeleton, "Spine");
|
||
spine.animation = undefined;
|
||
spine.skeletonData = loadInfo.asset as sp.SkeletonData;
|
||
spine.setAnimation(0, "idle", true);
|
||
} else {
|
||
console.warn("加载宠物_socket_spine失败,但是不是当前宠物");
|
||
ResManager.getInstance().releaseAsset(loadInfo.asset);
|
||
}
|
||
}
|
||
}
|
||
|
||
this.socketNode.setParent(partSkeleton.node);
|
||
const socket = this.getSocketNode(partSkeleton, bonePath);
|
||
this.socketNode.layer = partSkeleton.node.layer;
|
||
socket.target = this.socketNode;
|
||
const socketSpine = this.socketNode.getOrAddComponent(sp.Skeleton);
|
||
if (socketSpine && socketSpine.skeletonData) {
|
||
socketSpine.setAnimation(0, "idle", true);
|
||
}
|
||
// eslint-disable-next-line no-self-assign
|
||
partSkeleton.sockets = partSkeleton.sockets;
|
||
this.setSocketZIndex();
|
||
}
|
||
protected setSocketZIndex() {
|
||
if (this.socketNode) {
|
||
this.socketNode.setSiblingIndex(0);
|
||
}
|
||
}
|
||
}
|