2

私は現在 iPhone ゲームに取り組んでおり、その場でアニメーションを作成する必要があります。アニメーションは複数の画像に基づいており、画像の組み合わせの範囲が広すぎて、すべてのシーケンスを事前に作成することは不可能であるため、状況が変化するたびに一連の画像を再計算できるようにしたいと考えています。

この関数は、一連の画像を作成し、アニメーション シーケンスとして使用します。次の 2 点についてサポートが必要です。

  1. 見つけるのに苦労している大きなメモリリークがいくつかあります - それらを見つけるのに助けが必要です
  2. 私はiPhoneに慣れていないので、もっと良い方法があるかどうか知りたいのですが、それを書く方法についてより良い提案があれば、共有してください...

コード:

(void) updateImages:(int) smallPicID
{
    CGRect smallPicRect;
    smallPicRect.size = CGSizeMake(25.0f, 25.0f);

    //TODO: add smallPic location for every image. Currently the values only match the first image...
    static const CGPoint smallPicLocation[11][SMALLPIC_LOCATION_COUNT] = 
    {
        { {126.0f, 153.0f},{105.0f, 176.0f}, {115.0f, 205.0f}, {145.0f, 211.0f}, {166.0f, 188.0f}, {156.0f, 159.0f} },
        { {183.0f, 91.0f}, {201.0f, 97.0f}, {205.0f, 115.0f}, {191.0f, 127.0f}, {173.0f, 122.0f}, {169.0f, 124.0f} },
        { {183.0f, 91.0f}, {201.0f, 97.0f}, {205.0f, 115.0f}, {191.0f, 127.0f}, {173.0f, 122.0f}, {169.0f, 124.0f} },
        { {183.0f, 91.0f}, {201.0f, 97.0f}, {205.0f, 115.0f}, {191.0f, 127.0f}, {173.0f, 122.0f}, {169.0f, 124.0f} },
        { {183.0f, 91.0f}, {201.0f, 97.0f}, {205.0f, 115.0f}, {191.0f, 127.0f}, {173.0f, 122.0f}, {169.0f, 124.0f} },
        { {183.0f, 91.0f}, {201.0f, 97.0f}, {205.0f, 115.0f}, {191.0f, 127.0f}, {173.0f, 122.0f}, {169.0f, 124.0f} },
        { {183.0f, 91.0f}, {201.0f, 97.0f}, {205.0f, 115.0f}, {191.0f, 127.0f}, {173.0f, 122.0f}, {169.0f, 124.0f} },
        { {183.0f, 91.0f}, {201.0f, 97.0f}, {205.0f, 115.0f}, {191.0f, 127.0f}, {173.0f, 122.0f}, {169.0f, 124.0f} },
        { {183.0f, 91.0f}, {201.0f, 97.0f}, {205.0f, 115.0f}, {191.0f, 127.0f}, {173.0f, 122.0f}, {169.0f, 124.0f} },
        { {183.0f, 91.0f}, {201.0f, 97.0f}, {205.0f, 115.0f}, {191.0f, 127.0f}, {173.0f, 122.0f}, {169.0f, 124.0f} },
        { {183.0f, 91.0f}, {201.0f, 97.0f}, {205.0f, 115.0f}, {191.0f, 127.0f}, {173.0f, 122.0f}, {169.0f, 124.0f} }
    };

    for(int i = 0; i < self.m_finalImages.count; ++i)
    {
        // start with base image
        UIImage * baseImg = [self.m_finalImagesEmpty objectAtIndex:i];
        CGImageRef baseImgCtx = baseImg.CGImage;

        // Create the bitmap context that matches the baseImg parameters
        CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
        CGContextRef newImgCtx = CGBitmapContextCreate(NULL, 
                                                       CGImageGetWidth(baseImgCtx), 
                                                       CGImageGetHeight(baseImgCtx), 
                                                       8, 0, colorSpace, 
                                                       (kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst));
        CGColorSpaceRelease(colorSpace); 

        if (newImgCtx == NULL) 
        { 
            // error creating context
            assert(0);
            return;
        }

        // Get empty drum image width, height.
        size_t w = CGImageGetWidth(baseImgCtx);
        size_t h = CGImageGetHeight(baseImgCtx);
        CGRect rect = {{0,0},{w,h}}; 

        // Draw the image to the bitmap context.
        // newImgCtx now contains the full empty drum image.
        CGContextDrawImage(newImgCtx, rect, baseImgCtx); 

        CGContextSaveGState(newImgCtx);
        // translate & scale because of origin difference between UIKit and CG
        CGContextTranslateCTM(newImgCtx, 0, h);
        CGContextScaleCTM(newImgCtx, 1, -1);

        int startLocation = 0;
        int endLocation = SMALLPIC_LOCATION_COUNT;

        // for each location
        for(int j = startLocation; j < endLocation; j++)
        {
            // if its empty, nothing to do, move to next bullet
            if (m_locationStatus[j] == CY_EMPTY)
                continue;

            UIImage * srcImg;
            switch (m_locationStatus[j]) 
            {
                case CY_FULL: srcImg = [self.m_finalImagesLoaded objectAtIndex:i];  break;
                case CY_USED:  srcImg = [self.m_finalImagesSpent objectAtIndex:i];  break;
            }

            // create small image containing only the smallpic from the src img
            smallPicRect.origin = smallPicLocation[i][j];
            CGImageRef smallpicCGImg = CGImageCreateWithImageInRect(srcImg.CGImage, smallPicRect);

            // draw the smallpic into the new context
            CGContextDrawImage(newImgCtx, smallPicRect, smallpicCGImg);         

            CGImageRelease(smallpicCGImg);
        }

        CGContextRestoreGState(newImgCtx);

        // update the image from the context
        UIImage *baseImg = [self.m_finalImages objectAtIndex:i];
        CGImageRef imgref = CGBitmapContextCreateImage(newImgCtx);
        //[baseImg release];
        [baseImg initWithCGImage:imgref];

        CGContextRelease(newImgCtx);
    }
}
4

1 に答える 1

2

私が最初に飛び出すのは、CGBitmapContextCreateImage() を使用して最後の近くで imgref を作成することですが、一致する CGImageRelease() はありません。baseImg initWithCGImage: メッセージはメモリを消費するだけです。「コンテキストから画像を更新する」で始まるセクションを次のように置き換えたいと思います。

CGImageRef imgref = CGBitmapContextCreateImage(newImgCtx);
UIImage *replacmentBaseImg = [[UIImage alloc] initWithCGImage:imgref];
CGImageRelease(imgref);

[self.m_finalImages replaceObjectAtIndex:i withObject:replacementBaseImg];
[replacementBaseImg release];

CGContextRelease(newImgCtx);

これは、m_finalImages が NSMutableArray であり、その配列に挿入された他の画像を適切に解放して、それらを置き換えると割り当てが解除されることを前提としています。

より大きな構造上の注意として、小さなサブイメージを個々の CALayer に描画し、それらのレイヤーをさまざまな場所で画面の内外にスワップして、アニメーションを完成させることを検討したい場合があります。Quartz 描画はコストが高く、CALayer は GPU にテクスチャとして保存されたキャッシュ イメージです。他の人々は、CALayers を使用してこれらのスプライト ベースのアニメーションを実行し、印象的なパフォーマンスを達成しました。

于 2009-05-21T13:13:39.867 に答える