2010年11月18日 星期四

iPhone 開發筆記18: cocos2d MultipleTouch

A. 新增 cocos2d Application Project: boardGame5

B. HelloWorldScene.h
// When you import this file, you import all the cocos2d classes
#import "cocos2d.h"

// HelloWorld Layer                 //@add
@interface HelloWorld : CCLayer <CCTargetedTouchDelegate>

// returns a Scene that contains the HelloWorld as the only child
+(id) scene;

@end

-----------------------------------------------------------------------------------------------

C. boardGame5AppDelegate.m

- (void) applicationDidFinishLaunching:(UIApplication*)application
{
    CC_DIRECTOR_INIT();
   
    //@add
    // Init the window
    window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
   
    //@add
    [window setUserInteractionEnabled:YES]; 
    [window setMultipleTouchEnabled:YES];
    ....
}

-----------------------------------------------------------------------------------------------

D. HelloWorldScene.m

// on "init" you need to initialize your instance
-(id) init
{
    // always call "super" init
    // Apple recommends to re-assign "self" with the "super" return value
    if( (self=[super init] )) {
       
        //@add
        self.isTouchEnabled = YES;  
        // @add
        [[CCTouchDispatcher sharedDispatcher]
         addTargetedDelegate:self priority:0 swallowsTouches:YES];
    ....
    }
    return self;
}


// @add
-(BOOL) ccTouchBegan:(UITouch*)touch withEvent:(UIEvent*)event
{   
    CGPoint touchLocation=[touch locationInView:[touch view]];
    touchLocation=[[CCDirector sharedDirector] convertToGL:touchLocation];
    CGPoint nodePosition = [self convertToNodeSpace: touchLocation];
   
    int t_x = nodePosition.x;
    int t_y = nodePosition.y;    

    ....
   
    return YES;
}

2010年11月17日 星期三

iPhone 開發筆記17: cocos2d 圖片動畫效果

A. 新增 cocos2d Application Project.

B. 在 HelloWorldScene.m:
-(id) init
{
    // always call "super" init
    // Apple recommends to re-assign "self" with the "super" return value
    if( (self=[super init] )) {
        ....
        // 從左上角往右下角切割圖檔
        //CCSprite *sprite = [CCSprite spriteWithFile:@"Icon.png" rect:CGRectMake(20, 20, 57, 57)];

        CCSprite *sprite = [CCSprite spriteWithFile:@"Icon.png"]; // source size
        sprite.position = ccp(240, 50);
   
        /* 動畫效果: case01 -> normal */
        id action =
        // (1). CCJumpTo: 跳躍至絕對座標
        // [CCJumpTo actionWithDuration:2 position:ccp(300,0) height:50 jumps:4]; // -> 300, 0

        // (2). CCJumpBy: 跳躍至相對座標(以原始座標累加距離的跳躍)
        // [CCJumpBy actionWithDuration:2 position:ccp(300,0) height:50 jumps:4]; // -> 540, 50

        // (3). CCRotateTo: 旋轉
        // [CCRotateTo actionWithDuration:2 angle:180];
       
        // (4). 淡入
        // [CCFadeIn actionWithDuration:2];
       
        // (5). 淡出
        // [CCFadeOut actionWithDuration:2];
       
        // (6). 移至絕對座標
        // [CCMoveTo actionWithDuration:2 position: ccp(100, 100)];
       
        // (7). 移至相對座標
        // [CCMoveBy actionWithDuration:2 position: ccp(100, 100)]; // 340, 150

        // 混合動作
        // (8). CCSequence: one by one (連續動作)
        [CCSequence actions:
        // [CCRotateTo actionWithDuration:2 angle:180], // ---> error with reverse happend?
        [CCRotateBy actionWithDuration:2 angle:180],
        [CCJumpBy actionWithDuration:2 position:ccp(300,0) height:50 jumps:4],
        [CCFadeOut actionWithDuration:2],
        [CCCallFunc actionWithTarget:self selector:@selector(callback1)],
        nil];

        // 混合動作
        // (9). CCSpawn: do it the sametime (同時動作)
        /*
         [CCSpawn actions:
         [CCRotateTo actionWithDuration:2 angle:180], // ---> error with reverse happend?
         [CCRotateBy actionWithDuration:2 angle:180],
         [CCJumpBy actionWithDuration:2 position:ccp(300,0) height:50 jumps:4],
         [CCFadeOut actionWithDuration:2],
         [CCCallFunc actionWithTarget:self selector:@selector(callback1)],
         nil];
         */

        /* 動畫效果: case02 -> repeat */
        // (10). CCRepeatForever: 無限重複執行
        // CCRepeatForever *repeat = [CCRepeatForever actionWithAction:action];
       
        // (11). CCRepeat: 重複執行
        // CCRepeat *repeat = [CCRepeat actionWithAction:action times:2];

       
/* 動畫效果: case03 -> reverse */
        // (12). reverse: 反向執行
        // id t_reverse = [CCSequence actions:action, [action reverse], nil];

        // runAction
        // case 1: for normal
        [sprite runAction:action];
       
        // case 2: for repeat
        // [sprite runAction:repeat];
       
        // case 3: for reverse
        // [sprite runAction:t_reverse];

        [self addChild: sprite];
    }
    return self;
}


- (void) callback1
{
    CCLabel *labelEnd = [CCLabel labelWithString:@"Game Over" fontName:@"Marker Felt" fontSize:64];
   
    CGSize size = [[CCDirector sharedDirector] winSize];
   
    // position the label on the center of the screen
    labelEnd.position = ccp( size.width /2 , size.height/2 - 100 );
   
    [self addChild: labelEnd];
}

iPhone 開發筆記16: cocos2d 安裝與移除

A. cocos2d 官網: http://www.cocos2d-iphone.org/

B. 下載穩定版本(Stable version): http://www.cocos2d-iphone.org/download

C. 安裝方式:
   1. 解壓縮下載的檔案: cocos2d-iphone-0.99.4.tar.gz
   2. 在 Terminal 下, 到解壓縮目錄內執行:
      $ cd cocos2d-iphone-0.99.4
      $ sudo ./install-templates.sh
   3. 可以看到以下的安裝訊息:
      Installing cocos2d template:
      /Library/Application Support/Developer/Shared/Xcode/Project Templates/cocos2d 0.99.4/cocos2d Application/

      Installing cocos2d + box2d template:
      /Library/Application Support/Developer/Shared/Xcode/Project Templates/cocos2d 0.99.4/cocos2d Box2d Application/

      Installing cocos2d + chipmunk template:
      /Library/Application Support/Developer/Shared/Xcode/Project Templates/cocos2d 0.99.4/cocos2d Chipmunk Application/

      creating destination directory:
      /Library/Application Support/Developer/Shared/Xcode/File Templates/cocos2d 0.99.4/

D. 移除方式:
   刪除: C 安裝後所產生的目錄即可.

iPhone 開發筆記15: 單點觸控與多點觸控

// 單點觸控
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
   
    UITouch *touch = [[event allTouches] anyObject];
    CGPoint location = [touch locationInView:touch.view];
    // location.x
    // location.y
}

----------------------------------------------------------------------------------------------------

// 多點觸控
A. 新增一個 Window-based Application Project: multiTouch

B. 新增繼承 UIView 的 Class: TouchView
----------------------------------------------------------------------------------------------------

C. multiTouchAppDelegate.h
#import <UIKit/UIKit.h>
//@add
#import "TouchView.h"

@interface multiTouchAppDelegate : NSObject <UIApplicationDelegate> {
    UIWindow *window;
}

@property (nonatomic, retain) IBOutlet UIWindow *window;

@end

----------------------------------------------------------------------------------------------------

D. multiTouchAppDelegate.m

#import "multiTouchAppDelegate.h"

@implementation multiTouchAppDelegate

@synthesize window;

#pragma mark -
#pragma mark Application lifecycle

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {   
   
    // Override point for customization after application launch.
    //@add
    [application setStatusBarStyle:UIStatusBarStyleBlackOpaque]; // 改變狀態列背景

    TouchView *touchView = [[[TouchView alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];

    [window addSubview:touchView];   
   
    [window makeKeyAndVisible];
   
    return YES;
}

----------------------------------------------------------------------------------------------------

E. TouchView.h

#import <UIKit/UIKit.h>

@interface TouchView : UIView {
    //@add
    CGPoint touch1;
    CGPoint touch2;
    double unitDistance;
    double initialDistance;
}

//@add
- (double)getDistance:(CGPoint)fromPoint toPoint:(CGPoint)otherPoint;

@end

----------------------------------------------------------------------------------------------------
F. TouchView.m

#import "TouchView.h"

@implementation TouchView

- (id)initWithFrame:(CGRect)frame {
    if ((self = [super initWithFrame:frame])) {
        // Initialization code
        //@add
        [self setMultipleTouchEnabled:YES];
    }
    return self;
}

- (void) touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event {
    NSArray *allTouches = [touches allObjects];
    int count = [allTouches count];
    if (count > 0)
        touch1 = [[allTouches objectAtIndex:0] locationInView:self];
    if (count > 1)
    {
        touch2 = [[allTouches objectAtIndex:1] locationInView:self];
        initialDistance = [self getDistance:touch1 toPoint:touch2];
        NSLog(@"initialDistance:%f",initialDistance);
    }
    [self setNeedsDisplay]; // 強制更新畫面: invoke -> drawRect
}

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
   
    NSArray *allTouches = [touches allObjects];
    int count = [allTouches count];
    if (count > 0)
        touch1 = [[allTouches objectAtIndex:0] locationInView:self];
    if (count > 1)
    {
        touch2 = [[allTouches objectAtIndex:1] locationInView:self];
        unitDistance = [self getDistance:touch1 toPoint:touch2];
        NSLog(@"unitDistance:%f",unitDistance);
    }
    [self setNeedsDisplay];
// 強制更新畫面: invoke -> drawRect
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {

    if (initialDistance > unitDistance) {
        // 縮小
        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"multiTouch" message:@"Your touch is close to eachother" delegate:nil cancelButtonTitle:@"Yep, I did." otherButtonTitles:nil];

 
        [alert show];
        [alert release];   
    }
    else if (initialDistance < unitDistance){
        // 放大
        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"multiTouch" message:@"Your touch is distant from eachother" delegate:nil cancelButtonTitle:@"Yep, I did." otherButtonTitles:nil];

 
        [alert show];
        [alert release];
    }
}


// 二點距離: 平方相加, 開根號
- (double)getDistance:(CGPoint)fromPoint toPoint:(CGPoint)otherPoint
{
    double deltaX = otherPoint.x - fromPoint.x;
    double deltaY = otherPoint.y - fromPoint.y;
    return sqrt(pow(deltaX, 2) + pow(deltaY, 2));
}

// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect {
    // Drawing code
    //@add Line
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextSetLineWidth(context, 2);
    CGContextSetStrokeColorWithColor(context, [UIColor blueColor].CGColor);
    CGContextMoveToPoint(context,touch1.x,touch1.y);
    CGContextAddLineToPoint(context,touch2.x,touch2.y);
    CGContextStrokePath(context);
}

- (void)dealloc {
    [super dealloc];
}

@end

2010年11月11日 星期四

iPhone 開發筆記14: 背景音樂

A. 在專案的 "Frameworks" 新增以下的 framework: CoreAudio.frameworkAudioToolbox.framework .

B. 在專案的 "Groups & Files" 新增一個 Group: "Audio", 並新增以下的檔案: GBMusicTrack.hGBMusicTrack.m

//
//  GBMusicTrack.h
//  GameBase
//
//  Created by Jake Peterson (AnotherJake) on 7/6/08.
//  Copyright 2008 Jake Peterson. All rights reserved.
//

//#import <Cocoa/Cocoa.h>
#import <AudioToolbox/AudioQueue.h>
#import <AudioToolbox/AudioFile.h>

#define NUM_QUEUE_BUFFERS    3

@interface GBMusicTrack : NSObject
{
    AudioFileID                       audioFile;
    AudioStreamBasicDescription     dataFormat;
    AudioQueueRef                   queue;
    UInt64                            packetIndex;
    UInt32                            numPacketsToRead;
    AudioStreamPacketDescription   *packetDescs;
    BOOL                             repeat;
    BOOL                             trackClosed;
    AudioQueueBufferRef            buffers[NUM_QUEUE_BUFFERS];
}

- (id)initWithPath:(NSString *)path;
- (void)setGain:(Float32)gain;
- (void)setRepeat:(BOOL)yn;
- (void)play;
- (void)pause;

// close is called automatically in GBMusicTrack's dealloc method, but it is recommended
// to call close first, so that the associated Audio Queue is released immediately, instead
// of having to wait for a possible autorelease, which may cause some conflict
- (void)close;

extern NSString    *GBMusicTrackFinishedPlayingNotification;

@end

------------------------------------------------------------------------------------------------------

//
//  GBMusicTrack.m
//  GameBase
//
//  Created by Jake Peterson (AnotherJake) on 7/6/08.
//  Copyright 2008 Jake Peterson. All rights reserved.
//

#import "GBMusicTrack.h"

static UInt32 gBufferSizeBytes = 0x10000; // 64k

NSString *GBMusicTrackFinishedPlayingNotification
= @"GBMusicTrackFinishedPlayingNotification";

@interface GBMusicTrack (InternalMethods)

static void BufferCallback(void *inUserData, AudioQueueRef inAQ, AudioQueueBufferRef buffer);
- (void)callbackForBuffer:(AudioQueueBufferRef)buffer;
- (UInt32)readPacketsIntoBuffer:(AudioQueueBufferRef)buffer;

@end

@implementation GBMusicTrack

#pragma mark -
#pragma mark GBMusicTrack

- (void)dealloc
{
    [self close];
    [super dealloc];
}

- (void)close
{
    // it is preferrable to call close first, before dealloc if there is a problem waiting for
    // an autorelease
    if (trackClosed)
        return;
    trackClosed = YES;
    AudioQueueStop(queue, YES);
    AudioQueueDispose(queue, YES);
    AudioFileClose(audioFile);
}

- (id)initWithPath:(NSString *)path
{
    UInt32        size, maxPacketSize;
    char        *cookie;
    int            i;
   
    if(!(self = [super init])) return nil;
    if (path == nil) return nil;
   
    // try to open up the file using the specified path
    if (noErr != AudioFileOpenURL((CFURLRef)[NSURL fileURLWithPath:path], 0x01, kAudioFileCAFType, &audioFile))
    {
        NSLog(@"GBMusicTrack Error - initWithPath: could not open audio file. Path given was: %@", path);
        return nil;
    }
   
    // get the data format of the file
    size = sizeof(dataFormat);
    AudioFileGetProperty(audioFile, kAudioFilePropertyDataFormat, &size, &dataFormat);
   
    // create a new playback queue using the specified data format and buffer callback
    AudioQueueNewOutput(&dataFormat, BufferCallback, self, nil, nil, 0, &queue);
   
    // calculate number of packets to read and allocate space for packet descriptions if needed
    if (dataFormat.mBytesPerPacket == 0 || dataFormat.mFramesPerPacket == 0)
    {
        // since we didn't get sizes to work with, then this must be VBR data (Variable BitRate), so
        // we'll have to ask Core Audio to give us a conservative estimate of the largest packet we are
        // likely to read with kAudioFilePropertyPacketSizeUpperBound
        size = sizeof(maxPacketSize);
        AudioFileGetProperty(audioFile, kAudioFilePropertyPacketSizeUpperBound, &size, &maxPacketSize);
        if (maxPacketSize > gBufferSizeBytes)
        {
            // hmm... well, we don't want to go over our buffer size, so we'll have to limit it I guess
            maxPacketSize = gBufferSizeBytes;
            NSLog(@"GBMusicTrack Warning - initWithPath: had to limit packet size requested for file path: %@", path);
        }
        numPacketsToRead = gBufferSizeBytes / maxPacketSize;
       
        // will need a packet description for each packet since this is VBR data, so allocate space accordingly
        packetDescs = malloc(sizeof(AudioStreamPacketDescription) * numPacketsToRead);
    }
    else
    {
        // for CBR data (Constant BitRate), we can simply fill each buffer with as many packets as will fit
        numPacketsToRead = gBufferSizeBytes / dataFormat.mBytesPerPacket;
       
        // don't need packet descriptsions for CBR data
        packetDescs = nil;
    }
   
    // see if file uses a magic cookie (a magic cookie is meta data which some formats use)
    AudioFileGetPropertyInfo(audioFile, kAudioFilePropertyMagicCookieData, &size, nil);
    if (size > 0)
    {
        // copy the cookie data from the file into the audio queue
        cookie = malloc(sizeof(char) * size);
        AudioFileGetProperty(audioFile, kAudioFilePropertyMagicCookieData, &size, cookie);
        AudioQueueSetProperty(queue, kAudioQueueProperty_MagicCookie, cookie, size);
        free(cookie);
    }
   
    // allocate and prime buffers with some data
    packetIndex = 0;
    for (i = 0; i < NUM_QUEUE_BUFFERS; i++)
    {
        AudioQueueAllocateBuffer(queue, gBufferSizeBytes, &buffers[i]);
        if ([self readPacketsIntoBuffer:buffers[i]] == 0)
        {
            // this might happen if the file was so short that it needed less buffers than we planned on using
            break;
        }
    }
    repeat = NO;
    trackClosed = NO;
    return self;
}

- (void)setGain:(Float32)gain
{
    AudioQueueSetParameter(queue, kAudioQueueParam_Volume, gain);
}

- (void)setRepeat:(BOOL)yn
{
    repeat = yn;
}

- (void)play
{
    AudioQueueStart(queue, nil);
}

- (void)pause
{
    AudioQueuePause(queue);
}

#pragma mark -
#pragma mark Callback

static void BufferCallback(void *inUserData, AudioQueueRef inAQ, AudioQueueBufferRef buffer)
{
    // redirect back to the class to handle it there instead, so we have direct access to the instance variables
    [(GBMusicTrack *)inUserData callbackForBuffer:buffer];
}

- (void)callbackForBuffer:(AudioQueueBufferRef)buffer
{
    if ([self readPacketsIntoBuffer:buffer] == 0)
    {
        // End Of File reached, so rewind and refill the buffer using the beginning of the file instead
        packetIndex = 0;
        [self readPacketsIntoBuffer:buffer];
       
        // if not repeating then we'll pause it so it's ready to play again immediately if needed
        if (!repeat)
        {
            AudioQueuePause(queue);
           
            // we're not in the main thread during this callback, so enqueue a message on the main thread to post notification
            // that we're done, or else the notification will have to be handled in this thread, making things more difficult
            [self performSelectorOnMainThread:@selector(postTrackFinishedPlayingNotification:) withObject:nil waitUntilDone:NO];
        }
    }
}

- (void)postTrackFinishedPlayingNotification:(id)object
{
    // if we're here then we're in the main thread as specified by the callback, so now we can post notification that
    // the track is done without the notification observer(s) having to worry about thread safety and autorelease pools
    [[NSNotificationCenter defaultCenter] postNotificationName:GBMusicTrackFinishedPlayingNotification object:self];
}

- (UInt32)readPacketsIntoBuffer:(AudioQueueBufferRef)buffer
{
    UInt32        numBytes, numPackets;
   
    // read packets into buffer from file
    numPackets = numPacketsToRead;
    AudioFileReadPackets(audioFile, NO, &numBytes, packetDescs, packetIndex, &numPackets, buffer->mAudioData);
    if (numPackets > 0)
    {
        // - End Of File has not been reached yet since we read some packets, so enqueue the buffer we just read into
        // the audio queue, to be played next
        // - (packetDescs ? numPackets : 0) means that if there are packet descriptions (which are used only for Variable
        // BitRate data (VBR)) we'll have to send one for each packet, otherwise zero
        buffer->mAudioDataByteSize = numBytes;
        AudioQueueEnqueueBuffer(queue, buffer, (packetDescs ? numPackets : 0), packetDescs);
       
        // move ahead to be ready for next time we need to read from the file
        packetIndex += numPackets;
    }
    return numPackets;
}

@end

------------------------------------------------------------------------------------------------------

C. 在 xxxViewController.m 檔:

   #import "GBMusicTrack.h"


D. 在 xxxViewController.m 檔, 修改 viewDidLoad():
- (void)viewDidLoad {
    [super viewDidLoad];
    ....
    //background music
    GBMusicTrack *song = [[GBMusicTrack alloc] initWithPath:[[NSBundle mainBundle] pathForResource:@"streetFighter" ofType:@"mp3"]];

    [song setRepeat:YES];
    [song play];
}

2010年11月10日 星期三

iPhone 開發筆記13: 單一圖片與動態切換圖片

// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
    [super viewDidLoad];
   
    // single image                                                                  // x, y, width, height
    UIImageView *singleImage = [[UIImageView alloc] initWithFrame:CGRectMake(100, 125, 150, 130)];

    singleImage.image = [UIImage imageNamed:@"1.png"];

    singleImage.contentMode = UIViewContentModeBottomLeft; // 置於 frame 的左下角

    singleImage.alpha = 0.5f; // 透明度


    [self.view addSubview:singleImage];
   
-----------------------------------------------------------------------------------------------------

    // dynamic images
    NSArray * imageArray  = [[NSArray alloc] initWithObjects:
                             [UIImage imageNamed:@"1.png"],
                             [UIImage imageNamed:@"2.png"],
                             [UIImage imageNamed:@"3.png"],
                             [UIImage imageNamed:@"4.png"],
                             [UIImage imageNamed:@"5.png"],
                             [UIImage imageNamed:@"6.png"],
                             [UIImage imageNamed:@"7.png"],
                             [UIImage imageNamed:@"8.png"],
                             [UIImage imageNamed:@"9.png"],
                             [UIImage imageNamed:@"10.png"],
                             [UIImage imageNamed:@"11.png"],
                             [UIImage imageNamed:@"12.png"],
                             nil];
                                                                              // x, y, width, height
    UIImageView *dynamicImages = [[UIImageView alloc] initWithFrame:CGRectMake(100, 125, 150, 130)];

    dynamicImages.animationImages = imageArray;

    dynamicImages.animationDuration = 1.0f;

    dynamicImages.contentMode = UIViewContentModeBottomLeft; // 置於 frame 的左下角
   
    [self.view addSubview:dynamicImages];
    [dynamicImages startAnimating];
}

iPhone 開發筆記12: accelerometer 加速計

A. 在 xxx project 的 .h 檔 Class 宣告裡, 新增協定: <UIAccelerometerDelegate>

B. 在 xxx project 的 .m 檔的 Class 定義裡:

// Constant for the number of times per second (Hertz) to acceleration.
#define kAccelerometerFrequency 50
....
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
    [super viewDidLoad];
....

    // Configure and start the accelerometer
    [[UIAccelerometer sharedAccelerometer] setUpdateInterval:(1.0 / kAccelerometerFrequency)];

    [[UIAccelerometer sharedAccelerometer] setDelegate:self]; // .h => : <UIAccelerometerDelegate>
}

// UIAccelerometerDelegate method, called when the device accelerates.
- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration
{
    CGRect greenFrame = racquet_green.frame;
    greenFrame.origin.x = greenFrame.origin.x + acceleration.x;
    racquet_green.frame = greenFrame;
    /*
     NSLog(@"accelerometer");
     NSLog(@"x:%f",acceleration.x); // -1 ~ 1
     NSLog(@"y:%f",acceleration.y); // -1 ~ 1
     NSLog(@"z:%f",acceleration.z);
     */
}

iPhone 開發筆記11: 橫向畫面設定

A. 新增一個 View-based Project.
B. 在 Resources 裡,  新增一個背景圖檔(ex: background.jpg).
C. 在 Interface Builder 的 View 裡, 新增一個 UIImageView, 並設定剛剛的背景圖檔.

------------------------------------------------------------------------------------------------------

D. 在 Interface Builder 裡, 點選 View , 在 View Attributes 的 Simulated User Interface Elements 下的 Orientation 選擇: Landscape (風景畫: 代表橫向).

------------------------------------------------------------------------------------------------------

E. 打開 xxx-info.plist 檔, 新增以下一組 Key 與 Value:
Key: Initial interface orientation
Value: Landscape(right home button)

------------------------------------------------------------------------------------------------------

F.在程式裡, 加上一段 code:

// Override to allow orientations other than the default portrait orientation.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
    // Return YES for supported orientations
    //return (interfaceOrientation == UIInterfaceOrientationPortrait);
    //@add
    return (interfaceOrientation == UIInterfaceOrientationLandscapeLeft);
}

iPhone 開發筆記10: 利用 UIWebView 讀取 PDF 檔案

A. 新增一個 View-based Project(ex: viewPDF).

B. 在 Resources 裡,  新增一個 PDF 檔(ex: top.pdf).

C. 在 Interface Builder 的 View 裡, 新增一個 UIWebView.

-----------------------------------------------------------------------------------------------------------------

D. 調整 viewPDFViewController.h 如下:
#import <UIKit/UIKit.h>

@interface viewPDFViewController : UIViewController {
    UIWebView *myUIWebView;

}

@property (nonatomic, retain) IBOutlet UIWebView *myUIWebView;

@end

-----------------------------------------------------------------------------------------------------------------

E. 調整 viewPDFViewController.m 如下:
#import "viewPDFViewController.h"

@implementation viewPDFViewController

@synthesize myUIWebView;

........

// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
    [super viewDidLoad];
   
    NSString *pdfPath = [[NSBundle mainBundle] pathForResource:@"toc" ofType:@"pdf"];

    NSURL *pdfURL = [NSURL fileURLWithPath:pdfPath];

    NSURLRequest *pdfRequest = [NSURLRequest requestWithURL:pdfURL];

    [myUIWebView loadRequest:pdfRequest];
}

- (void)viewDidUnload {
    // Release any retained subviews of the main view.
    // e.g. self.myOutlet = nil;
    self.myUIWebView = nil;
}

- (void)dealloc {
    [myUIWebView release];
   
    [super dealloc];
}

-----------------------------------------------------------------------------------------------------------------

F. 在 Interface Builder , 將 File's Owner 的 Outlets: myUIWebView 連結到 View 下的 UIWebView.

iPhone 開發筆記09: 小記

A. 在 iPhone 模擬器內, 使用者可以存放檔案的目錄位置:
lanli(使用者) > library(資源庫) > Application Support > iPhone Simulator > 4.1 > Applications > 05B3668E-9938-4220-BEC5-BBF27900992D (編碼的目錄) > Ducuments

2010年10月26日 星期二

iPhone 開發筆記08: Setting a Background Color for UIButton

參考來源:
Cocoa Is My Girlfriend » Fun With UIButtons and Core Animation Layers
http://www.cimgf.com/2010/01/28/fun-with-uibuttons-and-core-animation-layers/

步驟:
A. 在 Interface Builder 裡, 設定所使用的 UIButton 的 Attributes TypeCustom.
B. 在 Xcode 的 Resource 裡, 新增 QuartzCore framework, 並在 xxxViewController.h 檔中引入:
import <QuartzCore/QuartzCore.h>

UIButton *button1;
. . . .
@property (nonatomic, retain) IBOutlet UIButton *button1;


C. 在 xxxViewController.m 檔中的 - (void)viewDidLoad: 內加入以下的程式碼:
@synthesize button1;
. . . .
- (void)viewDidLoad {

    [[button1 layer] setCornerRadius:8.0f];
    [[button1 layer] setMasksToBounds:YES];
    [[button1 layer] setBorderWidth:1.0f];
   
    /* set "green border" on the layer passing it a CGColorRef. */
    [[button1 layer] setBorderColor:[[UIColor greenColor] CGColor]];
   
    /* set the background color */
    // Core Animation way
    //[[button1 layer] setBackgroundColor:[[UIColor redColor] CGColor]];

    // UIView way
    [button1 setBackgroundColor:[UIColor redColor]];

    [super viewDidLoad];

}

說明:
1. With this code the layer gets a corner radius of 8.0

2. and the -setMasksToBounds: tells the button's layer to mask any layer content that comes below it in the layer tree. This is necessary in order for the layer to mask off the rounded corners.

3. Finally, set the border width to 1.0 to display an outline around the button.

4. The default color for this border is black. You can change it to anything you like using -setBorderColor: on the layer passing it a CGColorRef (e.g. [[UIColor greenColor] CGColor] would give you a green border).

5. You can set the background color in Interface Builder or in code–whichever you prefer. There are two ways to do this in code. One using the layer and one using the UIView call to -setBackgroundColor.

The main difference between the two is that the layer works with a CGColorRef while the UIView works with a UIColor. It' s a subtle difference, but one that you should know.

2010年10月18日 星期一

iPod Touch 3G JailBreak 4.1.0

One man's poison is another man's pleasure....

1. 備份 ECID: 在 Mac OS X 下, 連結 iPod Touch 並且下載 Umbrella:
http://thefirmwareumbrella.blogspot.com/ 來執行.

2. 備份資料:
(1). 執行 Cydia 的 AptBackup (可用來備份 Cydia 安裝過的軟體清單)
(2). 執行 Cydia 的 AppBackup (備份你所下載的應用程式之存檔與設定)
a. 備份後, 需檢查 iPod Touch 上 /private/var/mobile/Library/Preferences/AppBackup 目錄下的所有檔案(含子目錄下的檔案) 日期是否為最新的. 如果不是的話, 必須利用 sftp 登入到 iPod Touch 裡, 並調整 /private/var/mobile/Library/Preferences/AppBackup 目錄下 檔案與目錄權限為 777 (chmod 777 *.*), 之後再備份一次並檢查日期.

b. 承上, 利用 sftp 把 iPod Touch 上 /private/var/mobile/Library/Preferences/AppBackup 目錄下的 backuptimes.plist 還有 tarballs 資料夾備份到電腦上.

(3). 使用 iTunes 同步並備份 iPod Touch 的資料.

3. Download iPod Touch Firmware : (在 5.(2) 中會用到)
http://www.felixbruns.de/iPod/firmware/
=> 在此使用的版本為: iPod touch 3G (4.1/8B117)

4. 將 iPod Touch 進入 DFU Mode:
(1). 開啟 iTunes 並將手上的 iPod Touch 連接至電腦.
(2). 開啓任何一個應用程式, 並強制關機(同時按著 "主目錄鍵" 及 "電源開關鍵"(稍先) 不放)
(3). 當 iPod Touch 重新啓動後, 放開 "電源開關鍵", 10 秒後, 再放開"主目錄鍵".
(4). 進入 DFU Mode 後及按回復之前, 主機將維持黑屏及不會顯示任何東西.

5. 使用 iTunes 回復 DFU Mode 的 iPod Touch:
(1). Mac 電腦: 按下鍵盤 Option 鍵, 並同時按下 iTunes 裏的回復按鈕.
(2). 彈出提示框後, 選取剛剛下載的 iPod Touch 3G 4.1 官方韌體, 並等侍 iTunes 回應.

6. 回復 iPod Touch 的備份資料並執行一次同步與 Umbrella.

7. GreenPosi0n
(1). 更新 iTunes 到 10.0.1
(2). 下載 GreenPois0n: http://www.greenpois0n.com/
=> 在此採用: Mac 的 gp_mac_rc3_2.zip
(3). 在 iPod Touch 連結 iTunes 下, 先將 iPod Touch 關機, 並且解壓縮 gp_mac_rc3_2.zip 成 greenpois0n.app
(4). 執行 greenpois0n.app, 按下 "jailbreak" , 並按照畫面提示的步驟操作:
a. Press and hold the sleep button (2 sec)
b. Continue holding sleep, press and hold home (10 sec)
c. Release sleep button, continue holding home (15 sec)

8. 執行 iPod Touch 上的 Loader 後便可安裝 Cydia.

9. Cydia 設定.
(1). Cydia 開啟後, 選擇 Developer (No Filters).
(2). 重開 Cydia, 若有軟件更新, 將彈出提示框, 選擇 Upgrade Essential, 再選擇 Confirm.
(3). 注意軟件更新時不要譲主機自動上鎖.
(4). 請再次開啟 Cydia, 按下 Change, 若有軟件更新, 選擇 Upgrade (), 再選擇 Confirm.

10. Cydia 安裝軟體.
(1). OpenSSH: 可在 Mac 上使用 sftp client 的軟體連入 iPod Touch 系統中.
(2). AptBackup: 備份你用Cydia安裝的軟體清單.
=> 安裝後, 可進入 Aptbackup 選擇 restore,來命令你的 Cydia 將你有安裝的軟體,一一的安裝回去.
(因為它檔案存放位置會隨著 iTunes 的備份,存回電腦.)

(3). AppBackup: 備份你所下載的應用程式之存檔與設定.
(4). AppSync for OS 4.1: 讓應用程式 (.ipa / .app) 可直接透過 iTunes 安裝.
a. 開啟 Cydia > MANAGE > SOURCES > EDIT > ADD
b. 輸入 http://cydia.hackulo.us/ > 按下 Add Source 按鈕 > 若彈出提示框, 選擇 Add Anyway 即可.
c. 完成 Source Update 後, 按下 Return To Cydia, 返回 Source, 再按下剛加入的 Sources, 選擇 AppSync for OS 4.1 安裝.
d. 安裝完成後, 請重新啟動主機.

(5). CyDelete: 可直接在桌面刪除從 Cydia 下載的軟體.
(6). USB Drive: 可當成 USB 硬碟來使用.
a. 新增安裝源: http://apt.dmytro.me/
b. 安裝 USB Drive 軟體.

(7). afc2add: 可讓應用軟體( iPhone Explorer / DiskAid )瀏覽到 iPhone 的根目錄.

11. 更改 iPod Touch 的 root 密碼.
(1). 確定已用 Cydia 安裝了 OpenSSH.
(2). 共享 Mac Book Pro 的網路給 iPod Touch:
=> Mac OS X > 系統偏好設定 > 共享 > Internet 共享
(都設定好時要勾選, 此時 Mac 本身可能無法上網)
> 共享來源: 乙太網路; 對使用以下傳輸埠的電腦: AirPort

(3). iPod Touch > 設定 > Wi-Fi > 選擇網路: SnowLeopard (同時查看 IP, ex: 10.0.2.2)
(4). Mac OS X > 終端機 > ssh root@10.0.2.2 (default password: alpine)
=> 如果出現以下訊息: WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!
代表, 之前有 jailbreak 過不同的版本並曾登入過 iPod Touch,
解決辦法: 先移除(這裡用搬移檔案) Mac 上 .ssh 目錄下的檔案, 再登入一次:
$ cd /Users/lanli/.ssh
$ mv known_hosts known_hosts_back_20101018

(5). 承上, 鍵入 passwd 來輸入新密碼.
(6). 亦可在 Mac 上使用 sftp client 的軟體連入 iPod Touch 系統中.

12 . 檢查 AppBackup 儲存的目錄.
(1). 登入 iPod Touch 後, 到 AppBackup 目錄下, 檢查其下的檔案與子目錄下的檔案日期是否為最新的.
$ cd /private/var/mobile/Library/Preferences/AppBackup
$ ls -al

(2). 如果不是的話, 先執行 AppBackup (按下左下角的 ALL => Backup), 讓他產生該有的檔案.

a. 承上, 調整目錄與檔案的權限.
$ chmod 777 *.* (在 AppBackup 目錄下 )

b. 承上, 並將之前 2. 備份資料: (2). 執行 Cydia 的 AppBackup 所備份的資料, 利用 sftp 傳回 iPod Touch 上(覆蓋舊檔).

c. 承上, 然後在 AppBackup 軟體裡 按左下角的 ALL => Restore

13. 使用 iTunes 同步並備份 iPod Touch 的資料.
=> 主要是用來同步之前安裝了 JB 後才可安裝的軟體 ^^ (Cydia 以外的軟體)

2010年9月9日 星期四

iPhone 開發筆記07: 碰觸背景時關閉鍵盤

步驟一:

View-based Application:
1. view controller 的 nib 檔中的 View 圖像, 為 nib 的容器檢視.(container view)
2. 在 Interface Builder 中, 於 identity inspector(識別檢閱器)裡, 將 View 的類別由 UIView 改成 UIControl.
3. 因為 UIControl 是 UIView 的子類別, 且 UIControl 具有觸發動作方法的能力.
------------------------------------------------------------------------------------------------
步驟二:

xxxViewController.h
....
-(IBAction)backgroundTap:(id)sender;
------------------------------------------------------------------------------------------------
步驟三:

xxxViewController.m
...
-(IBAction)backgroundTap:(id)sender{
[nameField resignFirstResponder];
[numberField resignFirstResponder];
}
------------------------------------------------------------------------------------------------
步驟四:

將 View 上的 Touch Down 事件, 連到 backgroundTap 這個 IBAction.

2010年9月8日 星期三

iPhone 開發筆記06: 小記

1. 從 IBAction 的 sender, 取得被點選按鈕的標題名稱.
NSString *title = [sender titleForState:UIControlStateNormal];
說明:
UIControlStateNormal: 控制項為正常狀態.(有作用, 但目前沒有被使用)
UIControlStateHighlighted: 控制項正在被點選或使用中.
UIControlStateDisabled: 控制項 沒有啓用或不能使用.
UIControlStateSelected: 控制項目前被選取.

2. - (void)viewDidUnload; - (void)dealloc;
@property (nonatomic, retain) IBOutlet UILabel *statusText;

- (void)viewDidUnload {
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
//@add
self.statusText = nil;
}

- (void)dealloc {
//@add
[statusText release];

[super dealloc];
}

3. Events 翻譯
Touch Up Inside: 碰觸離手
Touch Drag Inside: 碰觸拖拉

4. 在 .h 與 .m 檔之間切換
===> option + command + 向上鍵

5. 調整檢視至適當大小
Layout > Size to Fit

2010年9月5日 星期日

耶魯大學開放課程:天體物理學之探索和爭議 ---- 心得筆記

Open Yale course:Frontiers and Controversies in Astrophysics
----------------------------------------------------------------------------------------------------
1. 不要算 125 的平方根, 算 121 的平方根就好. 這簡單很多, 這就是商場上說的打破思考貫例. (Thinking outside the box) 要避免事倍功半, 認真做事, 但是要想辦法將其簡化.

2010年8月31日 星期二

iPC OSx86 10.5.6 Universal Intel/AMD

NoteBook: Acer TravelMate 426LC
購入日期: 2003年1月15日
-------------------------------------------------------------------------------------------------
OS: iPC OSx86 10.5.6 Universal Intel/AMD
限制: 無法使用 Boot Camp
-------------------------------------------------------------------------------------------------
參考資料:
1. iPC OSx86 Install Disc » iPC OSx86 Universal 10.5.6
http://pcwizcomputer.com/ipcosx86/?page_id=96&cpage=8

2. How to update iPC 10.5.6 to 10.5.7?
http://osx86.net/archive/index.php/t-2980.html
-------------------------------------------------------------------------------------------------
注意事項:
1. For some reason sometimes Extensions.mkext is not always cleared on the first boot causing some kexts not to load. This is easily remedied. If you installed the right drivers and they don't seem to have any effect, boot in, go to /System/Library, find the Extensions.mkext file and delete it. Then restart and keep tapping F8 to open the boot menu. Type in "-f" without quotes and hit enter to rebuild the kext cache. This only needs to be done once.
-------------------------------------------------------------------------------------------------
安裝步驟:
A. 將 NoteBook 調整成光碟開機, 放入 "iPC OSx86 10.5.6 Universal Intel/AMD" 片後重新開機.

B. 從光碟開機後, 於訊息暫停時, 按 F8 進入啟動選單(start up options).

C. 在 boot: 後輸入 -v , 再按 enter. (start up with diagnostic message; 顯示診斷訊息)

D. 等待一段時間後(約5分鐘), 出現安裝的語言選擇畫面:
===> 選擇最上方的: "Use English for the main language"

E. 出現 "Welcome" 畫面時, 先等待上方的功能表出現(有時會比較慢載入)

F. 於功能表中, 選擇: Utility > Disk Utility > Erase :
===> 將硬碟重新作分割如下後, 按下右下方的 "Erase" 按鈕:
Volume Format: Mac OS Extended (Journaled)

Name: Leopard (自取)

G. 完成分割後, 按下左上角紅色關閉按鈕, 即會回到之前的 "Welcome" 畫面, 接著按 "Continue".

H. software license agreement => Agree

I. Select a Destination => Leopard (之前分割好的) => Continue

J. Install Summary => Customize, 選取以下的項目:
=> iPC OSx86 10.5.6 Base System(預設)
=> Language Translations: Traditional Chinese
=> iPC OSx86 10.5.6 Intel AMD SSE2 SSE3:
> kernels: 9.4.0 StageXNU Universal Kernel
> Drivers > Video Drivers: LaptopDisplay
>
Drivers > Chipset Drivers: LegacyAppleIntelPIIXATA
> Drivers > Audio Drivers > OtherAudio Drivers: AC97 Audio
> Drivers > Ethernet Drivers: Intel PRO 100/VE
> Drivers > USB Drivers: Patched USB Drivers
> Drivers > Power Management: AppleACPIBatteryManager
> Fixes and Patches:
ACPI Fix
(
wont mount drives without this);
CPUS=1 One Core Fix
;
IOPCMCIAFamily
(
enables PCMCIA cards);
Seatbelt.kext 10.5.5
;
USB Mount Fix
;
PS /2 Device Support
: PS / 2 Keyboard Fix(enables keyboard and touch pad).

===> Done ===> Install ===> Checking Installation DVD => Skip (開始安裝....)

K. 安裝完成後: Restart => 退出光碟片

L. 重新開機後, F8 => boot: -f
=> On the first boot make sure to boot with the -f boot flag! Do this to make sure that all installed kexts are loaded properly. It is only required once.
-------------------------------------------------------------------------------------------------
M. update iPC 10.5.6 to 10.5.7 (似乎不太穩定, 尤其是無法正常重新開機)
a.
Download Andy's 9.6.0 kernel package:
http://www.mediafire.com/?gl1nmwjen0y

b. Download Mac OS X 10.5.7 Update:
http://support.apple.com/kb/DL826

c. 步驟:
1. Open the terminal.

2. Browse into main directory of your Mac OS partition.
"cd /Volumes/Leopard"
"ls -l"

3. You should see a file named "mach_kernel" there. Make a backup of it.
"cp mach_kernel mach_kernel_old"

4. Repair its permissions.
"sudo chmod -R 755 mach_kernel_old"
"sudo chown -R 0:0 mach_kernel_old"

#5. Now you can run Software Update, and get your update.
===> 如果執行 Software Update, 會直接更新 10.5.8 版本(更新後, 無法正常登入), 所以直接執行之前下載的 Mac OS X 10.5.7 Update 檔案.

6. After the update - restart your computer.

7. While booting, press F8 and write :
"mach_kernel_old -x" (無法登入的話, 參數改成: -v -x)

8. When your computer boots up in safe mode - just install Andy's package.

9. Restart and boot normally.

10. You have 10.5.7 running.

Well, that's it. You can of course make a backup of System.kext aswell, then instead of booting into safe mode and installing Andy's kernel - you can boot into -s mode and copy back the System.kext ( and repair permissions ), but i find this way more convenient.

PS. seatbelt.kext is needed on 10.5.6 to mount USB/DMG properly. Without it your system may fail to mount usb drives or images, or kernel panic at you when you try to do it.
-------------------------------------------------------------------------------------------------
N. Download Xcode 3.1.4(這個版本還沒有支援開發 iPhone) for Leopard
Apple’s developer website only links to the latest version of Xcode, which requires Snow Leopard (Mac OS X 10.6).

If you’re still running Leopard (10.5), you need to go to this alternative developer website:
http://connect.apple.com/

Log in with your ADC credentials, click “Downloads”, then click “Developer Tools” in the right sidebar, and then search the page for “3.1.4″.