|
Июн
06
|
В продолжении статьи, первую часть которой можно найти здесь мы мы рассмотрим следующие моменты:
- динамическая загрузка изображения с “UIImageView“,
- работа с массивами
Шаг 1
Откройте созданный в части 1 проект “Ball“.
Шаг 2
Импортируйте еще одно изображение в группу “Resources” (можно воспользоваться прежним, но гораздо интереснее будет добавить новое).
Шаг 3
Для хранения второго мяча нам потребуется еще одна переменная, поэтому откройте файл “BallViewController.h“. Назовем второй мяч “mBall2” (не самое удачное имя — в реальном приложении лучше иметь дело с массивами).
1 2 3 4 5 6 7 8 9 10 11 | #import @class Ball; @interface BallViewController : UIViewController { IBOutlet Ball* mBall; Ball* mBall2; } @property(retain, nonatomic) IBOutlet Ball* mBall; @property(retain, nonatomic) Ball* mBall2; @end |
Обратите внимание: модификатор “IBOutlet” мы не включаем, поскольку не будем ссылаться на “mBall2” из редактора Interface Builder. Впрочем, вреда от его присутствия не будет.
Шаг 4
Теперь все готово к загрузке изображения. Отредактируйте “BallViewController.m” и воспользуйтесь для загрузки методом “initWithImage“. Как и в предыдущем случае, оптимальным местом инициализации будет функция “viewDidLoad“.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | #import "BallViewController.h" #import "Ball.h" @implementation BallViewController @synthesize mBall; @synthesize mBall2; // Внедряем viewDidLoad для дополнительной настройки после загрузки представления, обычно из nib-файла. - (void)viewDidLoad { [super viewDidLoad]; [mBall setSpeedX:5 Y:5]; mBall2=[[Ball alloc] initWithImage:[UIImage imageNamed:@"ball2.png"]]; [self.view addSubview:mBall2]; [mBall2 setSpeedX:10 Y:10]; mBall2.center=self.view.center; [NSTimer scheduledTimerWithTimeInterval:1.0/30.0 target:self selector:@selector(moveBall) userInfo:nil repeats:YES]; } |
Поскольку “Ball” — производная “UIImageView“, для загрузки изображения можно воспользоваться “UIImageView::initWithImage“. Однако, раз “initWithImage” в качестве собственного параметра принимает объект “UIImage” , сначала нужно создать “UIImage” для передачи “initWithImage“.
1 | mBall2=[[Ball alloc] initWithImage:[UIImage imageNamed:@"ball2.png"]]; |
После этого добавляем “Ball” в текущее представление (т.е. к полноценному интерфейсу), размещая его по центру — и вновь посредством “addSubview“.
1 2 | [self.view addSubview:mBall2]; mBall2.center=self.view.center; |
Для скорости я указал значение 10, но число может быть и другим. При нажатии кнопки “Build and Run” мяч должен появиться в центре экрана.
Шаг 5
Теперь приступим к перемещению мяча, вызвав ту же функцию “move”, которую декларировали в классе “Ball“. Как видим, выделение и расширение “UIImageView” упрощает наращивание функциональности, снимая необходимость в переписывании отвечающего за перемещение изображения кода.
1 2 3 4 5 | -(void)moveBall { [mBall move]; [mBall2 move]; } |
И заодно неплохо бы освободить мяч методом “dealloc“.
1 2 3 4 5 | - (void)dealloc { [super dealloc]; [mBall dealloc]; [mBall2 dealloc]; } |
Загрузить код проекта здесь.
При динамической загрузке изображения кода требуется больше, чем при загрузке через редактор IB. Но есть и преимущества — улучшенный контроль изображения и простота создания многочисленных его экземпляров. Этим и займемся.
Хранение объектов в массиве
Хранить многочисленные объекты мы будем в “NSMutableArray“. Еще один доступный в Cocoa вариант — массив “NSArray“, похожий, но не допускающий изменений. Для нашего проекта было бы достаточно и его, но в реальной игре предпочтительнее “NSMutableArray“, поскольку состояние игры меняется достаточно часто.
Откройте “BallViewController.h” и добавьте переменную “NSMutableArray“, удалив имеющиеся переменные “Ball“, поскольку их мы поместим в массив. Результат должен выглядеть так:
1 2 3 4 5 6 7 8 9 | #import @class Ball; @interface BallViewController : UIViewController { NSMutableArray *mBallArray; } @property(retain, nonatomic) NSMutableArray* mBallArray; @end |
Открыв “BallViewController.xib“, удалите относящийся к мячу объект “ImageView” (добавленный в первой части урока). Больше мы не будем работать с редактором IB, вместо этого создавая все мячи динамически.
Теперь добавим в массив объекты “Ball“. Откройте “BallViewController.m” и внесите в файл следующий код:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | #import "BallViewController.h" #import "Ball.h" @implementation BallViewController @synthesize mBallArray; // Внедряем viewDidLoad для дополнительной настройки после загрузки представления, обычно из nib-файла. - (void)viewDidLoad { [super viewDidLoad]; mBallArray = [[NSMutableArray alloc] init]; int i; for (i = 0; i < 10; i++) { Ball* ball=[[Ball alloc] initWithImage:[UIImage imageNamed:@"ball.png"]]; [mBallArray addObject:ball]; [self.view addSubview:ball]; int speed=random() % 10; [ball setSpeedX:speed Y:speed]; ball.center=self.view.center; } [NSTimer scheduledTimerWithTimeInterval:1.0/30.0 target:self selector:@selector(moveBall) userInfo:nil repeats:YES]; } |
С помощью цикла создаем 10 мячей, добавляя каждый в массив посредством “addObject“. С помощью функции “random” задаем для них случайную скорость (параметр “speed“). Обратите внимание на вызовы функции “addObject“, необходимые для добавления мячей в массив.
Для активизации мячей перемещаемся по массиву, вызывая для каждого объекта функцию “move“. Я выполнил задачу с помощью “objectAtIndex“, но это может быть и нумератор.
1 2 3 4 5 6 7 8 9 | -(void)moveBall { int i; int numberOfBalls=[mBallArray count]; for (i = 0; i { Ball* ball=[mBallArray objectAtIndex:i]; [ball move]; } } |
Не пренебрегая правилами хорошего тона, освободим все объекты с помощью “dealloc“.
1 2 3 4 5 6 7 8 9 10 11 | - (void)dealloc { [super dealloc]; int i; int numberOfBalls=[mBallArray count]; for (i = 0; i { Ball* ball=[mBallArray objectAtIndex:i]; [ball dealloc]; } [mBallArray dealloc]; } |
Настало время кнопки “Build and Run“. На экране должны с разной скоростью перемещаться мячи, отскакивая от краев экрана. Внимание: видимых мячей может быть меньше 10 из-за идентичной скорости некоторых. Чтобы исправить этот момент, расширьте диапазон случайных значений.

P.S. При наличии описанной ниже ошибки удалите “ImageView” из редактора IB. (Откройте “BallViewController.xib” и удалите “ImageView” для мяча, поскольку объект больше не используется, а переменная “mBall” отсутствует.)
Завершение работы программы из-за невыявленного исключения ‘NSUnknownKeyException’, reason: ‘[ setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key mBall.’
Оптимизация
Память iPhone ограничена, поэтому при создании приложений задействовать ее нужно эффективно. Нашли возможности для оптимизации? Обратите внимание на то, как для каждого объекта “Ball” создается отдельный объект “UIImage“. Предпочтительнее использовать его повторно, например, так:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | - (void)viewDidLoad { [super viewDidLoad]; mBallArray = [[NSMutableArray alloc] init]; int i; UIImage* image=[UIImage imageNamed:@"ball.png"]; for (i = 0; i < 10; i++) { Ball* ball=[[Ball alloc] initWithImage:image]; [mBallArray addObject:ball]; [self.view addSubview:ball]; int speed=random() % 10; [ball setSpeedX:speed Y:speed]; ball.center=self.view.center; } [NSTimer scheduledTimerWithTimeInterval:1.0/30.0 target:self selector:@selector(moveBall) userInfo:nil repeats:YES]; } |
Работа с несколькими изображениями
Предлагаю загрузить дополнительный объект “UIImage” и переключаться между ними. В представленном ниже коде я загружаю “ball1.png” и “ball2.png“, после чего циклически их меняю.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | - (void)viewDidLoad { [super viewDidLoad]; mBallArray = [[NSMutableArray alloc] init]; UIImage* image1=[UIImage imageNamed:@"ball1.png"]; UIImage* image2=[UIImage imageNamed:@"ball2.png"]; int i; for (i = 0; i < 10; i++) { UIImage* image; if ((i%2)==0) image=image1; else image=image2; Ball* ball=[[Ball alloc] initWithImage:image]; [mBallArray addObject:ball]; [self.view addSubview:ball]; int speed=random() % 10; [ball setSpeedX:speed Y:speed]; ball.center=self.view.center; } [NSTimer scheduledTimerWithTimeInterval:1.0/30.0 target:self selector:@selector(moveBall) userInfo:nil repeats:YES]; } |
На этом все. Успехов вам!


Июнь 9th, 2009 at 10:55
[...] продолжение темы, рассмотренной в частях 1 и 2, мы будем и дальше работать с созданным ранее [...]