Files
Max-Cocos-Demo/assets/games/scripts/pets/BasePart.ts
2025-11-26 22:57:07 +08:00

233 lines
8.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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);
}
}
}