2015-10-13 16:34:01 -07:00

143 lines
4.9 KiB
Dart

part of flutter_sprites;
/// A constraint limits or otherwise controls a [Node]'s properties, such as
/// position or rotation. Add a list of constraints by setting the [Node]'s
/// constraints property.
///
/// Constrains are applied after the update calls are
/// completed. They can also be applied at any time by calling a [Node]'s
/// [applyConstraints] method. It's possible to create custom constraints by
/// overriding this class and implementing the [constrain] method.
abstract class Constraint {
/// Called before the node's update method is called. This method can be
/// overridden to create setup work that needs to happen before the the
/// node is updated, e.g. to calculate the node's speed.
void preUpdate(Node node, double dt) {
}
/// Called after update is complete, if the constraint has been added to a
/// [Node]. Override this method to modify the node's property according to
/// the constraint.
void constrain(Node node, double dt);
}
double _dampenRotation(double src, double dst, double dampening) {
if (dampening == null)
return dst;
double delta = dst - src;
while (delta > 180.0) delta -= 360;
while (delta < -180) delta += 360;
delta *= dampening;
return src + delta;
}
/// A [Constraint] that aligns a nodes rotation to its movement.
class ConstraintRotationToMovement extends Constraint {
/// Creates a new constraint the aligns a nodes rotation to its movement
/// vector. A [baseRotation] and [dampening] can optionally be set.
ConstraintRotationToMovement({this.baseRotation: 0.0, this.dampening});
/// The filter factor used when constraining the rotation of the node. Valid
/// values are in the range 0.0 to 1.0
final double dampening;
/// The base rotation will be added to a the movement vectors rotation.
final double baseRotation;
Point _lastPosition;
void preUpdate(Node node, double dt) {
_lastPosition = node.position;
}
void constrain(Node node, double dt) {
if (_lastPosition == null) return;
if (_lastPosition == node.position) return;
// Get the target angle
Offset offset = node.position - _lastPosition;
double target = degrees(GameMath.atan2(offset.dy, offset.dx)) + baseRotation;
node.rotation = _dampenRotation(node.rotation, target, dampening);
}
}
/// A [Constraint] that rotates a node to point towards another node. The target
/// node is allowed to have a different parent, but they must be in the same
/// [SpriteBox].
class ConstraintRotationToNode extends Constraint {
/// Creates a new [Constraint] that rotates the node towards the [targetNode].
/// The [baseRotation] will be added to the nodes rotation, and [dampening]
/// can be used to ease the rotation.
ConstraintRotationToNode(this.targetNode, {this.baseRotation: 0.0, this.dampening});
/// The node to rotate towards.
final Node targetNode;
/// The base rotation will be added after the target rotation is calculated.
final double baseRotation;
/// The filter factor used when constraining the rotation of the node. Valid
/// values are in the range 0.0 to 1.0
final double dampening;
void constrain(Node node, double dt) {
Offset offset;
if (targetNode.spriteBox != node.spriteBox) {
// The target node is in another sprite box or has been removed
return;
}
if (targetNode.parent == node.parent) {
offset = targetNode.position - node.position;
} else {
offset = node.convertPointToBoxSpace(Point.origin)
- targetNode.convertPointToBoxSpace(Point.origin);
}
double target = degrees(GameMath.atan2(offset.dy, offset.dx)) + baseRotation;
node.rotation = _dampenRotation(node.rotation, target, dampening);
}
}
/// A [Constraint] that constrains the position of a node to equal the position
/// of another node, optionally with dampening.
class ConstraintPositionToNode extends Constraint {
/// Creates a new [Constraint] that constrains the poistion of a node to be
/// equal to the position of the [targetNode]. Optionally an [offset] can
/// be used and also [dampening]. The targetNode doesn't need to have the
/// same parent, but they need to be added to the same [SpriteBox].
ConstraintPositionToNode(this.targetNode, {this.dampening, this.offset: Offset.zero});
final Node targetNode;
final Offset offset;
final double dampening;
void constrain(Node node, double dt) {
Point targetPosition;
if (targetNode.spriteBox != node.spriteBox || node.parent == null) {
// The target node is in another sprite box or has been removed
return;
}
if (targetNode.parent == node.parent) {
targetPosition = targetNode.position;
} else {
targetPosition = node.parent.convertPointFromNode(Point.origin, targetNode);
}
if (offset != null)
targetPosition += offset;
if (dampening == null)
node.position = targetPosition;
else
node.position = GameMath.filterPoint(node.position, targetPosition, dampening);
}
}