diff --git a/Extensions/CCTransformationNode/CCTransformationNode.h b/Extensions/CCTransformationNode/CCTransformationNode.h index 1584fa2..c7cd3bf 100644 --- a/Extensions/CCTransformationNode/CCTransformationNode.h +++ b/Extensions/CCTransformationNode/CCTransformationNode.h @@ -35,6 +35,7 @@ @property (nonatomic, assign) float roll; @property (nonatomic, assign) float pitch; +@property (nonatomic, assign) float yaw; @property (nonatomic, assign) float perspective; // strength of the 3D perspective @property (nonatomic, readonly, getter = isBackFacing) BOOL backFacing; // node is backfacing diff --git a/Extensions/CCTransformationNode/CCTransformationNode.m b/Extensions/CCTransformationNode/CCTransformationNode.m index d3b0a1c..7d481f0 100644 --- a/Extensions/CCTransformationNode/CCTransformationNode.m +++ b/Extensions/CCTransformationNode/CCTransformationNode.m @@ -49,6 +49,7 @@ - (instancetype)init // initialize _roll = 0.0f; _pitch = 0.0f; + _yaw = 0.0f; _perspective = 1.0; _dirty = YES; // done @@ -59,17 +60,40 @@ - (instancetype)init - (void)visit:(CCRenderer *)renderer parentTransform:(const GLKMatrix4 *)parentTransform { + if (!_visible) return; + if (_dirty) { - + CGSize size = [CCDirector sharedDirector].viewSize; + float aspect = size.width / size.height; + // create rotation matrix GLKMatrix4 matrixPitch = GLKMatrix4MakeXRotation(_pitch); GLKMatrix4 matrixRoll = GLKMatrix4MakeYRotation(_roll); - _transformation = GLKMatrix4Multiply(matrixRoll, matrixPitch); - - // apple perspective - _transformation.m03 = _perspective * sinf(_roll) * cosf(_pitch); - _transformation.m13 = _perspective * sinf(_pitch) * cosf(_roll); + GLKMatrix4 matrixYaw = GLKMatrix4MakeZRotation(_yaw); + + // create translation matrix + CGPoint pos = [self positionInPoints]; + pos = ccp((2 * pos.x / size.width) - 1.0, (2 * pos.y / size.height) - 1.0); + GLKMatrix4 matrixTranslate = GLKMatrix4MakeTranslation(pos.x, pos.y, 0); + + // greate perspective matrix + GLKMatrix4 perspective = GLKMatrix4Make( + 1.0, 0.0, 0.0, 0.0, + 0.0, 1.0, 0.0, 0.0, + 0.0, 0.0, 0.0, _perspective, + 0.0, 0.0, 0.0, 1.0 + ); + + // calculate combined rotation + GLKMatrix4 rotation = GLKMatrix4Multiply(matrixRoll, matrixPitch); + + // adjust perspective for yaw and translation + perspective = GLKMatrix4Multiply(matrixYaw, perspective); + perspective = GLKMatrix4Multiply(matrixTranslate, perspective); + + // create final rotation + perspective martix + _transformation = GLKMatrix4Multiply(perspective, rotation); // transformation is up to date _dirty = NO; @@ -78,17 +102,45 @@ - (void)visit:(CCRenderer *)renderer parentTransform:(const GLKMatrix4 *)parentT // calculate final transformation (used for backface calculation) _finalTransformation = GLKMatrix4Multiply(_transformation, *parentTransform); - [super visit:renderer parentTransform:&_finalTransformation]; + // create basic transformation matrix + // position is not used + CGAffineTransform t = [self nodeToParentTransform]; + t.tx = [CCDirector sharedDirector].viewSize.width / 2; + t.ty = [CCDirector sharedDirector].viewSize.height / 2; + + // Convert to 4x4 column major GLK matrix. + _finalTransformation = GLKMatrix4Multiply(_finalTransformation, + GLKMatrix4Make( + t.a, t.b, 0.0f, 0.0f, + t.c, t.d, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + t.tx, t.ty, _vertexZ, 1.0f + )); + + // draw self and children + BOOL drawn = NO; + + for (CCNode *child in _children) + { + if (!drawn && (child.zOrder >= 0)) + { + [self draw:renderer transform:&_finalTransformation]; + drawn = YES; + } + [child visit:renderer parentTransform:&_finalTransformation]; + } + + if (!drawn) [self draw:renderer transform:&_finalTransformation]; + + // reset for next frame + _orderOfArrival = 0; } //---------------------------------------------------------------------- - (BOOL)isBackFacing { - // this can not be calculated uder _dirty, as parent transform might change - GLKVector3 vector = (GLKVector3){0,0,1}; - vector = GLKMatrix4MultiplyVector3 (_finalTransformation, vector); - return(vector.z > 0); + return(_finalTransformation.m23 > 0); } //---------------------------------------------------------------------- @@ -105,6 +157,12 @@ - (void)setPitch:(float)pitch _pitch = pitch; } +- (void)setYaw:(float)yaw +{ + _dirty = YES; + _yaw = yaw; +} + //---------------------------------------------------------------------- @end diff --git a/Extensions/CCTransformationNode/README.md b/Extensions/CCTransformationNode/README.md index 96b1a78..650fdb3 100644 --- a/Extensions/CCTransformationNode/README.md +++ b/Extensions/CCTransformationNode/README.md @@ -2,8 +2,7 @@ CCTransformationNode ==================== Type of class : Descendant of CCNode - -Uses extension : +Uses extension : [NONE] A node, capable of adding 3D transformations to a scene. @@ -17,10 +16,11 @@ It requires no other setup, or that you switch to 3D. You can either add this no Three properties have been implememnted. 1) Roll, which will roll the sprite around its Y axis 2) Pitch, which will roll the sprite around its X axis +3) Yaw, which will roll the sprite around its Z axis 3) Perspective, which will define the amount of perspective added (0=no perspective) OBS! -**This component is still experimental** +There is still a slight problem with aspect ratio The goal is to try to avoid to have the user to switch to a perspective projection, as this can cause artifacts for 2D games. diff --git a/cocos2d-iphone-ext/Classes/Tests/CCTransformationNodeTest.m b/cocos2d-iphone-ext/Classes/Tests/CCTransformationNodeTest.m index 5a7311e..68ec27d 100644 --- a/cocos2d-iphone-ext/Classes/Tests/CCTransformationNodeTest.m +++ b/cocos2d-iphone-ext/Classes/Tests/CCTransformationNodeTest.m @@ -78,10 +78,11 @@ - (void)cardFlipTest _transformation.positionType = CCPositionTypeNormalized; _transformation.position = ccp(0.5, 0.5); + [self.contentNode addChild:_transformation]; _card = [cardNode cardWithName:[cardNode randomCardName]]; - _card.scale = 2; + // _card.scale = 2; _card.name = @"card.0"; [_transformation addChild:_card]; } @@ -90,22 +91,21 @@ - (void)cardFlipTest - (void)cardFlipTestA { - self.subTitle = @"(pitch + rotation) works"; + self.subTitle = @"Pitch + Rotation"; _flipType = CCFlipTypePitchRotation; [self cardFlipTest]; } - (void)cardFlipTestB { - self.subTitle = @"(roll + rotation) works"; + self.subTitle = @"Roll + Rotation"; _flipType = CCFlipTypeRollRotation; [self cardFlipTest]; } - - (void)cardFlipTestC { - self.subTitle = @"(pitch + roll) BROKEN (wrong aspect 50% of the time)"; + self.subTitle = @"Pitch + Roll"; _flipType = CCFlipTypePitchRoll; [self cardFlipTest]; } @@ -117,7 +117,6 @@ - (void)update:(CCTime)delta delta *= 0.125; CCNode *card = [self getChildByName:@"card.0" recursively:YES]; - // card.rotation += 0.2; if ([card isKindOfClass:[cardNode class]]) { @@ -132,12 +131,14 @@ - (void)update:(CCTime)delta case CCFlipTypePitchRotation: _transformation.pitch += 11.0 * delta; - _transformation.rotation += 100 * delta; + // _transformation.rotation += 100 * delta; + _transformation.yaw += delta; break; case CCFlipTypeRollRotation: _transformation.roll += 11.0 * delta; - _transformation.rotation += 100 * delta; + // _transformation.rotation += 100 * delta; + _transformation.yaw += delta; break; } }