分享一个酷炫的粒子动画实现

271 篇文章 0 订阅
6 篇文章 0 订阅

之前在 Code4App 上看到的一个粒子动画实现,下面先上图看下动画效果,接着分析下里面的核心实现方便大家实现其它更酷炫的动画效果。

源码地址:Code4App Demo
废话少说,先上图看下效果。

顶部掉落   底部投射



先看下把图片变成一个个像素点的代码实现:

- (NSArray*)getRGBAsFromImage:(UIImage*)image {
    //1. get the image into your data buffer.
    CGImageRef imageRef = [image CGImage];
    NSUInteger imageW = CGImageGetWidth(imageRef);
    NSUInteger imageH = CGImageGetHeight(imageRef);
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    NSUInteger bytesPerPixel = 4; //一个像素4字节
    NSUInteger bytesPerRow = bytesPerPixel * imageW;
    unsigned char *rawData = (unsigned char*)calloc(imageH*imageW*bytesPerPixel, sizeof(unsigned char)); //元数据
    NSUInteger bitsPerComponent = 8;
    CGContextRef context = CGBitmapContextCreate(rawData, imageW, imageH, bitsPerComponent, bytesPerRow, colorSpace, kCGImageAlphaPremultipliedLast|kCGBitmapByteOrder32Big);
    CGColorSpaceRelease(colorSpace);
    CGContextDrawImage(context, CGRectMake(0, 0, imageW, imageH), imageRef);
    CGContextRelease(context);

    //2. Now your rawData contains the image data in the RGBA8888 pixel format.
    CGFloat addY = (_maxParticleCount == 0) ? 1 : (imageH/_maxParticleCount);
    CGFloat addX = (_maxParticleCount == 0) ? 1 : (imageW/_maxParticleCount);
    NSMutableArray *result = [NSMutableArray new];
    for (int y = 0; y < imageH; y+=addY) {
        for (int x = 0; x < imageW; x+=addX) {
            NSUInteger byteIndex = bytesPerRow*y + bytesPerPixel*x;
            //rawData一维数组存储方式RGBA(第一个像素)RGBA(第二个像素)...
            CGFloat red   = ((CGFloat) rawData[byteIndex]     ) / 255.0f;
            CGFloat green = ((CGFloat) rawData[byteIndex + 1] ) / 255.0f;
            CGFloat blue  = ((CGFloat) rawData[byteIndex + 2] ) / 255.0f;
            CGFloat alpha = ((CGFloat) rawData[byteIndex + 3] ) / 255.0f;

            if (alpha == 0 ||
                (_ignoredWhite && (red+green+blue == 3)) ||
                (_ignoredBlack && (red+green+blue == 0))) {
                //要忽略的粒子
                continue;
            }

            AZParticle *particle = [AZParticle new];
            particle.color = [UIColor colorWithRed:red green:green blue:blue alpha:alpha];
            particle.point = CGPointMake(x, y);
            if (_customColor) {
                particle.customColor = _customColor;
            }
            if (_randomPointRange > 0) {
                particle.randomPointRange = _randomPointRange;
            }

            [result addObject:particle];
        }
    }
    free(rawData);
    return result;
}



然后通过 CADisplayLink 累加一个变量再触发自己重绘,其中重绘实现如下:

-(void)drawInContext:(CGContextRef)ctx {
    int count = 0;
    for (AZParticle *particle in _particleArray) {
        if (particle.delayTime > _animTime) {
            continue;
        }

        CGFloat curTime = _animTime - particle.delayTime;
        if (curTime >= _animDuration + particle.delayDuration) { //到达了目的地的粒子原地等待下没到达的粒子
            curTime =  _animDuration + particle.delayDuration;
            count ++;
        }

        CGFloat curX = [self easeInOutQuad:curTime begin:_beginPoint.x end:particle.point.x + self.bounds.size.width/2-CGImageGetWidth(_image.CGImage)/2 duration:_animDuration + particle.delayDuration];
        CGFloat curY = [self easeInOutQuad:curTime begin:_beginPoint.y end:particle.point.y + self.bounds.size.height/2 - CGImageGetHeight(_image.CGImage)/2 duration:_animDuration + particle.delayDuration];
        CGContextAddEllipseInRect(ctx, CGRectMake(curX , curY , 1, 1));
        const CGFloat* components = CGColorGetComponents(particle.color.CGColor);
        CGContextSetRGBFillColor(ctx, components[0], components[1], components[2], components[3]);
        CGContextFillPath(ctx);
    }
    if (count == _particleArray.count) {
        [self reset];
        if (_azDelegate && [_azDelegate respondsToSelector:@selector(onAnimEnd)]) {
            [_azDelegate onAnimEnd];
        }
    }
}



iPhone6 上试了下性能,还是比较差的,动画中 CPU 基本在 90% 以上,但是大家可以根据里面的核心实现,做一下性能优化,定制下自己想要的动画效果。

可以把刷新频率稍微降低一点
可以把图片切割成4个像素块、16个像素块、或者一些很小的块状图片
可以自定义动画路径,做成一些有想象力的曲线路径
可以封装成 UIView 的 category 方法,更加方便使用
……

例如可以稍微改造一下实现下面的效果:

底部投射

本文具体代码: https://github.com/BenXia/CoolAnimationsDemo

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值