161 lines
4.2 KiB
Dart
161 lines
4.2 KiB
Dart
import 'package:flame/components.dart';
|
|
|
|
class RuntimeScaleMode {
|
|
const RuntimeScaleMode._();
|
|
|
|
static const fit = 'fit';
|
|
static const fill = 'fill';
|
|
static const stretch = 'stretch';
|
|
static const none = 'none';
|
|
|
|
static const all = {fit, fill, stretch, none};
|
|
|
|
static bool isSupported(String value) => all.contains(value);
|
|
}
|
|
|
|
class RuntimeViewportConfig {
|
|
const RuntimeViewportConfig({
|
|
required this.designWidth,
|
|
required this.designHeight,
|
|
this.scaleMode = RuntimeScaleMode.fit,
|
|
});
|
|
|
|
final double designWidth;
|
|
final double designHeight;
|
|
final String scaleMode;
|
|
|
|
Vector2 get designSize => Vector2(designWidth, designHeight);
|
|
}
|
|
|
|
class RuntimeViewportTransform {
|
|
const RuntimeViewportTransform({
|
|
required this.x,
|
|
required this.y,
|
|
required this.width,
|
|
required this.height,
|
|
required this.scaleX,
|
|
required this.scaleY,
|
|
required this.scaleMode,
|
|
});
|
|
|
|
final double x;
|
|
final double y;
|
|
final double width;
|
|
final double height;
|
|
final double scaleX;
|
|
final double scaleY;
|
|
final String scaleMode;
|
|
|
|
Map<String, Object?> toMap() {
|
|
return {
|
|
'x': x,
|
|
'y': y,
|
|
'width': width,
|
|
'height': height,
|
|
'scaleX': scaleX,
|
|
'scaleY': scaleY,
|
|
'scaleMode': scaleMode,
|
|
};
|
|
}
|
|
}
|
|
|
|
class RuntimeViewport {
|
|
const RuntimeViewport._();
|
|
|
|
static RuntimeViewportTransform compute({
|
|
required Vector2 screenSize,
|
|
required RuntimeViewportConfig config,
|
|
}) {
|
|
final designWidth = config.designWidth;
|
|
final designHeight = config.designHeight;
|
|
final screenWidth = screenSize.x;
|
|
final screenHeight = screenSize.y;
|
|
|
|
if (designWidth <= 0 || designHeight <= 0) {
|
|
throw const FormatException('Runtime viewport design size must be > 0');
|
|
}
|
|
if (!RuntimeScaleMode.isSupported(config.scaleMode)) {
|
|
throw FormatException(
|
|
'Runtime viewport scaleMode is unsupported: ${config.scaleMode}',
|
|
);
|
|
}
|
|
|
|
final safeScreenWidth = screenWidth <= 0 ? designWidth : screenWidth;
|
|
final safeScreenHeight = screenHeight <= 0 ? designHeight : screenHeight;
|
|
|
|
final scaleX = safeScreenWidth / designWidth;
|
|
final scaleY = safeScreenHeight / designHeight;
|
|
|
|
return switch (config.scaleMode) {
|
|
RuntimeScaleMode.fit => _uniform(
|
|
designWidth: designWidth,
|
|
designHeight: designHeight,
|
|
screenWidth: safeScreenWidth,
|
|
screenHeight: safeScreenHeight,
|
|
scale: scaleX < scaleY ? scaleX : scaleY,
|
|
scaleMode: config.scaleMode,
|
|
),
|
|
RuntimeScaleMode.fill => _uniform(
|
|
designWidth: designWidth,
|
|
designHeight: designHeight,
|
|
screenWidth: safeScreenWidth,
|
|
screenHeight: safeScreenHeight,
|
|
scale: scaleX > scaleY ? scaleX : scaleY,
|
|
scaleMode: config.scaleMode,
|
|
),
|
|
RuntimeScaleMode.stretch => RuntimeViewportTransform(
|
|
x: 0,
|
|
y: 0,
|
|
width: safeScreenWidth,
|
|
height: safeScreenHeight,
|
|
scaleX: scaleX,
|
|
scaleY: scaleY,
|
|
scaleMode: config.scaleMode,
|
|
),
|
|
RuntimeScaleMode.none => RuntimeViewportTransform(
|
|
x: (safeScreenWidth - designWidth) / 2,
|
|
y: (safeScreenHeight - designHeight) / 2,
|
|
width: designWidth,
|
|
height: designHeight,
|
|
scaleX: 1,
|
|
scaleY: 1,
|
|
scaleMode: config.scaleMode,
|
|
),
|
|
_ => throw FormatException(
|
|
'Runtime viewport scaleMode is unsupported: ${config.scaleMode}',
|
|
),
|
|
};
|
|
}
|
|
|
|
static void apply(
|
|
PositionComponent root,
|
|
RuntimeViewportTransform transform,
|
|
) {
|
|
root
|
|
..position = Vector2(transform.x, transform.y)
|
|
..scale = Vector2(transform.scaleX, transform.scaleY)
|
|
..size = Vector2(transform.width, transform.height);
|
|
}
|
|
|
|
static RuntimeViewportTransform _uniform({
|
|
required double designWidth,
|
|
required double designHeight,
|
|
required double screenWidth,
|
|
required double screenHeight,
|
|
required double scale,
|
|
required String scaleMode,
|
|
}) {
|
|
final width = designWidth * scale;
|
|
final height = designHeight * scale;
|
|
return RuntimeViewportTransform(
|
|
x: (screenWidth - width) / 2,
|
|
y: (screenHeight - height) / 2,
|
|
width: width,
|
|
height: height,
|
|
scaleX: scale,
|
|
scaleY: scale,
|
|
scaleMode: scaleMode,
|
|
);
|
|
}
|
|
}
|