From 2320e79c1d5dfc8a21ca535337c928496b65e12a Mon Sep 17 00:00:00 2001 From: helloyork Date: Fri, 25 Oct 2024 16:10:10 -0700 Subject: [PATCH] fixed: Image scale incorrect when resizing the stage --- CHANGELOG.md | 10 ++++++++++ package.json | 2 +- src/game/nlcore/elements/transform/transform.ts | 13 +++++++++++-- src/game/nlcore/game.ts | 4 ++-- src/game/nlcore/gameTypes.ts | 4 ++-- src/game/player/elements/displayable/Text.tsx | 14 ++++++++------ src/game/player/elements/image/Image.tsx | 12 ++++++------ src/game/player/elements/say/Say.tsx | 5 ++--- src/game/player/lib/AspectRatio.tsx | 3 ++- src/game/player/provider/ratio.tsx | 5 ++++- 10 files changed, 48 insertions(+), 24 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b873eef..513d2ab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,15 @@ # Changelog +## [0.1.2] - 2024/10/24 + +### Incompatible Changes + +- `game.config.player.width` and `game.config.player.height` cannot be string anymore + +### Fixed + +- Image scale incorrect when resizing the stage + ## [0.1.1] - 2024/10/23 ### Fixed diff --git a/package.json b/package.json index e378166..8e0dd3c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "narraleaf-react", - "version": "0.1.1", + "version": "0.1.2", "description": "A React visual novel player framework", "main": "./dist/main.js", "types": "./dist/index.d.ts", diff --git a/src/game/nlcore/elements/transform/transform.ts b/src/game/nlcore/elements/transform/transform.ts index d6d8094..0f8b8f2 100644 --- a/src/game/nlcore/elements/transform/transform.ts +++ b/src/game/nlcore/elements/transform/transform.ts @@ -127,7 +127,16 @@ export class Transform { } /**@internal */ - static propToCSSTransform(state: GameState, prop: Record, translate: [string?, string?] = []): string { + static propToCSSTransform( + state: GameState, + prop: Record, + { + translate = [], + scale = 1, + }: { + translate?: [string?, string?]; + scale?: number; + } = {}): string { if (!state.getLastScene()) { throw new Error("No scene found in state, make sure you called \"scene.activate()\" before this method."); } @@ -135,7 +144,7 @@ export class Transform { const Transforms = [ `translate(${translate[0] || ((invertX ? "" : "-") + "50%")}, ${translate[1] || ((invertY ? "" : "-") + "50%")})`, (prop["rotation"] !== undefined) && `rotate(${prop["rotation"]}deg)`, - (prop["scale"] !== undefined) && `scale(${prop["scale"]})`, + (prop["scale"] !== undefined) && `scale(${prop["scale"] * scale})`, ]; return Transforms.filter(Boolean).join(" "); } diff --git a/src/game/nlcore/game.ts b/src/game/nlcore/game.ts index 2ed700f..1947c84 100644 --- a/src/game/nlcore/game.ts +++ b/src/game/nlcore/game.ts @@ -31,8 +31,8 @@ export class Game { aspectRatio: 16 / 9, minWidth: 800, minHeight: 450, - width: "100%", - height: "100%", + width: 1920, + height: 1080, skipKey: ["Control"], skipInterval: 100, }, diff --git a/src/game/nlcore/gameTypes.ts b/src/game/nlcore/gameTypes.ts index 39f74da..1631c21 100644 --- a/src/game/nlcore/gameTypes.ts +++ b/src/game/nlcore/gameTypes.ts @@ -37,8 +37,8 @@ export type GameConfig = { * The minimum width and height of the player in pixels */ minHeight: number; - width: number | string; - height: number | string; + width: number; + height: number; /** * When player presses one of these keys, the game will skip the current action * diff --git a/src/game/player/elements/displayable/Text.tsx b/src/game/player/elements/displayable/Text.tsx index ad17141..43f6757 100644 --- a/src/game/player/elements/displayable/Text.tsx +++ b/src/game/player/elements/displayable/Text.tsx @@ -25,12 +25,14 @@ export default function Text({state, text}: Readonly<{ }, "transform": (props: TransformDefinitions.Types) => { return { - transform: Transform.propToCSSTransform(state, props, [ - text.config.alignX === "left" ? "0%" - : (text.config.alignX === "right" ? "-100%" : void 0), - text.config.alignY === "top" ? "100%" - : (text.config.alignY === "bottom" ? "0%" : void 0), - ]), + transform: Transform.propToCSSTransform(state, props, { + translate: [ + text.config.alignX === "left" ? "0%" + : (text.config.alignX === "right" ? "-100%" : void 0), + text.config.alignY === "top" ? "100%" + : (text.config.alignY === "bottom" ? "0%" : void 0), + ], + }), }; } }; diff --git a/src/game/player/elements/image/Image.tsx b/src/game/player/elements/image/Image.tsx index 2df40c4..0f493d8 100644 --- a/src/game/player/elements/image/Image.tsx +++ b/src/game/player/elements/image/Image.tsx @@ -8,6 +8,7 @@ import {ImgElementProp} from "@core/elements/transition/type"; import {useGame} from "@player/provider/game-state"; import {DisplayableChildProps} from "@player/elements/displayable/type"; import Displayable from "@player/elements/displayable/Displayable"; +import {useRatio} from "@player/provider/ratio"; export default function Image({ image, @@ -47,9 +48,7 @@ export default function Image({ element: image, skipTransition: state.game.config.elements.img.allowSkipTransition, skipTransform: state.game.config.elements.img.allowSkipTransform, - transformOverwrites: { - "scale": () => ({}), - }, + transformOverwrites: {}, }} child={(props) => ( void; }>) { + const {ratio} = useRatio(); const defaultProps: ImgElementProp = { src: Utils.staticImageDataToSrc(image.state.src), @@ -96,7 +96,7 @@ function DisplayableImage( style: { top: "50%", left: "50%", - transform: "translate(-50%, -50%)", + transform: `translate(-50%, -50%) scale(${ratio.state.scale})`, } } ]; @@ -123,7 +123,7 @@ function DisplayableImage( const mergedProps = deepMerge(defaultProps, elementProps, { style: { - // transform: "translate(-50%, -50%)" + transform: `scale(${ratio.state.scale})`, } }, transitionProps[index] || {}) as any; return ( @@ -143,7 +143,7 @@ function DisplayableImage( key={"last"} {...deepMerge(defaultProps, { style: { - // transform: "translate(-50%, 50%)" + transform: `scale(${ratio.state.scale})`, } })} onLoad={handleLoad} diff --git a/src/game/player/elements/say/Say.tsx b/src/game/player/elements/say/Say.tsx index 843586c..6c3b8e6 100644 --- a/src/game/player/elements/say/Say.tsx +++ b/src/game/player/elements/say/Say.tsx @@ -1,6 +1,5 @@ import clsx from "clsx"; import React, {useEffect, useState} from "react"; -import Isolated from "@player/lib/isolated"; import {SayElementProps} from "@player/elements/say/type"; import {GameState} from "@core/common/game"; import Sentence from "@player/elements/say/Sentence"; @@ -74,7 +73,7 @@ export default function Say( }); return ( - +
{sentence.state.display && (
) } - +
); }; \ No newline at end of file diff --git a/src/game/player/lib/AspectRatio.tsx b/src/game/player/lib/AspectRatio.tsx index 3df195c..fa55314 100644 --- a/src/game/player/lib/AspectRatio.tsx +++ b/src/game/player/lib/AspectRatio.tsx @@ -60,7 +60,8 @@ export default function AspectRatio( justifyContent: "center" }); - ratio.update(width, height); + const scale = width / game.config.player.width; + ratio.update(width, height, scale); ratio.updateMin(MIN_WIDTH, MIN_HEIGHT); forceUpdate(); } diff --git a/src/game/player/provider/ratio.tsx b/src/game/player/provider/ratio.tsx index 866565f..c0f6989 100644 --- a/src/game/player/provider/ratio.tsx +++ b/src/game/player/provider/ratio.tsx @@ -9,6 +9,7 @@ export type AspectRatioState = { minWidth: number; minHeight: number; paused: boolean; + scale: number; }; type AspectRatioEvents = { @@ -29,6 +30,7 @@ class AspectRatio { minWidth: 800, minHeight: 450, paused: false, + scale: 0, }; public readonly events = new EventDispatcher(); @@ -38,9 +40,10 @@ class AspectRatio { constructor() { } - update(width: number, height: number) { + update(width: number, height: number, scale: number) { this.state.width = width; this.state.height = height; + this.state.scale = scale; this.events.emit(AspectRatio.EventTypes["event:aspectRatio.update"], width, height); }