一、效果实现
简单实现了一个消灭病毒的小效果,画面略显粗糙,多多见谅

控制球复位

二、操作杆实现
实现拖动小球,获取当前小球的旋转方向,将旋转的方向传递出去,旋转“坦克”进行攻击“病毒”。
#import "directionoptionview.h"
@interface directionoptionview()
//方向指示器滚珠
@property(nonatomic,strong) uiview * ball;
@end
@implementation directionoptionview
- (instancetype)initwithframe:(cgrect)frame changedirectionblock:(changedirectionblock)changedirectionblock
{
if (self = [super initwithframe:frame]) {
self.changedirectionblock = changedirectionblock;
[self makeview];
[self addpan];
}
return self;
}
//添加拖拽手势
- (void)addpan{
uipangesturerecognizer * pan = [[uipangesturerecognizer alloc] initwithtarget:self action: @selector(panaction:)];
[self addgesturerecognizer:pan];
}
- (void)panaction:(uipangesturerecognizer *)pan
{
switch (pan.state) {
case uigesturerecognizerstatebegan:
{
cgpoint point = [pan locationinview:**self**];
self.ball.alpha = 1;
[self movewithpoint:point];
}
break;
case uigesturerecognizerstatechanged:
{
cgpoint point = [pan locationinview:self];
[self movewithpoint:point];
}
break;
case uigesturerecognizerstateended:
{
cgpoint point = [pan locationinview:self];
[self resetballpositionwithendpoint:point];
}
break;
default:
break;
}
}
//小球复位
- (void)resetballpositionwithendpoint:(cgpoint)point
{
self.changedirectionblock(0);
[uiview animatewithduration:0.2 animations:^{
self.ball.center = cgpointmake((self.frame.size.width / 2.0), (self.frame.size.height / 2.0));
self.ball.alpha = 0.4;
}];
}
//根据控制球位置获取当前旋转角度
- (void)movewithpoint:(cgpoint)point
{
cgfloat distancecircle = (self.ball.frame.size.width / 2.0);
cgfloat x = point.x;
cgfloat y = point.y;
cgfloat dx = x - self.frame.size.width / 2.0;
cgfloat dy = y - self.frame.size.height / 2.0;
cgfloat rotation = atan2(dx,dy);
cgfloat r = self.frame.size.width / 2.0;
cgfloat rx = (r - distancecircle) * sin(rotation) + r;
cgfloat ry = (r - distancecircle) * cos(rotation) + r;
//防止控制球越界
if ((sqrt((dx * dx) + (dy * dy))) > (r - distancecircle)) {
x = rx;
y = ry;
}
//用block形式向外界暴露当前控制球相对于屏幕上方的角度
self.changedirectionblock(-rotation + m_pi);
self.ball.center = cgpointmake(x, y);
}
- (void)makeview{
//进行倒角
self.layer.maskstobounds = yes;
self.layer.cornerradius = self.frame.size.width / 2.0;
self.backgroundcolor = [[uicolor grouptableviewbackgroundcolor] colorwithalphacomponent:0.7];
//添加控制球
[self addsubview:self.ball];
}
//控制球
- (uiview *)ball
{
if (!_ball) {
cgsize size = cgsizemake(45, 45);
_ball = [[uiview alloc] initwithframe:cgrectmake((self.frame.size.width - size.width) / 2.0, (self.frame.size.height - size.height) / 2.0, size.width, size.height)];
_ball.alpha = 0.4;
_ball.layer.maskstobounds = yes;
_ball.layer.cornerradius = _ball.frame.size.width / 2.0;
_ball.backgroundcolor = [uicolor lightgraycolor];
}
return _ball;
}
@end
三、发射子弹及碰撞检测
1、发射子弹
//根据当前角度,预判子弹动画的结束位置
- (nsarray *)preparebulletpath
{
cgpoint center = self.center;
cgfloat maxlength = sqrt(([uiscreen mainscreen].bounds.size.width * [uiscreen mainscreen].bounds.size.width) + ([uiscreen mainscreen].bounds.size.height * [uiscreen mainscreen].bounds.size.height));
cgfloat endy = sin(self.angle - m_pi / 2.0) * maxlength + center.y;
cgfloat endx = cos(self.angle - m_pi / 2.0) * maxlength + center.x;
cgpoint endpoint = cgpointmake(endx, endy);
return @[@(center),@(endpoint)];
}
- (void)fir
{
cgfloat bulletwidth = 10;
bulletview * lastbulletview = self.bulletarr.count > 0 ? self.bulletarr.lastobject : nil;
if (!lastbulletview) {
bulletview * view = [[bulletview alloc] initwithframe:cgrectmake((self.frame.size.width - bulletwidth) / 2.0, 0,bulletwidth,bulletwidth)];
view.points = [self preparebulletpath];
[self.superview insertsubview:view belowsubview:self];
[self.bulletarr addobject:view];
view.center = [view.points[0] cgpointvalue];
[uiview animatewithduration:1 animations:^{
view.center = [view.points[1] cgpointvalue];
} completion:^(bool finished) {
[view removefromsuperview];
[self.bulletarr removeobject:view];
}];
}
}
fir 本身是一个定时器事件,在里面添加一些创建子弹的逻辑,位置移动还是用了最简单的 uiview 的 animatewithduration 方法,但是注意这里面通过 frame 进行碰撞检测是获取不到,所以,添加了 cadisplaylink 屏幕刷新事件来检测子弹视图的 layer.presentationlayer.frame来进行与病毒的 frame 进行检测屏幕位置是否包含。
2、检测碰撞
bool cgrectintersectsrect(cgrect rect1, cgrect rect2) 检测碰撞的方法
//添加屏幕刷新事件监听
- (void)addscreenrefreshaction
{
self.displaylink = [cadisplaylink displaylinkwithtarget:self selector: @selector(update)];
[self.displaylink addtorunloop:[nsrunloop currentrunloop] formode:nsrunloopcommonmodes];
}
- (void)update
{
[self.bulletarr enumerateobjectsusingblock:^(bulletview * bulletview, nsuinteger idx, bool * _nonnull stop) {
[self.virusarr enumerateobjectsusingblock:^(virusview * virusview, nsuinteger idx, bool * _nonnull stop) {
//检测碰撞
if (cgrectintersectsrect(bulletview.layer.presentationlayer.frame, virusview.frame)) {
[bulletview removefromsuperview];
[self.bulletarr removeobject:bulletview];
[virusview attacked];
if ([virusview isdie]) {
[virusview removefromsuperview];
[self.virusarr removeobject:virusview];
}
}
}];
}];
if (!self.virusarr.count) {
[self createvirusview];
}
}
四、添加病毒及消灭动画
1、随机创建病毒
- (void)createvirusview
{
int width = arc4random() % 30 + 50;
int x = arc4random() % ([[nsnumber numberwithfloat:[uiscreen mainscreen].bounds.size.width] integervalue] - width);
int y = arc4random() % ([[nsnumber numberwithfloat:[uiscreen mainscreen].bounds.size.height / 2.0] integervalue]);
virusview * virusview = [[virusview alloc] initwithframe:cgrectmake(x, y, width, width)];
[self.superview addsubview:virusview];
[self.virusarr addobject:virusview];
}
2、消灭动画
添加了一点粒子效果,显示病毒消散动画
- (void)fireexplode
{
caemitterlayer * emitter = [caemitterlayer layer];
emitter.frame = self.frame;
[self.superview.layer addsublayer:emitter];
emitter.rendermode = kcaemitterlayeradditive;
emitter.emitterposition = cgpointmake(emitter.frame.size.width*0.5, emitter.frame.size.height*0.5);
caemittercell *cell = [[caemittercell alloc] init];
cell.contents = ( __bridge id)[uiimage imagenamed:@"v4"].cgimage;
cell.birthrate = 1;//出生率
cell.lifetime = 0.7;//生命周期
cell.emissionlongitude = - m_pi_2;
cell.emissionrange = m_pi_2;
cell.alphaspeed = -0.2;
cell.velocity = 10;//速度
cell.scale = 0.15;//缩放倍数
emitter.emittercells = @[cell];
dispatch_after(dispatch_time(dispatch_time_now, (int64_t)(0.6 * nsec_per_sec)), dispatch_get_main_queue(), ^{
[emitter removefromsuperlayer];
});
}
五、思考与总结
添加 uiview 的 animatewithduration 方法后,这里用的是屏幕刷新检测,来获取当前控件的 layer.presentationlayer.frame 来检测碰撞,其他逻辑都相对简单。
以上就是ios 简单的操作杆旋转实现示例详解的详细内容,更多关于ios 操作杆旋转的资料请关注代码网其它相关文章!
发表评论