2009年11月27日 星期五

OpenGL 下的「退地」方案

經過幾天的吸星大法,東抄抄西抄抄,我已經成功在 OpenGL ES 秀出平面圖,並建立好自己的繪圖引擎。由於 OpenGL 沒有繪畫文字的功能,又不能使用 UILabel,唯有將文字變成貼圖秀出。由於文字多為單色,所以用 8 Bits 灰階就夠,再加上 Blending 便能轉為其他顔色!OpenGL 在我的 iPhone Orginal 上也跑得十分之快,真是簡單好用!

2009年11月26日 星期四

取得 iPhone OS 版本的方法

NSLog(@"Current system version = %@", [[UIDevice currentDevice] systemVersion]);

2009年11月25日 星期三

Quartz vs OpenGL

在開始製作移植 RPG 遊戲到 iPhone 之前,我曾經在網上尋求 Quartz 及 OpenGL 在 2D 效能上,及學習上哪個比較合適的答案。籍以決定 RPG 項目使用哪個技術。得到的結果是,網友大多宣稱在 2D 繪畫速度上 Quartz 跟 OpenGL 是差不多。亦由於我比較熟悉 Quartz 技術,因此決定做用這套技術。

除著開發的時間增加,繪圖的數目也提升了不少,一個畫面大約需要繪畫 400 幅 24x24 大小的圖片,當中包括透底處理、旋轉發倒轉處理。導致 Quartz 出現速度上的瓶頸。經過優化之後,在 iPhone Original 上繪畫的所需時間需要 0.4 秒左右,亦即是說一秒最多只有三幀;實在是不能接受的龜速。

於是我在 OpenGL 上做了一個測試,在 iPhone Original 上繪畫 400 幅 24x24 像素及帶有透明色的圖片,當中沒有做任個旋轉處理。出來的結果是平均時間 0.0160 秒,亦即是說大約為 62 fps。相信以這個速度,在加入遊戲邏輯、旋轉、網路通訊等處理後,保持 20 fps 是沒有問題。

由見及此,要製作繪畫次數不多的應用程式時,Quartz 是比教簡單易學、是比較好的選擇。但要很作較為大型及繪畫次數較多的應用程式時,Quartz 就不能勝任,反而 OpenGL 才是首選。

2009年11月24日 星期二

取得 iPhone Serial No. 的方法

NSLog(@"Serial: %@", [[UIDevice currentDevice] uniqueIdentifier]);

2009年11月20日 星期五

自家 App 製成 IPA 方法

更新:這個方法只適用於使用 Installous 安裝,利用 iTunes 安裝的打包方法,請參考本人較新的文章。

自從 Apple 把 Provisioning Profile 的期限改為三個月之後,久不久我便需要將 AppSales Mobile 的 Provisioning Profile 更新。於是我創作出解決方法,把 AppSales Mobile 變成自家製 IPA 檔案。方法如下:

1)建立 Payload 資料夾
2)把編譯好的 AppSales .app 拷到 Payload 內
3)把 Payload 壓縮成 ZIP 檔
4)把 Payload.zip 改名為 AppSales.ipa
5)把 AppSales.ipa 拷到 iPhone 裡的 /private/var/mobile/Library/Downloads
6)運行 Installous 安裝 AppSales.ipa

2009年11月19日 星期四

AppSales Mobile for 3.0

由昨天起,AppSales Mobile 不能從 iTunes Connect 下載銷售情報,是因為 iTunes Connect 的頁面更改了。要解決這個問題,可以到 http://github.com/omz/AppSales-Mobile 下載更新版 AppSales。這個版本在 3.0 能正常運作。

2009年11月10日 星期二

優化 Sprite 部份

今天嘗試把繪畫 Sprite 的部份優化,把重覆的部份移走,可惜失敗了。

把以下代碼:
spriteLayerData = malloc(SCREEN_WIDTH*SCREEN_HEIGHT*4);

colorSpace = CGColorSpaceCreateDeviceRGB();
spriteLayerContext = CGBitmapContextCreate(spriteLayerData, SCREEN_WIDTH, SCREEN_HEIGHT, 8, (SCREEN_WIDTH<<2), colorSpace, kCGImageAlphaPremultipliedFirst);
myRef = CGBitmapContextCreateImage(spriteLayerContext);

// Draw sprite to context
// ....
// ....

outputImage = [UIImage imageWithCGImage:myRef];
spriteLayer = [[UIImageView alloc] initWithImage:outputImage];
[self.view addSubview:spriteLayer];

CGImageRelease(myRef);
CGContextRelease(spriteLayerContext);
CGColorSpaceRelease(colorSpace);

換成:
spriteLayerData = malloc(SCREEN_WIDTH*SCREEN_HEIGHT*4);

colorSpace = CGColorSpaceCreateDeviceRGB();
spriteLayerContext = CGBitmapContextCreate(spriteLayerData, SCREEN_WIDTH, SCREEN_HEIGHT, 8, (SCREEN_WIDTH<<2), colorSpace, kCGImageAlphaPremultipliedFirst);
myRef = CGBitmapContextCreateImage(spriteLayerContext);

outputImage = [UIImage imageWithCGImage:myRef];
spriteLayer = [[UIImageView alloc] initWithImage:outputImage];
[self.view addSubview:spriteLayer];
memset(spriteLayerData, 0, (SCREEN_WIDTH*SCREEN_HEIGHT*4));

// Draw sprite to context
// ....
// ....
CGImageRelease(myRef);
CGContextRelease(spriteLayerContext);
CGColorSpaceRelease(colorSpace);

2009年11月6日 星期五

一個挑戰!

最近在處理圖片時出現了一個頗為嚴重的瓶頸。由於一個角色是由多個部份的圖片合成出來,在實時繪畫上,少不免會花上一點時間;而在我的 iPhone 2G 實機上測試出來的結果,才是令我頭痛的主要原因:

以下的結果是以「秒」為單位:
測試一:
》一張全畫面的 UIImageView 背景圖
》一張 UIImageView 標誌圖
》一個 UILabel 文字
所需時間:0.0003~0.0005 秒

測試二:
》一張全畫面的 UIImageView 背景圖
》一張 UIImageView 標誌圖
》一個 UILabel 文字
》建立一個及取消一個 Device Context(每幀)
所需時間:0.0016~0.0037 秒

測試三:
》一張全畫面的 UIImageView 背景圖
》一張 UIImageView 標誌圖
》一個 UILabel 文字
》建立一個及取消一個 Device Context(每幀)
》在 Device Context 上繪製圖片(每幀)
所需時間:0.7060~1.0885 秒

足足需要接近一秒的時間才完成!是一個極低的 Frame Rate。下一步要解決的是把這個部份加快至少 30 倍,確實是一個挑戰!

2009年11月3日 星期二

@selector in NSArray

除了之前學習到的 Class in NSArray 外,今日嘗試製作 Selector in NSArray。方法同樣很簡單:

- (void)runAllTest:(id)sender {
NSArray *menuList = [[NSArray alloc] initWithObjects:
@"test01:",
@"test02:",
@"test03:",
@"test04:",
nil];

NSString *currentTestName = [menuList objectAtIndex:currentTest];
[self addLog:[NSString stringWithFormat:@"[%@]...", currentTestName]];

// Get the selector of next test
SEL currentSelector = NSSelectorFromString(currentTestName);
int assertResult = (int)[self performSelector:currentSelector];

if (assertResult == 0) {[self addLog:@"OK\n"];}
else {[self addLog:[NSString stringWithFormat:@"ERROR %d\n", assertResult]];}

// Test complete
currentTest++;

// Stop if all tests have been ran
if (currentTest >= [menuList count]) {
[self stopTest:sender];
currentTest = 0;
return;
}

// Set timer for next test
timer = [NSTimer scheduledTimerWithTimeInterval:(0.5f) target:self selector:@selector(runAllTest:) userInfo:nil repeats:NO];
}

2009年11月1日 星期日