Skip to content

fix: add skin support#912

Open
MakinoharaShoko wants to merge 1 commit intodevfrom
fix-spine-skins
Open

fix: add skin support#912
MakinoharaShoko wants to merge 1 commit intodevfrom
fix-spine-skins

Conversation

@MakinoharaShoko
Copy link
Member

No description provided.

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly enhances the WebGAL engine by adding comprehensive support for dynamic Spine animation skin changes. It provides the necessary API, integrates skin selection into game scripts, and updates the state management to allow for seamless application and persistence of different character skins during gameplay. This feature allows for greater visual customization and variety for Spine models.

Highlights

  • Spine Skin Support: Introduced a new public method changeSpineSkinByKey in PixiController to dynamically change the skin of a Spine animation figure based on its key and the desired skin name.
  • Utility Function for Skin Application: Created a new applySpineSkin utility function in spine.ts to encapsulate the logic for finding and applying a skin to a Spine object, including handling different Spine runtime versions and setup poses.
  • Game Script Integration: The changeFigure game script now accepts a skin argument, allowing game designers to specify a Spine skin directly within game commands.
  • State Management Update: The ILive2DMotion interface and the setLive2dMotion reducer have been updated to include and manage the skin property, ensuring skin changes are properly tracked in the application state.
  • Automatic Skin Application: The useSetFigure hook now automatically applies the specified Spine skin when a figure's motion state is updated, ensuring visual consistency.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@cloudflare-workers-and-pages
Copy link

Deploying webgal-dev with  Cloudflare Pages  Cloudflare Pages

Latest commit: 2dfafcb
Status: ✅  Deploy successful!
Preview URL: https://d52550f6.webgal-dev.pages.dev
Branch Preview URL: https://fix-spine-skins.webgal-dev.pages.dev

View logs

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces skin support for Spine figures in the WebGAL project. It adds a new function changeSpineSkinByKey to PixiController.ts to change the skin of a Spine figure based on a key and skin name. It also modifies spine.ts to include a function applySpineSkin that applies the skin to the Spine object. Additionally, it updates changeFigure.ts, useSetFigure.ts, stageInterface.ts, and stageReducer.ts to integrate the new skin functionality into the game's scripting and state management systems. The changes look good overall, but there are some areas where improvements can be made to enhance code clarity and prevent potential issues.

figureSpine.interactive = false;

// 检查状态中是否有指定的动画
const motionFromState = webgalStore.getState().stage.live2dMotion.find((e) => e.target === key);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

This line reintroduces the original issue of checking the state for animations. It would be better to ensure that this logic is consistent with the new skin implementation.

Comment on lines +285 to +320
function applySpineSkin(spineObject: any, skinName: string) {
// @ts-ignore
const skeleton = spineObject.skeleton;
// @ts-ignore
const skeletonData = skeleton?.data ?? spineObject.spineData;
const skin =
// @ts-ignore
skeletonData?.findSkin?.(skinName) ??
// @ts-ignore
skeletonData?.skins?.find((item: any) => item.name === skinName);
if (!skeleton || !skin) {
return false;
}
try {
// @ts-ignore
if (typeof skeleton.setSkinByName === 'function') {
// @ts-ignore
skeleton.setSkinByName(skinName);
} else {
// @ts-ignore
skeleton.setSkin(skin);
}
} catch (error) {
// @ts-ignore
skeleton.setSkin?.(skin);
}
// @ts-ignore
if (typeof skeleton.setSlotsToSetupPose === 'function') {
// @ts-ignore
skeleton.setSlotsToSetupPose();
} else {
// @ts-ignore
skeleton.setupPoseSlots?.();
}
return true;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

This function duplicates the skin application logic found in PixiController.ts. Consolidate this logic into a single, reusable function to avoid redundancy and improve maintainability.

/**
 * Applies a skin to a Spine object.
 * @param spineObject The Spine object to apply the skin to.
 * @param skinName The name of the skin to apply.
 * @returns True if the skin was successfully applied, false otherwise.
 */
function applySpineSkin(spineObject: any, skinName: string): boolean {
  if (!spineObject?.skeleton) {
    logger.warn("Spine object has no skeleton.");
    return false;
  }

  const skeleton = spineObject.skeleton;
  const skeletonData = skeleton.data || spineObject.spineData;
  const skin = skeletonData?.findSkin?.(skinName) || skeletonData?.skins?.find((item: any) => item.name === skinName);

  if (!skin) {
    logger.warn(`Spine skin not found: ${skinName}`);
    return false;
  }

  try {
    if (typeof skeleton.setSkinByName === 'function') {
      skeleton.setSkinByName(skinName);
    } else {
      skeleton.setSkin(skin);
    }
  } catch (error) {
    logger.error(`Failed to set skin ${skinName}:`, error);
    skeleton.setSkin?.(skin);
  }

  if (typeof skeleton.setSlotsToSetupPose === 'function') {
    skeleton.setSlotsToSetupPose();
  } else {
    skeleton.setupPoseSlots?.();
  }

  return true;
}

Comment on lines +862 to +916
public changeSpineSkinByKey(key: string, skin: string) {
if (!skin) return;

const target = this.figureObjects.find((e) => e.key === key && !e.isExiting);
if (target?.sourceType !== 'spine') return;

const container = target.pixiContainer;
if (!container) return;
const sprite = container.children[0] as PIXI.Container;
if (sprite?.children?.[0]) {
const spineObject = sprite.children[0];
// @ts-ignore
const skeleton = spineObject.skeleton;
// @ts-ignore
const skeletonData = skeleton?.data ?? spineObject.spineData;
const skinObject =
// @ts-ignore
skeletonData?.findSkin?.(skin) ??
// @ts-ignore
skeletonData?.skins?.find((item: any) => item.name === skin);

if (!skeleton || !skinObject) {
logger.warn(`Spine skin not found: ${skin} on ${key}`);
return;
}

try {
// @ts-ignore
if (typeof skeleton.setSkinByName === 'function') {
// @ts-ignore
skeleton.setSkinByName(skin);
} else {
// @ts-ignore
skeleton.setSkin(skinObject);
}
} catch (error) {
// @ts-ignore
skeleton.setSkin?.(skinObject);
}

// @ts-ignore
if (typeof skeleton.setSlotsToSetupPose === 'function') {
// @ts-ignore
skeleton.setSlotsToSetupPose();
} else {
// @ts-ignore
skeleton.setupPoseSlots?.();
}

// @ts-ignore
spineObject.state?.apply?.(skeleton);
// @ts-ignore
skeleton.updateWorldTransform?.();
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This function contains a lot of duplicated code and multiple // @ts-ignore comments. It would be better to extract the skin application logic into a separate, reusable function to improve readability and maintainability. Also, consider using optional chaining instead of multiple if statements to check for nested properties.

Comment on lines +897 to +899
} catch (error) {
// @ts-ignore
skeleton.setSkin?.(skinObject);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The catch block only contains a // @ts-ignore comment and then attempts to set the skin. It would be better to log the error and potentially provide a more graceful fallback, or rethrow the error if it's unrecoverable.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant