Commit 840dfae9 authored by Viktor Lidholt's avatar Viktor Lidholt

Adds support for spline actions and constraints on nodes

parent a78370fe
part of sprites;
Point _cardinalSplineAt(Point p0, Point p1, Point p2, Point p3, double tension, double t) {
double t2 = t * t;
double t3 = t2 * t;
double s = (1.0 - tension) / 2.0;
double b1 = s * ((-t3 + (2.0 * t2)) - t);
double b2 = s * (-t3 + t2) + (2.0 * t3 - 3.0 * t2 + 1.0);
double b3 = s * (t3 - 2.0 * t2 + t) + (-2.0 * t3 + 3.0 * t2);
double b4 = s * (t3 - t2);
double x = p0.x * b1 + p1.x * b2 + p2.x * b3 + p3.x * b4;
double y = p0.y * b1 + p1.y * b2 + p2.y * b3 + p3.y * b4;
return new Point(x, y);
}
class ActionSpline extends ActionInterval {
ActionSpline(this.setter, this.points, double duration, [Curve curve]) : super(duration, curve) {
_dt = 1.0 / (points.length - 1.0);
}
final Function setter;
final List<Point> points;
double _dt;
void update(double t) {
double tension = 0.5;
int p;
double lt;
if (t < 0.0) t = 0.0;
if (t >= 1.0) {
p = points.length - 1;
lt = 1.0;
} else {
p = (t / _dt).floor();
lt = (t - _dt * p) / _dt;
}
Point p0 = points[(p - 1).clamp(0, points.length - 1)];
Point p1 = points[(p + 0).clamp(0, points.length - 1)];
Point p2 = points[(p + 1).clamp(0, points.length - 1)];
Point p3 = points[(p + 2).clamp(0, points.length - 1)];
Point newPos = _cardinalSplineAt(p0, p1, p2, p3, tension, lt);
//print("newPos: $newPos");
setter(newPos);
}
}
part of sprites;
abstract class Constraint {
void preUpdate(Node node, double dt) {
}
void constrain(Node node, double dt);
}
double _dampenRotation(double src, double dst, double dampening) {
double delta = dst - src;
while (delta > 180.0) delta -= 360;
while (delta < -180) delta += 360;
delta *= dampening;
return src + delta;
}
class ConstraintRotationToMovement {
ConstraintRotationToMovement([this.dampening]);
final double dampening;
Point _lastPosition;
void preUpdate(Node node, double dt) {
_lastPosition = node.position;
}
void constrain(Node node, double dt) {
assert(_lastPosition != null);
if (_lastPosition == node.position) return;
// Get the target angle
Offset offset = node.position - _lastPosition;
double target = degrees(GameMath.atan2(offset.dy, offset.dx));
if (dampening == null)
node.rotation = target;
else
node.rotation = _dampenRotation(node.rotation, target, dampening);
}
}
......@@ -76,6 +76,25 @@ class Node {
return _actions;
}
List<Constraint> _constraints;
List<Constraint> get constraints {
return _constraints;
}
set constraints(List<Constraint> constraints) {
_constraints = constraints;
if (_spriteBox != null) _spriteBox._constrainedNodes = null;
}
void applyConstraints(double dt) {
if (_constraints == null) return;
for (Constraint constraint in _constraints) {
constraint.constrain(this, dt);
}
}
// Constructors
/// Creates a new [Node] without any transformation.
......
......@@ -74,6 +74,8 @@ class SpriteBox extends RenderBox {
List<ActionController> _actionControllers;
List<Node> _constrainedNodes;
Rect _visibleArea;
Rect get visibleArea {
......@@ -139,11 +141,13 @@ class SpriteBox extends RenderBox {
_registerNode(Node node) {
_actionControllers = null;
_eventTargets = null;
if (node == null || node.constraints != null) _constrainedNodes = null;
}
_deregisterNode(Node node) {
_actionControllers = null;
_eventTargets = null;
if (node == null || node.constraints != null) _constrainedNodes = null;
}
// Event handling
......@@ -353,8 +357,10 @@ class SpriteBox extends RenderBox {
_frameRate = 1.0/delta;
_callConstraintsPreUpdate(delta);
_runActions(delta);
_callUpdate(_rootNode, delta);
_callConstraintsConstrain(delta);
// Schedule next update
_scheduleTick();
......@@ -392,6 +398,42 @@ class SpriteBox extends RenderBox {
}
}
void _callConstraintsPreUpdate(double dt) {
if (_constrainedNodes == null) {
_constrainedNodes = [];
_addConstrainedNodes(_rootNode, _constrainedNodes);
}
for (Node node in _constrainedNodes) {
for (Constraint constraint in node.constraints) {
constraint.preUpdate(node, dt);
}
}
}
void _callConstraintsConstrain(double dt) {
if (_constrainedNodes == null) {
_constrainedNodes = [];
_addConstrainedNodes(_rootNode, _constrainedNodes);
}
for (Node node in _constrainedNodes) {
for (Constraint constraint in node.constraints) {
constraint.constrain(node, dt);
}
}
}
void _addConstrainedNodes(Node node, List<Node> nodes) {
if (node._constraints != null && node._constraints.length > 0) {
nodes.add(node);
}
for (Node child in node.children) {
_addConstrainedNodes(child, nodes);
}
}
void _callSpriteBoxPerformedLayout(Node node) {
node.spriteBoxPerformedLayout();
for (Node child in node.children) {
......
......@@ -22,6 +22,8 @@ import 'package:sky_services/media/media.mojom.dart';
import 'package:vector_math/vector_math.dart';
part 'action.dart';
part 'constraint.dart';
part 'action_spline.dart';
part 'color_secuence.dart';
part 'image_map.dart';
part 'layer.dart';
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment