提交 1422bb82 编写于 作者: V Viktor Lidholt

Optimizes sprite transformations for box to node

Enabling/disabling of handling multiple pointers
Adds basic touch handling

R=abarth@chromium.org

Review URL: https://codereview.chromium.org/1179413009.
上级 2b126efb
......@@ -14,66 +14,66 @@ class GameDemoBox extends SpriteBox {
int _secondPointer = -1;
Point _firstPointerDownPos;
void handleEvent(Event event, BoxHitTestEntry entry) {
if (event is PointerEvent) {
Point pointerPos = new Point(event.x, event.y);
int pointer = event.pointer;
switch (event.type) {
case 'pointerdown':
if (_firstPointer == -1) {
// Assign the first pointer
_firstPointer = pointer;
_firstPointerDownPos = pointerPos;
}
else if (_secondPointer == -1) {
// Assign second pointer
_secondPointer = pointer;
_gameWorld.controlFire();
}
else {
// There is a pointer used for steering, let's fire instead
_gameWorld.controlFire();
}
break;
case 'pointermove':
if (pointer == _firstPointer) {
// Handle turning control
double joystickX = 0.0;
double deltaX = pointerPos.x - _firstPointerDownPos.x;
if (deltaX > _steeringThreshold || deltaX < -_steeringThreshold) {
joystickX = (deltaX - _steeringThreshold)/(_steeringMax - _steeringThreshold);
if (joystickX > 1.0) joystickX = 1.0;
if (joystickX < -1.0) joystickX = -1.0;
}
double joystickY = 0.0;
double deltaY = pointerPos.y - _firstPointerDownPos.y;
if (deltaY > _steeringThreshold || deltaY < -_steeringThreshold) {
joystickY = (deltaY - _steeringThreshold)/(_steeringMax - _steeringThreshold);
if (joystickY > 1.0) joystickY = 1.0;
if (joystickY < -1.0) joystickY = -1.0;
}
_gameWorld.controlSteering(joystickX, joystickY);
}
break;
case 'pointerup':
case 'pointercancel':
if (pointer == _firstPointer) {
// Un-assign the first pointer
_firstPointer = -1;
_firstPointerDownPos = null;
_gameWorld.controlSteering(0.0, 0.0);
}
else if (pointer == _secondPointer) {
_secondPointer = -1;
}
break;
default:
break;
}
}
}
// void handleEvent(Event event, BoxHitTestEntry entry) {
// if (event is PointerEvent) {
// Point pointerPos = new Point(event.x, event.y);
// int pointer = event.pointer;
//
// switch (event.type) {
// case 'pointerdown':
// if (_firstPointer == -1) {
// // Assign the first pointer
// _firstPointer = pointer;
// _firstPointerDownPos = pointerPos;
// }
// else if (_secondPointer == -1) {
// // Assign second pointer
// _secondPointer = pointer;
// _gameWorld.controlFire();
// }
// else {
// // There is a pointer used for steering, let's fire instead
// _gameWorld.controlFire();
// }
// break;
// case 'pointermove':
// if (pointer == _firstPointer) {
// // Handle turning control
// double joystickX = 0.0;
// double deltaX = pointerPos.x - _firstPointerDownPos.x;
// if (deltaX > _steeringThreshold || deltaX < -_steeringThreshold) {
// joystickX = (deltaX - _steeringThreshold)/(_steeringMax - _steeringThreshold);
// if (joystickX > 1.0) joystickX = 1.0;
// if (joystickX < -1.0) joystickX = -1.0;
// }
//
// double joystickY = 0.0;
// double deltaY = pointerPos.y - _firstPointerDownPos.y;
// if (deltaY > _steeringThreshold || deltaY < -_steeringThreshold) {
// joystickY = (deltaY - _steeringThreshold)/(_steeringMax - _steeringThreshold);
// if (joystickY > 1.0) joystickY = 1.0;
// if (joystickY < -1.0) joystickY = -1.0;
// }
//
// _gameWorld.controlSteering(joystickX, joystickY);
// }
// break;
// case 'pointerup':
// case 'pointercancel':
// if (pointer == _firstPointer) {
// // Un-assign the first pointer
// _firstPointer = -1;
// _firstPointerDownPos = null;
// _gameWorld.controlSteering(0.0, 0.0);
// }
// else if (pointer == _secondPointer) {
// _secondPointer = -1;
// }
// break;
// default:
// break;
// }
// }
// }
}
......@@ -70,6 +70,9 @@ class GameDemoWorld extends NodeWithSize {
// Add nebula
addNebula();
userInteractionEnabled = true;
handleMultiplePointers = true;
}
// Methods for adding game objects
......@@ -200,6 +203,73 @@ class GameDemoWorld extends NodeWithSize {
void controlFire() {
addLaser();
}
// Handle pointer events
int _firstPointer = -1;
int _secondPointer = -1;
Point _firstPointerDownPos;
bool handleEvent(SpriteBoxEvent event) {
Point pointerPos = convertPointToNodeSpace(event.boxPosition);
int pointer = event.pointer;
switch (event.type) {
case 'pointerdown':
if (_firstPointer == -1) {
// Assign the first pointer
_firstPointer = pointer;
_firstPointerDownPos = pointerPos;
}
else if (_secondPointer == -1) {
// Assign second pointer
_secondPointer = pointer;
controlFire();
}
else {
// There is a pointer used for steering, let's fire instead
controlFire();
}
break;
case 'pointermove':
if (pointer == _firstPointer) {
// Handle turning control
double joystickX = 0.0;
double deltaX = pointerPos.x - _firstPointerDownPos.x;
if (deltaX > _steeringThreshold || deltaX < -_steeringThreshold) {
joystickX = (deltaX - _steeringThreshold)/(_steeringMax - _steeringThreshold);
if (joystickX > 1.0) joystickX = 1.0;
if (joystickX < -1.0) joystickX = -1.0;
}
double joystickY = 0.0;
double deltaY = pointerPos.y - _firstPointerDownPos.y;
if (deltaY > _steeringThreshold || deltaY < -_steeringThreshold) {
joystickY = (deltaY - _steeringThreshold)/(_steeringMax - _steeringThreshold);
if (joystickY > 1.0) joystickY = 1.0;
if (joystickY < -1.0) joystickY = -1.0;
}
controlSteering(joystickX, joystickY);
}
break;
case 'pointerup':
case 'pointercancel':
if (pointer == _firstPointer) {
// Un-assign the first pointer
_firstPointer = -1;
_firstPointerDownPos = null;
controlSteering(0.0, 0.0);
}
else if (pointer == _secondPointer) {
_secondPointer = -1;
}
break;
default:
break;
}
return true;
}
}
// Game objects
......@@ -230,6 +300,18 @@ class Asteroid extends Sprite {
_movementVector = new Point(_rand.nextDouble() * _maxAsteroidSpeed * 2 - _maxAsteroidSpeed,
_rand.nextDouble() * _maxAsteroidSpeed * 2 - _maxAsteroidSpeed);
userInteractionEnabled = true;
}
bool handleEvent(SpriteBoxEvent event) {
if (event.type == "pointerdown") {
colorOverlay = new Color(0x99ff0000);
}
else if (event.type == "pointerup") {
colorOverlay = null;
}
return false;
}
}
......
......@@ -13,10 +13,10 @@ class Node {
Point _position;
double _rotation;
bool _isMatrixDirty;
Matrix4 _transformMatrix;
Matrix4 _transformMatrixFromWorld;
Matrix4 _transformMatrixNodeToBox;
Matrix4 _transformMatrixBoxToNode;
double _scaleX;
double _scaleY;
......@@ -30,6 +30,10 @@ class Node {
bool paused = false;
bool _userInteractionEnabled = false;
bool handleMultiplePointers = false;
int _handlingPointer;
List<Node>_children;
// Constructors
......@@ -38,7 +42,6 @@ class Node {
_rotation = 0.0;
_position = Point.origin;
_scaleX = _scaleY = 1.0;
_isMatrixDirty = false;
_transformMatrix = new Matrix4.identity();
_children = [];
_childrenNeedSorting = false;
......@@ -56,20 +59,23 @@ class Node {
double get rotation => _rotation;
void set rotation(double rotation) {
assert(rotation != null);
_rotation = rotation;
_isMatrixDirty = true;
_invalidateTransformMatrix();
}
Point get position => _position;
void set position(Point position) {
assert(position != null);
_position = position;
_isMatrixDirty = true;
_invalidateTransformMatrix();
}
double get zPosition => _zPosition;
void set zPosition(double zPosition) {
assert(zPosition != null);
_zPosition = zPosition;
if (_parent != null) {
_parent._childrenNeedSorting = true;
......@@ -82,8 +88,9 @@ class Node {
}
void set scale(double scale) {
assert(scale != null);
_scaleX = _scaleY = scale;
_isMatrixDirty = true;
_invalidateTransformMatrix();
}
List<Node> get children => _children;
......@@ -91,6 +98,7 @@ class Node {
// Adding and removing children
void addChild(Node child) {
assert(child != null);
assert(child._parent == null);
_childrenNeedSorting = true;
......@@ -99,12 +107,15 @@ class Node {
child._spriteBox = this._spriteBox;
_childrenLastAddedOrder += 1;
child._addedOrder = _childrenLastAddedOrder;
if (_spriteBox != null) _spriteBox._eventTargets = null;
}
void removeChild(Node child) {
assert(child != null);
if (_children.remove(child)) {
child._parent = null;
child._spriteBox = null;
if (_spriteBox != null) _spriteBox._eventTargets = null;
}
}
......@@ -120,12 +131,13 @@ class Node {
}
_children = [];
_childrenNeedSorting = false;
if (_spriteBox != null) _spriteBox._eventTargets = null;
}
// Calculating the transformation matrix
Matrix4 get transformMatrix {
if (!_isMatrixDirty) {
if (_transformMatrix != null) {
return _transformMatrix;
}
......@@ -148,42 +160,58 @@ class Node {
}
// Create transformation matrix for scale, position and rotation
_transformMatrix.setValues(cy * _scaleX, sy * _scaleX, 0.0, 0.0,
_transformMatrix = new Matrix4(cy * _scaleX, sy * _scaleX, 0.0, 0.0,
-sx * _scaleY, cx * _scaleY, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
_position.x, _position.y, 0.0, 1.0
);
_position.x, _position.y, 0.0, 1.0);
return _transformMatrix;
}
void _invalidateTransformMatrix() {
_transformMatrix = null;
_invalidateToBoxTransformMatrix();
}
void _invalidateToBoxTransformMatrix () {
_transformMatrixNodeToBox = null;
_transformMatrixBoxToNode = null;
for (Node child in children) {
child._invalidateToBoxTransformMatrix();
}
}
// Transforms to other nodes
Matrix4 _nodeToBoxMatrix() {
assert(_spriteBox != null);
Matrix4 t = transformMatrix;
// Apply transforms from parents
Node p = this.parent;
while (p != null) {
t = new Matrix4.copy(p.transformMatrix).multiply(t);
p = p.parent;
if (_transformMatrixNodeToBox != null) {
return _transformMatrixNodeToBox;
}
// Apply transform from sprite box
t = new Matrix4.copy(_spriteBox.transformMatrix).multiply(t);
return t;
if (_parent == null) {
// Base case, we are at the top
assert(this == _spriteBox.rootNode);
_transformMatrixNodeToBox = new Matrix4.copy(_spriteBox.transformMatrix).multiply(transformMatrix);
}
else {
_transformMatrixNodeToBox = new Matrix4.copy(_parent._nodeToBoxMatrix()).multiply(transformMatrix);
}
return _transformMatrixNodeToBox;
}
Matrix4 _boxToNodeMatrix() {
assert(_spriteBox != null);
Matrix4 t = _nodeToBoxMatrix();
t.invert();
if (_transformMatrixBoxToNode != null) {
return _transformMatrixBoxToNode;
}
_transformMatrixBoxToNode = new Matrix4.copy(_nodeToBoxMatrix());
_transformMatrixBoxToNode.invert();
return t;
return _transformMatrixBoxToNode;
}
Point convertPointToNodeSpace(Point boxPoint) {
......@@ -225,6 +253,7 @@ class Node {
// Rendering
void visit(PictureRecorder canvas) {
assert(canvas != null);
if (!visible) return;
prePaint(canvas);
......@@ -241,7 +270,6 @@ class Node {
}
void paint(PictureRecorder canvas) {
}
void visitChildren(PictureRecorder canvas) {
......@@ -276,4 +304,17 @@ class Node {
void spriteBoxPerformedLayout() {
}
// Handling user interaction
bool get userInteractionEnabled => _userInteractionEnabled;
void set userInteractionEnabled(bool userInteractionEnabled) {
_userInteractionEnabled = userInteractionEnabled;
if (_spriteBox != null) _spriteBox._eventTargets = null;
}
bool handleEvent(SpriteBoxEvent event) {
return false;
}
}
\ No newline at end of file
......@@ -9,7 +9,9 @@ abstract class NodeWithSize extends Node {
pivot = Point.origin;
}
NodeWithSize.withSize(Size this.size, [Point this.pivot]);
NodeWithSize.withSize(Size this.size, [Point this.pivot]) {
if (pivot == null) pivot = Point.origin;
}
void applyTransformForPivot(PictureRecorder canvas) {
if (pivot.x != 0 || pivot.y != 0) {
......
......@@ -22,6 +22,7 @@ class Sprite extends NodeWithSize {
double get opacity => _opacity;
void set opacity(double opacity) {
assert(opacity != null);
assert(opacity >= 0.0 && opacity <= 1.0);
_opacity = opacity;
}
......
......@@ -28,7 +28,8 @@ class SpriteBox extends RenderBox {
// Cached transformation matrix
Matrix4 _transformMatrix;
bool _transformMatrixIsDirty;
List<Node> _eventTargets;
// Setup
......@@ -47,8 +48,6 @@ class SpriteBox extends RenderBox {
_systemWidth = width;
_systemHeight = height;
_transformMatrixIsDirty = true;
_scheduleTick();
}
......@@ -68,20 +67,80 @@ class SpriteBox extends RenderBox {
void performLayout() {
size = constraints.constrain(Size.infinite);
_transformMatrixIsDirty = true;
_invalidateTransformMatrix();
_callSpriteBoxPerformedLayout(_rootNode);
}
// Event handling
void handleEvent(Event event, BoxHitTestEntry entry) {
void _addEventTargets(Node node, List<Node> eventTargets) {
if (node.userInteractionEnabled) {
eventTargets.add(node);
}
for (Node child in node.children) {
_addEventTargets(child, eventTargets);
}
}
void handleEvent(Event event, SpriteBoxHitTestEntry entry) {
if (event is PointerEvent) {
if (event.type == 'pointerdown') {
// Build list of event targets
if (_eventTargets == null) {
_eventTargets = [];
_addEventTargets(_rootNode, _eventTargets);
}
// Find the once that are hit by the pointer
List<Node> nodeTargets = [];
for (int i = _eventTargets.length - 1; i >= 0; i--) {
Node node = _eventTargets[i];
// Check if the node is ready to handle a pointer
if (node.handleMultiplePointers || node._handlingPointer == null) {
// Do the hit test
Point posInNodeSpace = node.convertPointToNodeSpace(entry.localPosition);
if (node.hitTest(posInNodeSpace)) {
nodeTargets.add(node);
node._handlingPointer = event.pointer;
}
}
}
entry.nodeTargets = nodeTargets;
}
// Pass the event down to nodes that were hit by the pointerdown
List<Node> targets = entry.nodeTargets;
for (Node node in targets) {
// Check if this event should be dispatched
if (node.handleMultiplePointers || event.pointer == node._handlingPointer) {
// Dispatch event
bool consumedEvent = node.handleEvent(new SpriteBoxEvent(new Point(event.x, event.y), event.type, event.pointer));
if (consumedEvent == null || consumedEvent) break;
}
}
// De-register pointer for nodes that doesn't handle multiple pointers
for (Node node in targets) {
if (event.type == 'pointerup' || event.type == 'pointercancel') {
node._handlingPointer = null;
}
}
}
}
bool hitTest(HitTestResult result, { Point position }) {
result.add(new SpriteBoxHitTestEntry(this, position));
return true;
}
// Rendering
Matrix4 get transformMatrix {
// Get cached matrix if available
if (!_transformMatrixIsDirty && _transformMatrix != null) {
if (_transformMatrix != null) {
return _transformMatrix;
}
......@@ -145,6 +204,11 @@ class SpriteBox extends RenderBox {
return _transformMatrix;
}
void _invalidateTransformMatrix() {
_transformMatrix = null;
_rootNode._invalidateToBoxTransformMatrix();
}
void paint(RenderObjectDisplayList canvas) {
canvas.save();
......@@ -225,3 +289,16 @@ class SpriteBox extends RenderBox {
}
}
}
class SpriteBoxHitTestEntry extends BoxHitTestEntry {
List<Node> nodeTargets;
SpriteBoxHitTestEntry(RenderBox target, Point localPosition) : super(target, localPosition);
}
class SpriteBoxEvent {
Point boxPosition;
String type;
int pointer;
SpriteBoxEvent(this.boxPosition, this.type, this.pointer);
}
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册