Настройка коллизионного пути UIView в iOS 9
В iOS 9 Apple представила collisionBoundsType
в UIKit-Dynamics
,
У меня нет проблем при установке этого UIDynamicItemCollisionBoundsTypeRectangle
или когда я установил это UIDynamicItemCollisionBoundsTypeEllipse
,
Снимок экрана ниже взят из игры, в которой я играю collisionBoundsType
игрока установлен на прямоугольник, а мяч на эллипс:
Тем не менее, когда я установил collisionBoundsType
по пути я получаю странное поведение, как видно здесь:
Вид выше, чем должен, и тело столкновения находится справа от того места, где оно должно быть.
В настоящее время у меня есть collisionBoundingPath
установить на это:
- (UIBezierPath *)collisionBoundingPath
{
maskPath = [[UIBezierPath alloc] init];
[maskPath addArcWithCenter:CGPointMake(SLIME_SIZE, SLIME_SIZE) radius:SLIME_SIZE startAngle:0*M_PI endAngle:M_PI clockwise:NO];
return maskPath;
}
Кроме того, моя функция drawRect выглядит так:
- (void) drawRect:(CGRect)rect
{
if (!_color){
[self returnDefualtColor];
}
if (!maskPath) maskPath = [[UIBezierPath alloc] init];
[maskPath addArcWithCenter:CGPointMake(SLIME_SIZE, SLIME_SIZE) radius:SLIME_SIZE startAngle:0*M_PI endAngle:M_PI clockwise:NO];
[_color setFill];
[maskPath fill];
}
Почему это происходит? Как установить путь тела столкновения так же, как рисунок на виде?
Кроме того, красный цвет является просто фоном вида (т.е. view.backgroundColor = [UIColor redColor];
).
3 ответа
Из документации по UIDynamicItem здесь следующее утверждение о системе координат для путей, по-видимому, представляет то, что не так:
Созданный вами объект пути должен представлять собой выпуклый многоугольник с намоткой против часовой стрелки или по часовой стрелке, и путь не должен пересекаться сам по себе. Точка (0, 0) пути должна находиться в центральной точке соответствующего динамического элемента. Если центральная точка не соответствует началу пути, поведение при столкновении может работать не так, как ожидалось.
Здесь говорится, что (0,0)
поскольку путь ДОЛЖЕН быть центральной точкой.
Я думаю, что центр вашей траектории дуги должен быть (0,0)
и не (SLIME_SIZE/2,SLIME_SIZE/2)
, Возможно, вы установили ширину и высоту фрейма UIView на SLIME_SIZE, а не SLIME_SIZE*2
?
SLIME_SIZE
действительно, кажется, определить радиус, поэтому ширина кадра должна быть SLIME_SIZE*2
, Если это установлено как SLIME_SIZE
, тогда это объясняет, почему вам нужно перевести SLIME_SIZE/2
как исправление.
Отладка физики это вещь. Вероятно, это не то, о чем пользователи iOS склонны много думать, поскольку они обычно делают очень простые вещи с UIKit Dynamics. Это немного стыдно, так как это один из лучших аспектов последних выпусков iOS, и он предлагает по-настоящему увлекательный способ создания впечатляющего пользовательского опыта.
Итак... как отлаживать физику?
Один из способов - мысленно представить, что происходит, а затем соотнести это с тем, что происходит, и найти диссонанс между воображаемым и реальным, а затем решить проблему с помощью сочетания процессов устранения, умственного или реального испытания, ошибки и дедукции. До тех пор, пока проблема не будет определена и решена.
Другой способ заключается в том, чтобы иметь визуальное представление обо всем, что было создано и взаимодействовало, обеспечивая достаточную обратную связь для более быстрого определения характера и степени элементов, их взаимосвязей и инцидентов / событий, а также для решения проблем буквальным зрением.
С этой целью с момента их появления были созданы различные визуальные отладчики и создатели симуляций физики.
К сожалению, в iOS нет такого экранного редактора или "редактора сцен" для UIKit Dynamics, и то, что доступно для такого рода визуальной отладки в Sprite Kit и Scene Kit, в лучшем случае элементарно.
Однако есть CALayers, которые присутствуют во всех представлениях UIKit, в которые CAShapeLayers можно создавать и рисовать вручную для точного представления любых физических элементов, их границ, их якорей и отношений.
CAShapeLayers являются "контейнером" для CGPath и могут иметь разные цвета для контура и заливки, а также более одного элемента CGPath в одном CAShapeLayer.
И, процитировать великого Роба:
"Если вы добавляете CAShapeLayer в качестве слоя в представление, вам не нужно реализовывать какой-либо код для рисования самостоятельно. Просто добавьте CAShapeLayer, и все готово. Например, вы можете даже позже изменить путь, и он будет автоматически перерисовать его для вас. CAShapeLayer избавит вас от трудностей написания ваших собственных процедур drawRect или drawLayer."
Если у вас огромное количество взаимодействующих элементов и вы хотите их отладить, могут возникнуть проблемы с производительностью CAShapeLayer, после чего вы можете использовать shouldRasterize для преобразования каждого в растровое изображение и получения значительного улучшения производительности при превышении ограничений, созданных " динамические "возможности CAShapeLayers.
Кроме того, для представления таких вещей, как ограничения и соединения, существует простой процесс создания пунктирных линий на CAShapeLayers, просто устанавливая свойства. Вот основы настройки свойств CAShapeLayer и способ использования массива для создания 5-5-5 пунктирного контура с штрихом блока, шириной 3, без заливки.
CAShapeLayer *shapeLayer = [CAShapeLayer layer];
[shapeLayer setBounds:self.bounds];
[shapeLayer setPosition:self.center];
[shapeLayer setFillColor:[[UIColor clearColor] CGColor]];
[shapeLayer setStrokeColor:[[UIColor blackColor] CGColor]];
[shapeLayer setLineWidth:3.0f];
[shapeLayer setLineJoin:kCALineJoinRound];
[shapeLayer setLineDashPattern:
[NSArray arrayWithObjects:[NSNumber numberWithInt:10],
[NSNumber numberWithInt:5],nil]];
Я смог ответить на это, изменив:
- (UIBezierPath *)collisionBoundingPath
{
maskPath = [[UIBezierPath alloc] init];
[maskPath addArcWithCenter:CGPointMake(SLIME_SIZE, SLIME_SIZE) radius:SLIME_SIZE startAngle:0*M_PI endAngle:M_PI clockwise:NO];
return maskPath;
}
чтобы:
- (UIBezierPath *)collisionBoundingPath
{
maskPath = [[UIBezierPath alloc] init];
[maskPath addArcWithCenter:CGPointMake(SLIME_SIZE / 2, SLIME_SIZE / 2) radius:SLIME_SIZE startAngle:0*M_PI endAngle:M_PI clockwise:NO];
return maskPath;
}
Основное отличие состоит в том, что я изменил центр дуги, разделив значения x и y на 2.