Skip to content

Commit

Permalink
fix(spriteanimator): simplified aspect ratio calculation and fixed bu…
Browse files Browse the repository at this point in the history
…g with zooming (#1467)
  • Loading branch information
netgfx committed May 24, 2023
1 parent d42d257 commit 02c140e
Show file tree
Hide file tree
Showing 2 changed files with 15 additions and 28 deletions.
12 changes: 9 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2096,8 +2096,6 @@ type Props = {
fps?: number
/** The frame identifier to use, has to be one of animationNames */
frameName?: string
/** The scale factor of the aspect ratio */
scaleFactor?: number
/** The URL of the texture JSON (if using JSON-Array or JSON-Hash) */
textureDataURL?: string
/** The URL of the texture image */
Expand All @@ -2122,12 +2120,20 @@ type Props = {
play?: boolean
/** Control when the animation pauses */
pause?: boolean
/** Whether or not the Sprite should flip sides on the x-axis */
flipX?: boolean
/** Sets the alpha value to be used when running an alpha test. https://threejs.org/docs/#api/en/materials/Material.alphaTest */
alphaTest?: number
}
```

The SpriteAnimator component provided by drei is a powerful tool for animating sprites in a simple and efficient manner. It allows you to create sprite animations by cycling through a sequence of frames from a sprite sheet image or JSON data.

Notes:
The SpriteAnimator component internally uses the useFrame hook from react-three-fiber (r3f) for efficient frame updates and rendering.

- The SpriteAnimator component internally uses the useFrame hook from react-three-fiber (r3f) for efficient frame updates and rendering.
- The sprites should contain equal size frames
- Trimming of spritesheet frames is not yet supported

```jsx
<SpriteAnimator
Expand Down
31 changes: 6 additions & 25 deletions src/core/SpriteAnimator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ export type SpriteAnimatorProps = {
endFrame?: number
fps?: number
frameName?: string
scaleFactor?: number
maxScale?: number
textureDataURL?: string
textureImageURL: string
loop?: boolean
Expand All @@ -32,8 +30,6 @@ export const SpriteAnimator: React.FC<SpriteAnimatorProps> = (
endFrame,
fps,
frameName,
scaleFactor,
maxScale,
textureDataURL,
textureImageURL,
loop,
Expand Down Expand Up @@ -66,7 +62,6 @@ export const SpriteAnimator: React.FC<SpriteAnimatorProps> = (
const [spriteTexture, setSpriteTexture] = React.useState<THREE.Texture>(new THREE.Texture())
const totalFrames = React.useRef<number>(0)
const [aspect, setAspect] = React.useState<Vector3 | undefined>([1, 1, 1])
const aspectFactor = scaleFactor || 0.1
const flipOffset = flipX ? -1 : 1

function loadJsonAndTextureAndExecuteCallback(
Expand All @@ -85,24 +80,10 @@ export const SpriteAnimator: React.FC<SpriteAnimatorProps> = (
})
}

const calculateAspectRatio = (width: number, height: number, factor: number): Vector3 => {
const adaptedHeight = height * (v.aspect > width / height ? v.width / width : v.height / height)
const adaptedWidth = width * (v.aspect > width / height ? v.width / width : v.height / height)
const scaleX = adaptedWidth * factor
const scaleY = adaptedHeight * factor
const currentMaxScale = maxScale ?? 1
// Calculate the maximum scale based on the aspect ratio and max scale limit
let finalMaxScaleW = Math.min(currentMaxScale, scaleX)
let finalMaxScaleH = Math.min(currentMaxScale, scaleY)

// Ensure that scaleX and scaleY do not exceed the max scale while maintaining aspect ratio
if (scaleX > currentMaxScale) {
finalMaxScaleW = currentMaxScale
finalMaxScaleH = (scaleY / scaleX) * currentMaxScale
}

spriteRef.current.scale.set(finalMaxScaleW, finalMaxScaleH, 1)
return [finalMaxScaleW, finalMaxScaleH, 1]
const calculateAspectRatio = (width: number, height: number): Vector3 => {
const aspectRatio = height / width
spriteRef.current.scale.set(1, aspectRatio, 1)
return [1, aspectRatio, 1]
}

// initial loads
Expand Down Expand Up @@ -178,7 +159,7 @@ export const SpriteAnimator: React.FC<SpriteAnimatorProps> = (
textureData.current = _spriteTexture

const { w, h } = getFirstItem(json.frames).sourceSize
const aspect = calculateAspectRatio(w, h, aspectFactor)
const aspect = calculateAspectRatio(w, h)

setAspect(aspect)
if (matRef.current) {
Expand Down Expand Up @@ -292,7 +273,7 @@ export const SpriteAnimator: React.FC<SpriteAnimatorProps> = (
if (diff <= fpsInterval) return
timerOffset.current = now - (diff % fpsInterval)

calculateAspectRatio(frameW, frameH, aspectFactor)
calculateAspectRatio(frameW, frameH)
const framesH = (metaInfo.w - 1) / frameW
const framesV = (metaInfo.h - 1) / frameH
const {
Expand Down

1 comment on commit 02c140e

@vercel
Copy link

@vercel vercel bot commented on 02c140e May 24, 2023

Choose a reason for hiding this comment

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

Please sign in to comment.