Class 14iOS 應⽤用軟體設計
課程⼤大綱•   ⽤用 Processing 學習繪圖程式邏輯    •   QV081:球移動反彈    •   QV082:Objective-C 的物件思維•   Objective-C 類別與⾃自訂類別    •   QV080:⾃自訂...
Processing
Processing 語⾔言特性• 適合學習基礎的程式邏輯• 畫⾯面上的繪圖呈現
程式結構•   void setup()    {      // 設定的部份    }•   void draw()    {      // 時間迴圈的部份    }
資料型態• int• float• 陣列 int[], float[]
起始設定畫布• size( w, h)• smooth( )• frameRate( n )• background( R, G, B )
常⽤用的畫圖指令• point(x, y)• line(x1, y1, x2, y2)• rect(x1, y1, x2, y2)• ellipse(x1, y1, w, h)• triangle(x1, y1, x2, y2, x3, y3)...
顏⾊色指令• fill( R, G, B )• noFill()• stroke( R, G, B)• strokeWeight( w )• noStroke()
更多 Processing 的程式技巧
範例: 移動球,撞牆反彈
Project QV081 球移動,碰到周圍反彈   計時器 NSTimer   UI 物件移動位置 常數定義與變數使⽤用 .....傳統 C 語⾔言的思維
ViewController.xib
ViewController.h#import <UIKit/UIKit.h>extern const float areaWidth;extern const float areaHeight;                        ...
常數宣告            ViewController.m (1/2)const float areaWidth = 320;const float areaHeight = 460;@implementation ViewControl...
ViewController.m (2/2)- (void) gameLoop: (NSTimer *) theTimer{    // 取得新位置     float ballX = ball.center.x;     float ball...
思考訓練 考慮有哪些參數是適合單獨定義,以 便讓程式的彈性增加  框框⼤大⼩小,位置  遞增量  預設位置、預設⽅方向  ......
讓程式更具彈性• 定義的資料儘可能獨⽴立,且保持彈性 • 畫⾯面⼤大⼩小 (320x460)  ===> 改為常數或變數定義• 物件⼤大⼩小 (40x40⾃自訂)  ===> 抓取物件的實際值
Objective-C 希望......• 能⽤用類別物件時,儘可能⽤用類別 (避開直覺的資料型態)• 不重覆變數,減少記憶體的使⽤用
Project QV082與 Project QV081 ⽐比較...球移動,碰到周圍反彈Objective-C 物件的使⽤用.....Objective-C 的思維
ViewController.h#import <UIKit/UIKit.h>extern const CGRect CGRectArea;            "物件" 常數宣告@interface ViewController : UIV...
#import "ViewController.h"                      ViewController.m (1/2)@implementation ViewController@synthesize ball;const...
ViewController.m (2/2)                                                               移⾄至計算後- (void) gameLoop: (NSTimer *) ...
挑戰練習 有多個球在畫⾯面亂動時該怎麼處理?
範例:⾃自訂類別
Project QV080開發者⾃自建 UIView 類別
選擇這裡新增檔案 (類別)
選擇 Objective-C class
(1) 輸⼊入類別名稱(2) 選擇『繼承』⾃自 UIView類別
#import <UIKit/UIKit.h>            MYView.h@interface MYView : UIView@end                                                 ...
MYView.h#import <UIKit/UIKit.h>@interface MYView : UIView           property{    UIImage *img;}- (id) initImage:(CGRect)fr...
MYView.m#import "MYView.h"@implementation MYView- (id) initImage:(CGRect)frame filename:(NSString *)name{    if(self = [su...
ViewController.h在主程式中使⽤用⾃自訂類別  #import <UIKit/UIKit.h>  #import "MYView.h"              引⼊入類別  @interface ViewController :...
ViewController.m#import "ViewController.h"@implementation ViewController                                        此例中同時⽰示範不藉...
⾃自我練習 在主程式增加功能,讓此類別物件產 ⽣生動作 (例如:讓它移動) 在類別內增加功能 (property, method, ......)
程式參考                         範例:讓此炸彈掉落- (void) loadView{    ****** 省略部份程式 ******    [NSTimer scheduledTimerWithTimeInterva...
範例:⾃自定類別,移動碰撞
Project QV084⾃自訂類別的物件在畫⾯面上移動,撞牆反彈學習重點:⾃自訂物件的移動(遊戲設計中稱為 sprite『動畫精靈』)
⾃自定類別
MYView.h       ⾃自定類別的宣告#import <UIKit/UIKit.h>@interface MYView : UIView{    UIImage *img;}- (id) initImage:(CGRect)frame ...
⾃自定類別的實作                                      MYView.m#import "MYView.h"@implementation MYView- (id) initImage:(CGRect)fra...
ViewController.h#import <UIKit/UIKit.h>#import "MYView.h"@interface ViewController : UIViewController{    MYView *imageVie...
ViewController.m (1/2)- (void)viewDidLoad{    [super viewDidLoad];    incX = 2.0;                         要移動的量    incY = ...
檢查碰撞,                                                 ViewController.m (2/2)            若到邊緣則反彈- (void) gameLoop: (NSTimer...
挑戰練習 使⽤用多個物件......
範例:兩個物件,互相碰撞
Project QV085延續 Project QV084⾃自訂類別,產⽣生兩個物件在畫⾯面上移動,撞牆反彈球與球相撞時亦反彈學習重點:尚未使⽤用到物件的優點 (不是很理想的寫法)
⾃自定類別(與之前相同)
ViewController.h       ⾃自定類別的宣告#import <UIKit/UIKit.h>#import "MYView.h"@interface ViewController : UIViewController{    M...
- (void)viewDidLoad{                                                       ViewController.m (1/3)    [super viewDidLoad]; ...
ViewController.m (2/3)- (void) gameLoop: (NSTimer *)theTimer{    // ********** 第⼀一個球 **********    // 取得物件,移⾄至新位置    image...
- (void) gameLoop: (NSTimer *)theTimer             ViewController.m (1/3){    ****** 省略部份程式 ******    // 處理碰撞    float dis...
程式思考 出現更多個球 (希望不會寫到瘋掉) 如何讓主程式不要⼀一再重覆寫相同的 內容?
範例:   三個物件(動作定義在類別上)
Project QV086延續 Project QV084, QV085產⽣生三個物件各⾃自移動,兩兩碰撞後反彈學習重點:更佳的物件寫法 、取得物件內部的資料(Property, Synthesize)
哪些東⻄西應該和『物件⾃自⾝身』有關 物件應該⾃自⼰己動   速度、⽅方向...... 物件應該具有各⾃自的外觀   圖檔、⼤大⼩小、顏⾊色...... 物件應該⾃自⼰己偵測碰撞   撞牆壁後反彈   兩球相撞後反彈 (???)
MYView.h   ⾃自定類別的宣告#import <UIKit/UIKit.h>@interface MYView : UIView{    UIImage *img;    float incX, incY;}@property floa...
MYView.m (1/2)#import "MYView.h"@implementation MYView@synthesize incX, incY;- (id) initImage:(CGRect)frame filename:(NSSt...
MYView.m (2/2)****** 省略部份程式 ******                                 物件內的屬性- (void) move{    // 取得物件,移⾄至新位置    self.center =...
ViewController.h#import <UIKit/UIKit.h>#import "MYView.h"@interface ViewController : UIViewController{    MYView *imageVie...
ViewController.m (1/5)- (void)viewDidLoad{    // 產⽣生 MYView 並初始化    imageView = [[MYView alloc]                  initImage...
ViewController.m (2/5)    程式主要迴圈:球移動    多呼叫物件內的 method- (void) gameLoop: (NSTimer *)theTimer{    [imageView move];    [bal...
碰撞處理⽅方法之⼀一                                    ViewController.m (3/5)- (void) gameLoop: (NSTimer *)theTimer{    ****** 省略部份...
碰撞處理⽅方法之⼆二                                      ViewController.m (4/5)- (BOOL) checkHit: (MYView *)b1 :(MYView *)b2{    fl...
碰撞處理⽅方法之三                                         ViewController.m (5/5) - (void) checkHitAndBounce:(MYView *)b1 :(MYView ...
程式思考 物件之間的溝通還有別的做法嗎?
範例:(陣列)    處理更多球的   移動、產⽣生及消失
Project QV087延續 Project QV084~QV086⾃自訂兩個類別,多個物件Objective-C 陣列使⽤用球碰撞炸彈後消失,另有按鈕產⽣生新的球學習重點:Objective-C 陣列
當『物件』數量更多時...... 需記錄每⼀一個物件的狀態及資訊   陣列⼤大⼩小......   陣列元素的存取...... 數量的變更   刪除......   增加......
MYView.h#import <UIKit/UIKit.h>@interface MYView : UIView{    UIImage *img;    float incX, incY;}@property float incX, inc...
#import "MYView.h"                                                        MYView.m (1/2)#define   ARC4RANDOM_MAX   0x10000...
MYView.m (2/2)@implementation MYBomb- (id) initImage:(CGRect)frame filename:(NSString *)name{    if(self = [super initWith...
ViewController.h#import <UIKit/UIKit.h>#import "MYView.h"extern const int BallNumber;                   初始陣列⼤大⼩小@interface...
ViewController.m (1/4)    起始多個物件,存於陣列內- (void)viewDidLoad{    ****** 省略部份程式 ******    // 產⽣生 ballAry    ballArray = [[NSMu...
ViewController.m (2/4)陣列內各個球的移動及碰撞處理- (void) gameLoop: (NSTimer *)theTimer{    NSMutableArray *objectsToDelete = [NSMutabl...
ViewController.m (3/4)    球與球的碰撞處理- (void) gameLoop: (NSTimer *)theTimer{                                                 ...
ViewController.m (4/4)       產⽣生新的球- (IBAction) buildOne:(id)sender{    MYView *newView = [[MYView alloc]                 ...
數種繪圖及動畫 APIUIKit   Quartz 2D        OpenGL ES
Quartz 2D
painters model• canvas• page• context
output device
Current transformation        matrix (CTM)•   Quartz accomplishes device independence with a    separate coordinate system...
Project QV136 Quartz2D 基本繪圖指令 動畫精靈 (sprite) 概念 應標變換
Quartz2D 繪圖程式的基本架構                         Shape1View.m (1/2)- (void)drawRect:(CGRect)rect{    // 取得圖像內⽂文,並保存它的狀態    CGCon...
Shape1View.m (2/2)// 繪圖CGContextBeginPath(context);CGContextSetRGBFillColor(context, 0.0f, 0.0f, 1.0f, 1.0f);CGContextAddR...
ViewController.m#import "ViewController.h"#import "Shape1View.h"#import "Shape2View.h"#import "Shape3View.h"@implementatio...
Shape2View加⼊入Timer及按下互動  Shape3View  加⼊入座標變換
Project QV137動畫精靈 (sprite) 概念  Quartz 2D(含座標變換)  UIView (含 NSTimer)在主迴圈和 sprite 中的觸控⽐比較
按空⽩白處會產⽣生新物件          按物體會變換顏⾊色          按三次後會消失
ShapeView.h@interface ShapeView : UIView{    NSTimer *timer;    CGFloat x, y, r;    CGFloat colorR, colorG, colorB;    CGF...
- (id)initWithFrame:(CGRect)frame                  ShapeView.m (1/2){    self = [super initWithFrame:frame];    if (self) ...
- (void)drawRect:(CGRect)rect{    // 取得圖像內⽂文,並保存它的狀態                                                   ShapeView.m    CGCo...
-(void) touchesBegan:(NSSet *)touches   withEvent:(UIEvent *)event{    colorR = (CGFloat)(arc4random() %   100)/100.0f;   ...
範例觀摩:QuartzFun, GLFun                   ref: ch.14
範例觀摩:QuartzDemo
............
I os 14
I os 14
Upcoming SlideShare
Loading in …5
×

I os 14

499 views
402 views

Published on

0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
499
On SlideShare
0
From Embeds
0
Number of Embeds
18
Actions
Shares
0
Downloads
0
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

I os 14

  1. 1. Class 14iOS 應⽤用軟體設計
  2. 2. 課程⼤大綱• ⽤用 Processing 學習繪圖程式邏輯 • QV081:球移動反彈 • QV082:Objective-C 的物件思維• Objective-C 類別與⾃自訂類別 • QV080:⾃自訂類別 • QV084:⾃自訂類別,移動碰撞 • QV085:兩個物件互相碰撞 • QV086:三個物件 (動作定義在物件上) • QV087:⽤用陣列處理更多的球• Quartz 2D • QV136:Quartz 2D • QV137:動畫精靈 (Sprite) • Samples:QuartzFun, GLFun, QuartzDemo
  3. 3. Processing
  4. 4. Processing 語⾔言特性• 適合學習基礎的程式邏輯• 畫⾯面上的繪圖呈現
  5. 5. 程式結構• void setup() { // 設定的部份 }• void draw() { // 時間迴圈的部份 }
  6. 6. 資料型態• int• float• 陣列 int[], float[]
  7. 7. 起始設定畫布• size( w, h)• smooth( )• frameRate( n )• background( R, G, B )
  8. 8. 常⽤用的畫圖指令• point(x, y)• line(x1, y1, x2, y2)• rect(x1, y1, x2, y2)• ellipse(x1, y1, w, h)• triangle(x1, y1, x2, y2, x3, y3)• quad(x1, y1, x2, y2, x3, y3, x4, y4)• bezier(x1, y1, x2, y2, x3, y3, x4, y4)
  9. 9. 顏⾊色指令• fill( R, G, B )• noFill()• stroke( R, G, B)• strokeWeight( w )• noStroke()
  10. 10. 更多 Processing 的程式技巧
  11. 11. 範例: 移動球,撞牆反彈
  12. 12. Project QV081 球移動,碰到周圍反彈 計時器 NSTimer UI 物件移動位置 常數定義與變數使⽤用 .....傳統 C 語⾔言的思維
  13. 13. ViewController.xib
  14. 14. ViewController.h#import <UIKit/UIKit.h>extern const float areaWidth;extern const float areaHeight; 常數宣告@interface ViewController : UIViewController{ IBOutlet UIImageView *ball; float ballMovementX, ballMovementY; // 每次移動的量}- (void) initializeTimer;- (void) gameLoop: (NSTimer *) theTimer; 變數宣告@end
  15. 15. 常數宣告 ViewController.m (1/2)const float areaWidth = 320;const float areaHeight = 460;@implementation ViewController- (void) initializeTimer{ float theInterval = 1.0 / 30.0; [NSTimer scheduledTimerWithTimeInterval:theInterval target:self selector:@selector(gameLoop:) userInfo:nil repeats:YES];}- (void) gameLoop: (NSTimer *) theTimer{ ****** 省略部份程式 ******}- (void)viewDidLoad 計時器使⽤用{ [super viewDidLoad]; (基本遊戲迴圈) // 起始設定 ballMovementX = 4.0; 速度控制之參數 ballMovementY = 4.0; (1) 遞增量 [self initializeTimer];} (2) 時間間隔
  16. 16. ViewController.m (2/2)- (void) gameLoop: (NSTimer *) theTimer{ // 取得新位置 float ballX = ball.center.x; float ballY = ball.center.y; ballX += ballMovementX; ballY += ballMovementY; ball.center = CGPointMake(ballX, ballY); 移⾄至新位置 // 檢查碰撞到周圍 if(ballX > areaWidth || ballX < 0) { ballMovementX = -ballMovementX; } if(ballY > areaHeight || ballY < 0) { ballMovementY = -ballMovementY; }}
  17. 17. 思考訓練 考慮有哪些參數是適合單獨定義,以 便讓程式的彈性增加 框框⼤大⼩小,位置 遞增量 預設位置、預設⽅方向 ......
  18. 18. 讓程式更具彈性• 定義的資料儘可能獨⽴立,且保持彈性 • 畫⾯面⼤大⼩小 (320x460) ===> 改為常數或變數定義• 物件⼤大⼩小 (40x40⾃自訂) ===> 抓取物件的實際值
  19. 19. Objective-C 希望......• 能⽤用類別物件時,儘可能⽤用類別 (避開直覺的資料型態)• 不重覆變數,減少記憶體的使⽤用
  20. 20. Project QV082與 Project QV081 ⽐比較...球移動,碰到周圍反彈Objective-C 物件的使⽤用.....Objective-C 的思維
  21. 21. ViewController.h#import <UIKit/UIKit.h>extern const CGRect CGRectArea; "物件" 常數宣告@interface ViewController : UIViewController{ IBOutlet UIImageView *ball; CGPoint ballMovement; // 每次移動的量}@property(nonatomic,retain) IBOutlet UIImageView *ball;- (void) initializeTimer;- (void) gameLoop: (NSTimer *) theTimer; 物件內含@end 較多資訊 (x, y)
  22. 22. #import "ViewController.h" ViewController.m (1/2)@implementation ViewController@synthesize ball;const CGRect CGRectArea = { {10.0f, 10.0f}, {300.0f, 440.0f} };- (void) initializeTimer{ 常數宣告 float theInterval = 1.0 / 30.0; [NSTimer scheduledTimerWithTimeInterval:theInterval target:self selector:@selector(gameLoop:) userInfo:nil repeats:YES];}- (void) gameLoop: (NSTimer *) theTimer{ ****** 省略部份程式 ******}- (void)viewDidLoad{ [super viewDidLoad]; 物件變數使⽤用 // 起始設定 ballMovement = CGPointMake(4.0, 4.0); [self initializeTimer];}
  23. 23. ViewController.m (2/2) 移⾄至計算後- (void) gameLoop: (NSTimer *) theTimer{ 的新位置 // 取得新位置 ball.center = CGPointMake(ball.center.x+ballMovement.x, ball.center.y+ballMovement.y); // 檢查碰撞到周圍 if(ball.center.x > (CGRectGetMinX(CGRectArea)-ball.frame.size.width/2) || ball.center.x < (CGRectGetMinX(CGRectArea)+ball.frame.size.width/2)) { ballMovement.x *= -1;; } if(ball.center.y > (CGRectGetMaxY(CGRectArea)-ball.frame.size.height/2) || ball.center.y < (CGRectGetMinY(CGRectArea)+ball.frame.size.height/2)) { ballMovement.y *= -1; }}
  24. 24. 挑戰練習 有多個球在畫⾯面亂動時該怎麼處理?
  25. 25. 範例:⾃自訂類別
  26. 26. Project QV080開發者⾃自建 UIView 類別
  27. 27. 選擇這裡新增檔案 (類別)
  28. 28. 選擇 Objective-C class
  29. 29. (1) 輸⼊入類別名稱(2) 選擇『繼承』⾃自 UIView類別
  30. 30. #import <UIKit/UIKit.h> MYView.h@interface MYView : UIView@end MYView.m#import "MYView.h"@implementation MYView- (id)initWithFrame:(CGRect)frame{ self = [super initWithFrame:frame]; if (self) { // Initialization code 開新檔時預設的內容 } return self;}/*// Only override drawRect: if you perform custom drawing.// An empty implementation adversely affects performance during ......- (void)drawRect:(CGRect)rect{ // Drawing code}*/@end
  31. 31. MYView.h#import <UIKit/UIKit.h>@interface MYView : UIView property{ UIImage *img;}- (id) initImage:(CGRect)frame filename:(NSString *)name;@end method (此例有改寫起始⽅方法, 故需要宣告)
  32. 32. MYView.m#import "MYView.h"@implementation MYView- (id) initImage:(CGRect)frame filename:(NSString *)name{ if(self = [super initWithFrame:frame]) { img = [UIImage imageNamed:name]; } return self;}- (void)drawRect:(CGRect)rect ⾃自⼰己的程式{ CGPoint p; p.x = 0; p.y = 0; [img drawAtPoint:p];}@end
  33. 33. ViewController.h在主程式中使⽤用⾃自訂類別 #import <UIKit/UIKit.h> #import "MYView.h"  引⼊入類別 @interface ViewController : UIViewController { MYView *imageView; } @end  使⽤用⾃自訂類別,產⽣生物件
  34. 34. ViewController.m#import "ViewController.h"@implementation ViewController 此例中同時⽰示範不藉由 xib 產⽣生畫⾯面的⽅方式- (void) loadView{ 注意 loadView 及 viewDidLoad ⽤用法時機 // 設置主要視圖 self.view = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]]; // 將背景設為⽩白⾊色 self.view.backgroundColor = [UIColor whiteColor]; // 產⽣生 MYView 並初始化 imageView = [[MYView alloc] initImage:CGRectMake(100.0f, 200.0f, 48.0f, 48.0f) filename:@"bomb.png"]; // 背景設為透明 imageView.backgroundColor = [UIColor clearColor]; // 將 MYView 新增於主視圖 [self.view addSubview:imageView];}- (void)viewDidLoad{ 使⽤用⾃自訂類別 [super viewDidLoad];! // Do any additional setup after loading the view, typically from a nib.}
  35. 35. ⾃自我練習 在主程式增加功能,讓此類別物件產 ⽣生動作 (例如:讓它移動) 在類別內增加功能 (property, method, ......)
  36. 36. 程式參考 範例:讓此炸彈掉落- (void) loadView{ ****** 省略部份程式 ****** [NSTimer scheduledTimerWithTimeInterval:0.01 target:self selector:@selector(gameLoop:) userInfo:nil repeats:YES];}- (void) gameLoop: (NSTimer *)theTimer{ // 取得物件,移⾄至新位置 (往下掉) imageView.center = CGPointMake(imageView.center.x, imageView.center.y+1); if(imageView.center.y>=self.view.frame.size.height) { imageView.center = CGPointMake(imageView.center.x, 0); }} 此處 imageView 為⾃自訂類別的物件
  37. 37. 範例:⾃自定類別,移動碰撞
  38. 38. Project QV084⾃自訂類別的物件在畫⾯面上移動,撞牆反彈學習重點:⾃自訂物件的移動(遊戲設計中稱為 sprite『動畫精靈』)
  39. 39. ⾃自定類別
  40. 40. MYView.h ⾃自定類別的宣告#import <UIKit/UIKit.h>@interface MYView : UIView{ UIImage *img;}- (id) initImage:(CGRect)frame filename:(NSString *)name;@end
  41. 41. ⾃自定類別的實作 MYView.m#import "MYView.h"@implementation MYView- (id) initImage:(CGRect)frame filename:(NSString *)name{ if(self = [super initWithFrame:frame]) { img = [UIImage imageNamed:name]; } return self;}- (void)drawRect:(CGRect)rect{ CGPoint p; p.x = 0; p.y = 0; [img drawAtPoint:p];}@end
  42. 42. ViewController.h#import <UIKit/UIKit.h>#import "MYView.h"@interface ViewController : UIViewController{ MYView *imageView; float incX, incY;} 要移動的量@end 直接⽤用浮點數
  43. 43. ViewController.m (1/2)- (void)viewDidLoad{ [super viewDidLoad]; incX = 2.0; 要移動的量 incY = 1.0; // 產⽣生 MYView 並初始化 imageView = [[MYView alloc] initImage:CGRectMake(100.0f, 200.0f, 64.0f, 64.0f) filename:@"3d_ball.png"]; // 背景設為透明 imageView.backgroundColor = [UIColor clearColor]; // 將 MYView 新增於主視圖 [self.view addSubview:imageView]; [NSTimer scheduledTimerWithTimeInterval:0.01 target:self selector:@selector(gameLoop:) userInfo:nil repeats:YES];}
  44. 44. 檢查碰撞, ViewController.m (2/2) 若到邊緣則反彈- (void) gameLoop: (NSTimer *)theTimer{ // 取得物件,移⾄至新位置 imageView.center = CGPointMake(imageView.center.x+incX, imageView.center.y+incY); // 檢查碰撞到周圍 if(imageView.center.x >= (self.view.frame.size.width-imageView.frame.size.width/2) || imageView.center.x <= (0+imageView.frame.size.width/2)) { incX *= -1; } if(imageView.center.y >= (self.view.frame.size.height-imageView.frame.size.height/2) || imageView.center.y <= (0+imageView.frame.size.height/2)) { incY *= -1; }}
  45. 45. 挑戰練習 使⽤用多個物件......
  46. 46. 範例:兩個物件,互相碰撞
  47. 47. Project QV085延續 Project QV084⾃自訂類別,產⽣生兩個物件在畫⾯面上移動,撞牆反彈球與球相撞時亦反彈學習重點:尚未使⽤用到物件的優點 (不是很理想的寫法)
  48. 48. ⾃自定類別(與之前相同)
  49. 49. ViewController.h ⾃自定類別的宣告#import <UIKit/UIKit.h>#import "MYView.h"@interface ViewController : UIViewController{ MYView *imageView1; float incX1, incY1; MYView *imageView2; 宣告兩個物件 float incX2, incY2;} 以及各別物件的移動量@end (不是很聰明的⽤用法)
  50. 50. - (void)viewDidLoad{ ViewController.m (1/3) [super viewDidLoad]; // ********** 第⼀一個球 ********** incX1 = 2.0; incY1 = 1.5; // 產⽣生 MYView 並初始化 imageView1 = [[MYView alloc] initImage:CGRectMake(100.0f, 200.0f, 48.0f, 48.0f) filename:@"bb_blue.png"]; // 背景設為透明 imageView1.backgroundColor = [UIColor clearColor]; // 將 MYView 新增於主視圖 [self.view addSubview:imageView1]; 重覆撰寫 // ********** 第⼆二個球 ********** 各別的運動 incX2 = 1.0; incY2 = 2.5; // 產⽣生 MYView 並初始化 imageView2 = [[MYView alloc] initImage:CGRectMake(80.0f, 120.0f, 48.0f, 48.0f) filename:@"bb_red.png"]; // 背景設為透明 imageView2.backgroundColor = [UIColor clearColor]; // 將 MYView 新增於主視圖 [self.view addSubview:imageView2]; ****** 省略部份程式 ******}
  51. 51. ViewController.m (2/3)- (void) gameLoop: (NSTimer *)theTimer{ // ********** 第⼀一個球 ********** // 取得物件,移⾄至新位置 imageView1.center = CGPointMake(imageView1.center.x+incX1, imageView1.center.y+incY1); // 檢查碰撞到周圍 if(imageView1.center.x>=(self.view.frame.size.width-imageView1.frame.size.width/2) || imageView1.center.x<=(0+imageView1.frame.size.width/2)) { incX1 *= -1; } if(imageView1.center.y>=(self.view.frame.size.height-imageView1.frame.size.height/2) || imageView1.center.y<=(0+imageView1.frame.size.height/2)) { incY1 *= -1; } // ********** 第⼀一個球 ********** // 取得物件,移⾄至新位置 imageView2.center = CGPointMake(imageView2.center.x+incX2, imageView2.center.y+incY2); // 檢查碰撞到周圍 if(imageView2.center.x>=(self.view.frame.size.width-imageView2.frame.size.width/2) || imageView2.center.x<=(0+imageView2.frame.size.width/2)) { incX2 *= -1; } if(imageView2.center.y>=(self.view.frame.size.height-imageView2.frame.size.height/2) || imageView2.center.y<=(0+imageView2.frame.size.height/2)) { incY2 *= -1; } ****** 省略部份程式 ******}
  52. 52. - (void) gameLoop: (NSTimer *)theTimer ViewController.m (1/3){ ****** 省略部份程式 ****** // 處理碰撞 float dist = sqrtf(powf(imageView1.center.x-imageView2.center.x, 2) +powf(imageView1.center.y-imageView2.center.y, 2)); if(dist<=(imageView1.frame.size.width/2+imageView2.frame.size.width/2)) { // 不是很漂亮的⽅方法 /* incX1 *= -1; incY1 *= -1; 檢查是否碰撞 incX2 *= -1; 直接反向 incY2 *= -1; (兩球圓⼼心的距離是否 */ ⼩小於兩圓半徑之和) // 能量守恆的⽅方式 float incX1Temp = incX1; float incX2Temp = incX2; float incY1Temp = incY1; float incY2Temp = incY2; incX1 = incX2Temp; 沒什麼了不起的 incY1 = incY2Temp; 物理原理 incX2 = incX1Temp; incY2 = incY1Temp; }}
  53. 53. 程式思考 出現更多個球 (希望不會寫到瘋掉) 如何讓主程式不要⼀一再重覆寫相同的 內容?
  54. 54. 範例: 三個物件(動作定義在類別上)
  55. 55. Project QV086延續 Project QV084, QV085產⽣生三個物件各⾃自移動,兩兩碰撞後反彈學習重點:更佳的物件寫法 、取得物件內部的資料(Property, Synthesize)
  56. 56. 哪些東⻄西應該和『物件⾃自⾝身』有關 物件應該⾃自⼰己動 速度、⽅方向...... 物件應該具有各⾃自的外觀 圖檔、⼤大⼩小、顏⾊色...... 物件應該⾃自⼰己偵測碰撞 撞牆壁後反彈 兩球相撞後反彈 (???)
  57. 57. MYView.h ⾃自定類別的宣告#import <UIKit/UIKit.h>@interface MYView : UIView{ UIImage *img; float incX, incY;}@property float incX, incY;- (id) initImage:(CGRect)frame filename:(NSString *)name;- (void) move;@end 移動的程式
  58. 58. MYView.m (1/2)#import "MYView.h"@implementation MYView@synthesize incX, incY;- (id) initImage:(CGRect)frame filename:(NSString *)name{ if(self = [super initWithFrame:frame]) { img = [UIImage imageNamed:name]; } incX = 0.5 + arc4random() % 4; incY = 0.5 + arc4random() % 4; return self;} 每個球的移動速****** 省略部份程式 ****** 度及⽅方向為隨機@end
  59. 59. MYView.m (2/2)****** 省略部份程式 ****** 物件內的屬性- (void) move{ // 取得物件,移⾄至新位置 self.center = CGPointMake(self.center.x+incX, self.center.y+incY); // 檢查碰撞到周圍 if(self.center.x>=(320-self.frame.size.width/2) || self.center.x<=(0+self.frame.size.width/2)) { incX *= -1; } if (self.center.y>=(460-self.frame.size.height/2) || self.center.y<=(0+self.frame.size.height/2)) { incY *= -1; } } 有幾個數值的⽤用法不是那麼地漂亮?
  60. 60. ViewController.h#import <UIKit/UIKit.h>#import "MYView.h"@interface ViewController : UIViewController{ MYView *imageView; MYView *ball1, *ball2;}@end 宣告三個物件
  61. 61. ViewController.m (1/5)- (void)viewDidLoad{ // 產⽣生 MYView 並初始化 imageView = [[MYView alloc] initImage:CGRectMake(100.0f, 200.0f, 64.0f, 64.0f) filename:@"3d_ball.png"]; // 背景設為透明 imageView.backgroundColor = [UIColor clearColor]; // 將 MYView 新增於主視圖 [self.view addSubview:imageView]; // 產⽣生 ball2 並初始化 ball1 = [[MYView alloc] initImage:CGRectMake(10.0f, 280.0f, 64.0f, 64.0f) filename:@"3d_ball.png"]; ball1.backgroundColor = [UIColor clearColor]; [self.view addSubview:ball1]; // 產⽣生 ball2 並初始化 ball2 = [[MYView alloc] initImage:CGRectMake(200.0f, 120.0f, 64.0f, 64.0f) filename:@"3d_ball.png"]; ball2.backgroundColor = [UIColor clearColor]; [self.view addSubview:ball2]; ****** 省略部份程式 ******}
  62. 62. ViewController.m (2/5) 程式主要迴圈:球移動 多呼叫物件內的 method- (void) gameLoop: (NSTimer *)theTimer{ [imageView move]; [ball1 move]; [ball2 move]; ****** 省略部份程式 ******}
  63. 63. 碰撞處理⽅方法之⼀一 ViewController.m (3/5)- (void) gameLoop: (NSTimer *)theTimer{ ****** 省略部份程式 ****** // 處理碰撞 (必須知道各物件內的屬性) float dist = sqrtf(powf(ball1.center.x-ball2.center.x, 2)+ powf(ball1.center.y-ball2.center.y, 2)); if(dist<=(ball1.frame.size.width/2+ball2.frame.size.width/2)) { // 能量守恆的⽅方式 float incX1Temp = ball1.incX; float incY1Temp = ball1.incY; float incX2Temp = ball2.incX; 取得各物件內的值, float incY2Temp = ball2.incY; 在主程式中寫 ball1.incX = incX2Temp; ball1.incY = incY2Temp; ball2.incX = incX1Temp; ball2.incY = incY1Temp; }}
  64. 64. 碰撞處理⽅方法之⼆二 ViewController.m (4/5)- (BOOL) checkHit: (MYView *)b1 :(MYView *)b2{ float dist = sqrtf(powf(b1.center.x-b2.center.x, 2) +powf(b1.center.y-b2.center.y, 2)); if(dist<=(b1.frame.size.width/2+b2.frame.size.width/2)) { ****** 省略部份程式 (反彈轉向) ****** return YES; } else { return NO; }}- (void) gameLoop: (NSTimer *)theTimer{ // 處理碰撞 (呼叫method傳回是否碰撞) if([self checkHit:ball1 :ball2]) 傳回兩物件是否碰撞 { ****** 省略部份程式 ****** }}
  65. 65. 碰撞處理⽅方法之三 ViewController.m (5/5) - (void) checkHitAndBounce:(MYView *)b1 :(MYView *)b2 { float dist = sqrtf(powf(b1.center.x-b2.center.x, 2) +powf(b1.center.y-b2.center.y, 2)); if(dist<=(b1.frame.size.width/2+b2.frame.size.width/2)) { // 反彈轉向 float incX1Temp = b1.incX; float incY1Temp = b1.incY; float incX2Temp = b2.incX; float incY2Temp = b2.incY; b1.incX = incX2Temp; b1.incY = incY2Temp; b2.incX = incX1Temp; b2.incY = incY1Temp; } } - (void) gameLoop: (NSTimer *)theTimer { 較完整的功能 [imageView move]; 檢查碰撞並 [ball1 move]; [ball2 move]; ⽴立即處理反彈 [self checkHitAndBounce:ball1 :ball2]; [self checkHitAndBounce:ball1 :imageView]; [self checkHitAndBounce:ball2 :imageView]; }
  66. 66. 程式思考 物件之間的溝通還有別的做法嗎?
  67. 67. 範例:(陣列) 處理更多球的 移動、產⽣生及消失
  68. 68. Project QV087延續 Project QV084~QV086⾃自訂兩個類別,多個物件Objective-C 陣列使⽤用球碰撞炸彈後消失,另有按鈕產⽣生新的球學習重點:Objective-C 陣列
  69. 69. 當『物件』數量更多時...... 需記錄每⼀一個物件的狀態及資訊 陣列⼤大⼩小...... 陣列元素的存取...... 數量的變更 刪除...... 增加......
  70. 70. MYView.h#import <UIKit/UIKit.h>@interface MYView : UIView{ UIImage *img; float incX, incY;}@property float incX, incY;- (id) initImage:(CGRect)frame filename:(NSString *)name;- (void) move;@end 同⼀一個檔案內含 兩個類別的宣告@interface MYBomb : UIView{ UIImage *img;}- (id) initImage:(CGRect)frame filename:(NSString *)name;@end
  71. 71. #import "MYView.h" MYView.m (1/2)#define ARC4RANDOM_MAX 0x100000000@implementation MYView@synthesize incX, incY;- (id) initImage:(CGRect)frame filename:(NSString *)name{ if(self = [super initWithFrame:frame]) { img = [UIImage imageNamed:name]; } incX = (float)arc4random()/ARC4RANDOM_MAX * 4.0f; incY = (float)arc4random()/ARC4RANDOM_MAX * 4.0f; return self;}- (void)drawRect:(CGRect)rect{ 球的移動量 ****** 省略部分程式 ******} 浮點數隨機亂數- (void) move{ ****** 省略部分程式 ******}@end
  72. 72. MYView.m (2/2)@implementation MYBomb- (id) initImage:(CGRect)frame filename:(NSString *)name{ if(self = [super initWithFrame:frame]) { img = [UIImage imageNamed:name]; } return self;}- (void)drawRect:(CGRect)rect{ CGPoint p; p.x = 0; p.y = 0; 單純擺上⼀一個圖⽚片 [img drawAtPoint:p];}@end
  73. 73. ViewController.h#import <UIKit/UIKit.h>#import "MYView.h"extern const int BallNumber; 初始陣列⼤大⼩小@interface ViewController : UIViewController{ MYBomb *imageBomb; NSMutableArray *ballArray; 宣告可變內容} 之陣列- (IBAction) buildOne:(id)sender;@end
  74. 74. ViewController.m (1/4) 起始多個物件,存於陣列內- (void)viewDidLoad{ ****** 省略部份程式 ****** // 產⽣生 ballAry ballArray = [[NSMutableArray alloc] init]; for(int i=0; i<BallNumber; i++) { MYView *tempView = [[MYView alloc] initImage:CGRectMake(150.0f, 10.0f, 64.0f, 64.0f) filename:@"3d_ball.png"]; tempView.backgroundColor = [UIColor clearColor]; [ballArray addObject:tempView]; } // 從陣列內產⽣生物件 for(MYView *obj in ballArray) { [self.view addSubview:obj]; } ****** 省略部份程式 ******}
  75. 75. ViewController.m (2/4)陣列內各個球的移動及碰撞處理- (void) gameLoop: (NSTimer *)theTimer{ NSMutableArray *objectsToDelete = [NSMutableArray array]; // 移動 for(MYView *obj in ballArray) { [obj move]; // 檢查碰指到炸彈的處理 float dist = sqrtf(powf(obj.center.x-imageBomb.center.x, 2) +powf(obj.center.y-imageBomb.center.y, 2)); if(dist<(obj.frame.size.width/2+imageBomb.frame.size.width/2)) { // 碰撞後刪除球 [obj removeFromSuperview]; // [ballArray removeObject:obj]; // 注意:此為錯誤⽤用法 [objectsToDelete addObject:obj]; } } [ballArray removeObjectsInArray:objectsToDelete]; ****** 省略部份程式 ******}
  76. 76. ViewController.m (3/4) 球與球的碰撞處理- (void) gameLoop: (NSTimer *)theTimer{ 取得兩兩不同的 ****** 省略部份程式 ****** 的陣列元素 // 兩球間之碰撞檢查及處理 for(int i=0; i<[ballArray count]-1; i++) { for(int j=i+1; j<[ballArray count]; j++) { MYView *obj1 = [ballArray objectAtIndex:i]; MYView *obj2 = [ballArray objectAtIndex:j]; [self checkHitAndBounce:obj1 :obj2]; } }}
  77. 77. ViewController.m (4/4) 產⽣生新的球- (IBAction) buildOne:(id)sender{ MYView *newView = [[MYView alloc] initImage:CGRectMake(50.0f, 50.0f, 64.0f, 64.0f) filename:@"3d_ball.png"]; newView.backgroundColor = [UIColor clearColor]; [ballArray addObject:newView]; 陣列內增加元素 [self.view addSubview:newView];} 置於畫⾯面上
  78. 78. 數種繪圖及動畫 APIUIKit Quartz 2D OpenGL ES
  79. 79. Quartz 2D
  80. 80. painters model• canvas• page• context
  81. 81. output device
  82. 82. Current transformation matrix (CTM)• Quartz accomplishes device independence with a separate coordinate system - user space - mapping it to the coordinate system of the output device - device space - using the current transformation matrix, or CTM.• The current transformation matrix is a particular type of matrix called an affine transform, which maps points from one coordinate space to another by applying translation, rotation, and scaling operations. (move, rotate, resize)
  83. 83. Project QV136 Quartz2D 基本繪圖指令 動畫精靈 (sprite) 概念 應標變換
  84. 84. Quartz2D 繪圖程式的基本架構 Shape1View.m (1/2)- (void)drawRect:(CGRect)rect{ // 取得圖像內⽂文,並保存它的狀態 CGContextRef context = UIGraphicsGetCurrentContext(); CGContextSaveGState(context); // 重設轉換設定 CGAffineTransform t = CGContextGetCTM(context); t = CGAffineTransformInvert(t); CGContextConcatCTM(context, t); // 繪圖 CGContextBeginPath(context); CGContextSetRGBFillColor(context, 0.0f, 0.0f, 1.0f, 1.0f); CGContextAddRect(context, CGRectMake(0.0f, 0.0f, 100.0f, 150.0f)); CGContextClosePath(context); CGContextDrawPath(context, kCGPathFill); ****** 省略部分程式 ****** // 還原圖像內⽂文 CGContextRestoreGState(context);}
  85. 85. Shape1View.m (2/2)// 繪圖CGContextBeginPath(context);CGContextSetRGBFillColor(context, 0.0f, 0.0f, 1.0f, 1.0f);CGContextAddRect(context, CGRectMake(0.0f, 0.0f, 100.0f, 150.0f));CGContextClosePath(context);CGContextDrawPath(context, kCGPathFill);// 繪圖CGContextBeginPath(context);CGContextSetRGBFillColor(context, 1.0f, 0.0f, 0.0f, 1.0f);CGContextMoveToPoint(context, 0.0f, 150.0f);CGContextAddLineToPoint(context, 100.0f, 150.0f);CGContextAddLineToPoint(context, 50.0f, 200.0f);CGContextAddLineToPoint(context, 0.0f, 150.0f);CGContextClosePath(context);CGContextDrawPath(context, kCGPathFill);CGContextClosePath(context);CGContextDrawPath(context, kCGPathFill);
  86. 86. ViewController.m#import "ViewController.h"#import "Shape1View.h"#import "Shape2View.h"#import "Shape3View.h"@implementation ViewController- (void)viewDidLoad{ [super viewDidLoad]; Shape1View *shape1 = [[Shape1View alloc] initWithFrame:self.view.frame]; shape1.backgroundColor = [UIColor clearColor]; [self.view addSubview:shape1]; ****** 省略部分程式 ******}
  87. 87. Shape2View加⼊入Timer及按下互動 Shape3View 加⼊入座標變換
  88. 88. Project QV137動畫精靈 (sprite) 概念 Quartz 2D(含座標變換) UIView (含 NSTimer)在主迴圈和 sprite 中的觸控⽐比較
  89. 89. 按空⽩白處會產⽣生新物件 按物體會變換顏⾊色 按三次後會消失
  90. 90. ShapeView.h@interface ShapeView : UIView{ NSTimer *timer; CGFloat x, y, r; CGFloat colorR, colorG, colorB; CGFloat rotation, rotationInc; int cnt;}
  91. 91. - (id)initWithFrame:(CGRect)frame ShapeView.m (1/2){ self = [super initWithFrame:frame]; if (self) { timer = [NSTimer scheduledTimerWithTimeInterval:1/30.0 target:self selector:@selector(move) userInfo:nil repeats:YES]; r = 80.0f; x = 0.0f; y = 0.0f; colorR = (CGFloat)(arc4random() % 100)/100.0f; colorG = (CGFloat)(arc4random() % 100)/100.0f; colorB = (CGFloat)(arc4random() % 100)/100.0f; rotation = 0.0f; rotationInc = (CGFloat)(arc4random() % 100)/100.0f / 10.0f; cnt = 0; } return self;} 會⾃自⼰己動的動畫精靈-(void) move{ rotation += rotationInc; [self setNeedsDisplay];}
  92. 92. - (void)drawRect:(CGRect)rect{ // 取得圖像內⽂文,並保存它的狀態 ShapeView.m CGContextRef context = UIGraphicsGetCurrentContext(); (2/2) CGContextSaveGState(context); // 重設轉換設定 CGAffineTransform t = CGContextGetCTM(context); t = CGAffineTransformInvert(t); t = CGAffineTransformTranslate(t, x+r/2, y+r/2); t = CGAffineTransformRotate(t, rotation); //t = CGAffineTransformScale (t, sinf(rotation), sinf(rotation)); CGContextConcatCTM(context, t); // 繪圖 (與座標位置無關) CGContextBeginPath(context); CGContextSetRGBFillColor(context, colorR, colorG, colorB, 1.0f); CGContextAddEllipseInRect(context, CGRectMake(x-r/2, y-r/2, r, r)); CGContextClosePath(context); CGContextDrawPath(context, kCGPathFill); CGFloat r2 = r / sqrtf(2.0f); CGContextBeginPath(context); CGContextSetRGBFillColor(context, 0.0f, 0.0f, 0.0f, 0.3f); CGContextAddRect(context, CGRectMake(x-r2/2, y-r2/2, r2, r2)); CGContextClosePath(context); CGContextDrawPath(context, kCGPathFill); // 還原圖像內⽂文 CGContextRestoreGState(context);}
  93. 93. -(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{ colorR = (CGFloat)(arc4random() % 100)/100.0f; colorG = (CGFloat)(arc4random() % 100)/100.0f; colorB = (CGFloat)(arc4random() % 100)/100.0f; cnt ++; if(cnt==3) { ShapeView.m [self removeFromSuperview]; }} ViewController.m 此為兩個不同物件的 touch event- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{ UITouch *myTouch = [touches anyObject]; CGPoint point = [myTouch locationInView:self.view]; ShapeView *shape = [[ShapeView alloc] initWithFrame:CGRectMake(point.x-40, point.y-40, 80, 80)]; shape.backgroundColor = [UIColor clearColor]; [self.view addSubview:shape];}
  94. 94. 範例觀摩:QuartzFun, GLFun ref: ch.14
  95. 95. 範例觀摩:QuartzDemo
  96. 96. ............

×