我會將閱讀文章的人視作對 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)




沒有留言:
張貼留言