我會將閱讀文章的人視作對 c / obj-c 以及 iOS有一定的認識,因此在obj-c/c的一些使用內容將不會有太多的解釋。另外會以AS3為對照的語言,作一些相關的引用跟對照。
此篇將延續上兩篇使用的專案
動態製作的原理,是依照連環圖動畫來製作(filpnook animation),使用一張一張圖讓他去播放(可以參考前面連結的影片),在瞭解動態如何製作之後,我們假設現在要製作一個數字跳動的動態,我希望能已30fps重複播放六張圖片,但如果這樣製作六張分開的圖片讓程式載入,不只在檔案上會增加很多圖檔,程式也必需要一直載入圖片來播放,這樣管理起又變得麻煩。 所以我們將會把一個物件(人物、角色...)的動態坐在一張檔案裡,圖片製作的方式如下:
一個Row, 可以做一方向(狀態)的動態, 將物件所有的動態做成一張圖(atlas 地圖集),用來載入程式來動作。
接著我們建立一個新的Class,繼承 Sprite 命名為 AtlasSprite
AltasSprite.h:
#import "Sprite.h" @interface AtlasSprite : Sprite { UIImage *atlas;//地圖集 CGImageRef image;//Quartz 圖片格式 CGFloat atlasWidth;//寬 CGFloat atlasHeight;//高度 CGRect clipRect;//紀錄圖片位置 int rows;//地圖集有幾行 int columns;//幾欄 int frame;//用來紀錄播放動態的影格 } @property (retain, nonatomic) UIImage *atlas; @property (assign) CGFloat atlasWidth,atlasHeight; @property (assign) CGRect clipRect; @property (assign) CGImageRef image; @property (assign) int rows,columns,frame; - (id) initWithFile:(NSString*) fileName withRows:(int)atlasRows withColumns:(int) atlasColumns;在AltasSprite中,我們宣告了八個新參數以及一個Method,接著我們進行Class的實作,這邊我會將method分開解釋,程式碼方面會比較零散,請大家自己注意一下
AltasSprite.m
- (id) initWithFile:(NSString*) fileName withRows:(int)atlasRows withColumns:(int) atlasColumns; { self = [super init]; if(self) { atlas = [[UIImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:fileName ofType:nil] ]; CGImageRef img = [atlas CGImage]; image = img; int width0 = CGImageGetWidth(image); int height0 = CGImageGetHeight(image); if(atlasRows < 1) atlasRows = 1; if(atlasColumns < 1) atlasColumns = 1; atlasWidth = width0; atlasHeight = height0; rows = atlasRows; columns = atlasColumns; width = round(width0/columns); height = round(height0/rows); CGFloat w2 = width*0.5; CGFloat h2 = height*0.5; clipRect = CGRectMake(-width*0.5, -height*0.5, width, height); frame = 0; } return self; }21行highlight的部份,將我們原點轉移到中心點, 這就是之後我們呈現圖案的範圍大小
接著我們覆寫drawBody Method
-(void) drawBody:(CGContextRef)context { int r0 = floor(frame/columns); int c0 = frame-columns*r0; CGFloat w2 = width*0.5; CGFloat h2 = height*0.5; CGFloat u = c0*width+w2; CGFloat v = atlasHeight - (r0*height+h2); CGContextBeginPath(context); CGContextAddRect(context, clipRect); CGContextClip(context); CGContextDrawImage(context, CGRectMake(-u, -v, atlasWidth, atlasHeight), image); }在3-4行程式碼的地方我們先求出我們要對應的row & column 接著運算出對應的在地圖集上的坐標,接著我們增加即將製作圖形的大小方塊,接著使用 CGContextDrawImage 的方式,在地圖集上將我們想呈現的出區塊畫出來(參考下圖)。
最後別忘了要釋放我們使用的圖片資源 AtlasSprite.m
-(void)dealloc { [atlas release]; CGImageRelease(image); [super dealloc]; }接著回到Quartz2DView進行修改:
//Quartz2Dview.h #import "Sprite.h" #import "AtlasSprite.h" @interface Quartz2DView : UIView { //Sprite *mySprite; AtlasSprite *atlasSprite; NSTimer *timer; int aframe; } -(void) dt:(NSTimer *) theTimer; @end //Quartz2DView.m - (id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { // Initialization code self.backgroundColor = [UIColor clearColor]; aframe = 0; atlasSprite = [[AtlasSprite alloc] initWithFile:@"sample.png" withRows:7 withColumns:7 ]; atlasSprite.x = 100; atlasSprite.y = 100; atlasSprite.frame = 1;//使呈現的圖案=01 } return self; } -(void) drawRect:(CGRect)rect { CGContextRef context = UIGraphicsGetCurrentContext(); CGContextSaveGState(context); CGAffineTransform t0 = CGContextGetCTM(context); t0 = CGAffineTransformInvert(t0); CGContextConcatCTM(context, t0); [atlasSprite updateBox]; [atlasSprite draw:context]; CGContextRestoreGState(context); }執行後的結果如下圖:
到這邊整個Class已經完成了,接下來要做的就是讓動態可以跑起來,我們建立一個 NSTimer 來處理動態的動作
- (id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { // Initialization code self.backgroundColor = [UIColor clearColor]; aframe = 0; atlasSprite = [[AtlasSprite alloc] initWithFile:@"sample.png" withRows:7 withColumns:7 ]; atlasSprite.x = 100; atlasSprite.y = 100; //atlasSprite.frame = 1;//使呈現的圖案=01 timer = [NSTimer scheduledTimerWithTimeInterval:1/30.0 target:self selector:@selector(dt:) userInfo:nil ]; } return self; } -(void) dt:(NSTimer *) theTimer { aframe+1 < atlasSprite.columns ? ++aframe : (aframe=0); atlasSprite.frame = aframe; [self setNeedsDisplay]; }執行出現的話面就不在提供了,畫面的紅色區塊將會00 ~ 06之間重複播放。
那麼,這篇文章到這邊也就結束了,可能大家對於AltasSprite.m 的 drawBody會有較多的疑問, 這邊牽扯到了一些數學計算,讀起來可能會比較不容易瞭解,所以附上了兩個圖片來讓大家理解。
總算是打完這篇了,這篇的文字敘述越來越少了,大多數的內容也都是使用程式碼和圖片來帶過 囧rz ..(變懶了);自己最近做練習,其實也是跌跌撞撞,debug花了2hrs才發現是使用到了method不是當前需要的,其實程式碼根本沒有錯誤,只能希望自己盡量小心不要再犯一樣的錯誤;最後在這邊希望這篇也能幫助到大家,如果內容有任何錯誤或者是指教,也請不要吝嗇,謝謝。
參考資料:
iOS Developer Library CGContext Reference
iOS Developer Library CGImage Reference
使用單張影像來製作flipbook動畫效果
iOS SDK Tutorial: Flip Book Style Animation, part 1 of 2
iOS SDK Tutorial: Flip Book Style Animation, part 2 of 2
範例下載: Sample3.zip
相關文章:
iOS SDK 認識 Quartz 2D(0)
iOS SDK 認識 Quartz 2D(1)
沒有留言:
張貼留言