I os 142. 課程⼤大綱
• ⽤用 Processing 學習繪圖程式邏輯
• QV081:球移動反彈
• QV082:Objective-C 的物件思維
• Objective-C 類別與⾃自訂類別
• QV080:⾃自訂類別
• QV084:⾃自訂類別,移動碰撞
• QV085:兩個物件互相碰撞
• QV086:三個物件 (動作定義在物件上)
• QV087:⽤用陣列處理更多的球
• Quartz 2D
• QV136:Quartz 2D
• QV137:動畫精靈 (Sprite)
• Samples:QuartzFun, GLFun, QuartzDemo
5. 程式結構
• void setup()
{
// 設定的部份
}
• void draw()
{
// 時間迴圈的部份
}
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. 顏⾊色指令
• fill( R, G, B )
• noFill()
• stroke( R, G, B)
• strokeWeight( w )
• noStroke()
16. 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
17. 常數宣告 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) 時間間隔
18. 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;
}
}
23. 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)
24. #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];
}
25. 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;
}
}
32. #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
34. 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
36. 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.
}
38. 程式參考 範例:讓此炸彈掉落
- (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 為⾃自訂類別的物件
42. MYView.h
⾃自定類別的宣告
#import <UIKit/UIKit.h>
@interface MYView : UIView
{
UIImage *img;
}
- (id) initImage:(CGRect)frame filename:(NSString *)name;
@end
43. ⾃自定類別的實作 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
45. 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];
}
46. 檢查碰撞,
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;
}
}
51. ViewController.h
⾃自定類別的宣告
#import <UIKit/UIKit.h>
#import "MYView.h"
@interface ViewController : UIViewController
{
MYView *imageView1;
float incX1, incY1;
MYView *imageView2; 宣告兩個物件
float incX2, incY2;
} 以及各別物件的移動量
@end (不是很聰明的⽤用法)
52. - (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];
****** 省略部份程式 ******
}
53. 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;
}
****** 省略部份程式 ******
}
54. - (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;
}
}
59. 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
移動的程式
60. 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
61. 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;
}
} 有幾個數值的⽤用法不是那麼地漂亮?
63. 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];
****** 省略部份程式 ******
}
64. ViewController.m (2/5)
程式主要迴圈:球移動
多呼叫物件內的 method
- (void) gameLoop: (NSTimer *)theTimer
{
[imageView move];
[ball1 move];
[ball2 move];
****** 省略部份程式 ******
}
65. 碰撞處理⽅方法之⼀一 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;
}
}
66. 碰撞處理⽅方法之⼆二 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]) 傳回兩物件是否碰撞
{
****** 省略部份程式 ******
}
}
67. 碰撞處理⽅方法之三 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];
}
72. 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
73. #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
74. 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
76. 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];
}
****** 省略部份程式 ******
}
77. 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];
****** 省略部份程式 ******
}
78. 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];
}
}
}
79. 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];
}
置於畫⾯面上
84. 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)
86. 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);
}
87. 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);
93. - (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];
}
94. - (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);
}
95. -(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];
}