mirror of
https://github.com/flame-engine/flame.git
synced 2025-11-03 20:36:31 +08:00
refactor!: Remove the Projector interface that is no longer used for coordinate transformations (#2955)
Remove the Projector interface that is no longer used for coordinate transformations. While this is exposed to end-users there is not much point in doing so as it was always an internal detail of our implementation. Since our last batch of removals of the old event system, this was left orphaned. I don't think deprecation is necessary as it is very unlikely that anyone is using this interface (and if they are, they can easily declare their own as we do not care about it anywhere). This interface is no longer necessary to interop with Flame in any way shape or form. If you wish to use it internally in your game you can just declare it yourself.
This commit is contained in:
2
.github/.cspell/words_dictionary.txt
vendored
2
.github/.cspell/words_dictionary.txt
vendored
@ -34,5 +34,3 @@ tappable
|
||||
tappables
|
||||
toolset
|
||||
underutilize
|
||||
unproject
|
||||
unscale
|
||||
|
||||
@ -11,6 +11,5 @@ export 'src/game/game.dart';
|
||||
export 'src/game/game_widget/game_widget.dart';
|
||||
export 'src/game/mixins/single_game_instance.dart';
|
||||
export 'src/game/notifying_vector2.dart';
|
||||
export 'src/game/projector.dart';
|
||||
export 'src/game/transform2d.dart';
|
||||
export 'src/text/renderers/text_paint.dart';
|
||||
|
||||
@ -1,104 +0,0 @@
|
||||
import 'package:flame/extensions.dart';
|
||||
|
||||
/// A simple interface to mark a class that can perform projection operations
|
||||
/// from one 2D Euclidean coordinate space to another.
|
||||
///
|
||||
/// This can be a Viewport, a Camera or anything else that exposes such
|
||||
/// operations to the user.
|
||||
abstract class Projector {
|
||||
/// Converts a vector in the screen space to the world space.
|
||||
///
|
||||
/// This considers both the translation and scaling transformations.
|
||||
Vector2 unprojectVector(Vector2 screenCoordinates);
|
||||
|
||||
/// Converts a vector in the world space to the screen space.
|
||||
///
|
||||
/// This considers both the translation and scaling transformations.
|
||||
Vector2 projectVector(Vector2 worldCoordinates);
|
||||
|
||||
/// Converts a vector representing a delta in the screen space to the world
|
||||
/// space.
|
||||
///
|
||||
/// This considers only the scaling transformation, as the translations are
|
||||
/// cancelled in a delta transformation.
|
||||
/// A delta can be a displacement (difference between two position
|
||||
/// vectors), a velocity (displacement over time), etc.
|
||||
Vector2 unscaleVector(Vector2 screenCoordinates);
|
||||
|
||||
/// Converts a vector representing a delta in the world space to the screen
|
||||
/// space.
|
||||
///
|
||||
/// This considers only the scaling transformation, as the translations are
|
||||
/// cancelled in a delta transformation.
|
||||
/// A delta can be a displacement (difference between two position
|
||||
/// vectors), a velocity (displacement over time), etc.
|
||||
Vector2 scaleVector(Vector2 worldCoordinates);
|
||||
|
||||
/// Creates a [ComposedProjector] that will apply the provided projectors
|
||||
/// in order.
|
||||
///
|
||||
/// Use when dealing with multiple coordinate transformations in succession.
|
||||
static Projector compose(List<Projector> projectors) {
|
||||
return ComposedProjector(projectors);
|
||||
}
|
||||
}
|
||||
|
||||
/// A simple Projector implementation that represents the identity operation
|
||||
/// (i.e. no-op).
|
||||
class IdentityProjector extends Projector {
|
||||
@override
|
||||
Vector2 projectVector(Vector2 v) => v;
|
||||
|
||||
@override
|
||||
Vector2 scaleVector(Vector2 v) => v;
|
||||
|
||||
@override
|
||||
Vector2 unprojectVector(Vector2 v) => v;
|
||||
|
||||
@override
|
||||
Vector2 unscaleVector(Vector2 v) => v;
|
||||
}
|
||||
|
||||
/// This is a [Projector] implementation that composes a list of projectors,
|
||||
/// in the order provided.
|
||||
///
|
||||
/// It will call the `project*` functions in the order in the array and the
|
||||
/// `unproject*` in the reversed order.
|
||||
/// For a list of projectors p1, p2, ..., pn, this is equivalent of the
|
||||
/// projector p = pn ∘ ... ∘ p2 ∘ p1.
|
||||
class ComposedProjector extends Projector {
|
||||
final List<Projector> _components;
|
||||
ComposedProjector(this._components);
|
||||
|
||||
@override
|
||||
Vector2 scaleVector(Vector2 worldCoordinates) {
|
||||
return _components.fold(
|
||||
worldCoordinates,
|
||||
(previousValue, element) => element.scaleVector(previousValue),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Vector2 projectVector(Vector2 worldCoordinates) {
|
||||
return _components.fold(
|
||||
worldCoordinates,
|
||||
(previousValue, element) => element.projectVector(previousValue),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Vector2 unscaleVector(Vector2 screenCoordinates) {
|
||||
return _components.reversed.fold(
|
||||
screenCoordinates,
|
||||
(previousValue, element) => element.unscaleVector(previousValue),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Vector2 unprojectVector(Vector2 screenCoordinates) {
|
||||
return _components.reversed.fold(
|
||||
screenCoordinates,
|
||||
(previousValue, element) => element.unprojectVector(previousValue),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -1,80 +0,0 @@
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:flame/game.dart';
|
||||
import 'package:flame_test/flame_test.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
void main() {
|
||||
group('IdentityProjector', () {
|
||||
test('basic properties', () {
|
||||
final projector = IdentityProjector();
|
||||
checkProjectorReversibility(projector);
|
||||
final v = Vector2(3.14, -3.15);
|
||||
expect(projector.projectVector(v), closeToVector(v));
|
||||
expect(projector.scaleVector(v), closeToVector(v));
|
||||
});
|
||||
});
|
||||
|
||||
group('ComposedProjector', () {
|
||||
test('compose 2 projectors', () {
|
||||
final projector = ComposedProjector([
|
||||
_ScaleProjector(3),
|
||||
_ScaleProjector(-1),
|
||||
]);
|
||||
checkProjectorReversibility(projector);
|
||||
expect(
|
||||
projector.projectVector(Vector2(4, 5)),
|
||||
closeToVector(Vector2(-12, -15)),
|
||||
);
|
||||
expect(
|
||||
projector.projectVector(Vector2(1, -2)),
|
||||
closeToVector(Vector2(-3, 6)),
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/// This function verifies that for the given [projector], its `project` and
|
||||
/// `unproject` methods are the inverses of one another.
|
||||
void checkProjectorReversibility(Projector projector) {
|
||||
final random = Random();
|
||||
for (var i = 0; i < 10; i++) {
|
||||
final point = Vector2(
|
||||
random.nextDouble() * exp(random.nextDouble().abs() * 2),
|
||||
random.nextDouble() * exp(random.nextDouble().abs() * 2),
|
||||
);
|
||||
expect(
|
||||
projector.projectVector(projector.unprojectVector(point)),
|
||||
closeToVector(point, 1e-13),
|
||||
);
|
||||
expect(
|
||||
projector.unprojectVector(projector.projectVector(point)),
|
||||
closeToVector(point, 1e-13),
|
||||
);
|
||||
expect(
|
||||
projector.scaleVector(projector.unscaleVector(point)),
|
||||
closeToVector(point, 1e-13),
|
||||
);
|
||||
expect(
|
||||
projector.unscaleVector(projector.scaleVector(point)),
|
||||
closeToVector(point, 1e-13),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _ScaleProjector extends Projector {
|
||||
_ScaleProjector(this.scale);
|
||||
final double scale;
|
||||
|
||||
@override
|
||||
Vector2 projectVector(Vector2 p) => p.scaled(scale);
|
||||
|
||||
@override
|
||||
Vector2 scaleVector(Vector2 p) => p.scaled(scale);
|
||||
|
||||
@override
|
||||
Vector2 unprojectVector(Vector2 p) => p.scaled(1 / scale);
|
||||
|
||||
@override
|
||||
Vector2 unscaleVector(Vector2 p) => p.scaled(1 / scale);
|
||||
}
|
||||
Reference in New Issue
Block a user