如何用Spritekit实现这个动画?

时间:2023-01-23 07:54:12

Question:

题:

How to achieve this animation with Spritekit?

如何用Spritekit实现这个动画?

如何用Spritekit实现这个动画?

What I've done:

我做了什么:

如何用Spritekit实现这个动画?

Problem:

问题:

1) I can draw all four petals,but once I lift my finger to draw the circle, it will still create a line from the previous point where I lift my finger to the new touches begin point. refer to gif below:

1)我可以绘制所有四个花瓣,但是一旦我抬起手指画圆圈,它仍然会从前一点创建一条线,在那里我将手指抬起到新的触点开始点。请参考下面的gif:

如何用Spritekit实现这个动画?

2) How to remove the solid orange line from the view incrementally (mine is too abrupt)?

2)如何逐渐从视图中删除实心橙色线(我的太突然)?

3) Need to tune the .sks file properties.

3)需要调整.sks文件属性。

4) https://*.com/questions/29792443/set-the-initial-state-of-skemitternode

4)https://*.com/questions/29792443/set-the-initial-state-of-skemitternode

This is my code:

这是我的代码:

#import "GameScene.h"

@interface GameScene()

@property (nonatomic) SKEmitterNode* fireEmmitter;
@property (nonatomic) SKEmitterNode* fireEmmitter2;

@end

@implementation GameScene

NSMutableArray *_wayPoints;
NSTimer* myTimer;

-(void)didMoveToView:(SKView *)view {

_wayPoints = [NSMutableArray array];

//Setup a background
self.backgroundColor = [UIColor blackColor];

//setup a fire emitter
NSString *fireEmmitterPath = [[NSBundle mainBundle] pathForResource:@"magic" ofType:@"sks"];
_fireEmmitter = [NSKeyedUnarchiver unarchiveObjectWithFile:fireEmmitterPath];
_fireEmmitter.position = CGPointMake(self.frame.size.width/2, self.frame.size.height/2 - 200);
_fireEmmitter.name = @"fireEmmitter";
_fireEmmitter.zPosition = 1;
_fireEmmitter.targetNode = self;
_fireEmmitter.particleBirthRate = 0;
[self addChild: _fireEmmitter];

//setup another fire emitter
NSString *fireEmmitterPath2 = [[NSBundle mainBundle] pathForResource:@"fireflies" ofType:@"sks"];
_fireEmmitter2 = [NSKeyedUnarchiver unarchiveObjectWithFile:fireEmmitterPath2];
_fireEmmitter2.position = CGPointMake(self.frame.size.width/2, self.frame.size.height/2);
_fireEmmitter2.name = @"fireEmmitter";
_fireEmmitter2.zPosition = 1;
_fireEmmitter2.targetNode = self;
_fireEmmitter2.particleBirthRate = 0;
[self addChild: _fireEmmitter2];


//Setup a LightNode
SKLightNode* light = [[SKLightNode alloc] init];
light.categoryBitMask = 1;
light.falloff = 1;
light.ambientColor = [UIColor whiteColor];
light.lightColor = [[UIColor alloc] initWithRed:1.0 green:1.0 blue:0.0 alpha:0.5];
light.shadowColor = [[UIColor alloc] initWithRed:0.0 green:0.0 blue:0.0 alpha:0.3];
[_fireEmmitter addChild:light];

}

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {

CGPoint touchPoint = [[touches anyObject] locationInNode:self.scene];

CGMutablePathRef ref = CGPathCreateMutable();

CGPoint p = touchPoint;
p = [self.scene convertPointToView:p];
CGPathMoveToPoint(ref, NULL, p.x, p.y);

_fireEmmitter.position = CGPointMake(touchPoint.x, touchPoint.y);
_fireEmmitter.particleBirthRate = 2000;

}

-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {

CGPoint touchPoint = [[touches anyObject] locationInNode:self.scene];

//On Dragging make the emitter with the attached light follow the position
for (UITouch *touch in touches) {
    [self addPointToMove:touchPoint];

    CGPoint location = [touch locationInNode:self];
    [self childNodeWithName:@"fireEmmitter"].position = CGPointMake(location.x, location.y);
}
}

-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
_fireEmmitter.particleBirthRate = 0;

[self performSelector:@selector(userHasCompletedTheDrawing) withObject:nil afterDelay:3];
}

- (void)userHasCompletedTheDrawing{
CGMutablePathRef path = CGPathCreateMutable();
if (_wayPoints && _wayPoints.count > 0) {
    CGPoint p = [(NSValue *)[_wayPoints objectAtIndex:0] CGPointValue];
    //p = [self.scene convertPointToView:p];
    CGPathMoveToPoint(path, nil, p.x, p.y);

    _fireEmmitter2.position = CGPointMake(p.x,p.y);
    _fireEmmitter2.particleBirthRate = 1000;

    for (int i = 0; i < _wayPoints.count; ++i) {
        p = [(NSValue *)[_wayPoints objectAtIndex:i] CGPointValue];
        CGPathAddLineToPoint(path, nil, p.x, p.y);
    }
    SKAction *followTrack = [SKAction followPath:path asOffset:NO orientToPath:YES duration:1];
    [_fireEmmitter2 runAction:followTrack completion:^{

        _fireEmmitter2.particleBirthRate = 0;

        [_fireEmmitter2 runAction:[SKAction waitForDuration:1] completion:^{
            //_fireEmmitter2.particleBirthRate = 0;
        }];
    }];
}


//myTimer = [NSTimer scheduledTimerWithTimeInterval: 0.01 target: self selector: @selector(removePointToMove) userInfo: nil repeats: YES];
[self performSelector:@selector(removeAllPointToMove) withObject:nil afterDelay:1];

}

- (void)addPointToMove:(CGPoint)point {
[_wayPoints addObject:[NSValue valueWithCGPoint:point]];
}

- (void)removeAllPointToMove{
[_wayPoints removeAllObjects];
}

- (void)removePointToMove{

if ([_wayPoints count]>0) {
    [_wayPoints removeObjectAtIndex:0];
}
}

- (void)drawLines {
//1

NSMutableArray *temp = [NSMutableArray array];
for(CALayer *layer in self.view.layer.sublayers) {
    if([layer.name isEqualToString:@"line"]) {
        [temp addObject:layer];
    }
}

[temp makeObjectsPerformSelector:@selector(removeFromSuperlayer)];

//3
CAShapeLayer *lineLayer = [CAShapeLayer layer];
lineLayer.name = @"line";
lineLayer.strokeColor = [UIColor orangeColor].CGColor;
lineLayer.fillColor = nil;
lineLayer.lineWidth = 3;
lineLayer.lineJoin = kCALineJoinRound; /* The join style used when stroking the path. Options are `miter', `round'
                                        * and `bevel'. Defaults to `miter'. */
lineLayer.zPosition = -1;

//4
CGPathRef path = [self createPathToMove];
lineLayer.path = path;
CGPathRelease(path);
[self.view.layer addSublayer:lineLayer];

}

- (CGPathRef)createPathToMove {
//1
CGMutablePathRef ref = CGPathCreateMutable();

//2
for(int i = 0; i < [_wayPoints count]; ++i) {
    CGPoint p = [_wayPoints[i] CGPointValue];
    p = [self.scene convertPointToView:p];
    //3
    if(i == 0 ) {
        CGPathMoveToPoint(ref, NULL, p.x, p.y);
    } else {
        CGPathAddLineToPoint(ref, NULL, p.x, p.y);
    }
}

return ref;
}

-(void)update:(CFTimeInterval)currentTime {
/* Called before each frame is rendered */

[self drawLines];

if ([_wayPoints count]==0) {
    [myTimer invalidate];
}

}
@end

This is my .sks files properties:

这是我的.sks文件属性:

如何用Spritekit实现这个动画?如何用Spritekit实现这个动画?

1 个解决方案

#1


1  

Concerning your first question, you need to split your CGPathRef into multiple subpaths so that no line gets drawn between the petals and the center. Use the CGPathCloseSubpath function when you are done drawing the petals so that you can call CGPathMoveToPoint and CGPathAddLineToPoint afterwards.

关于第一个问题,您需要将CGPathRef拆分为多个子路径,以便在花瓣和中心之间不会绘制任何线条。完成绘制花瓣后使用CGPathCloseSubpath函数,以便之后可以调用CGPathMoveToPoint和CGPathAddLineToPoint。

#1


1  

Concerning your first question, you need to split your CGPathRef into multiple subpaths so that no line gets drawn between the petals and the center. Use the CGPathCloseSubpath function when you are done drawing the petals so that you can call CGPathMoveToPoint and CGPathAddLineToPoint afterwards.

关于第一个问题,您需要将CGPathRef拆分为多个子路径,以便在花瓣和中心之间不会绘制任何线条。完成绘制花瓣后使用CGPathCloseSubpath函数,以便之后可以调用CGPathMoveToPoint和CGPathAddLineToPoint。