ios joystick 虚拟摇杆实现 ( 非 Cocos2d )

本文 Demo 代码已经上传 Github

https://github.com/pyzhangxiang/joystick-iosiphone

ios 上控制人物的移动,一是可以利用加速传感器计算设备的倾角来控制,另一个就是使用虚拟摇杆。使用传感器的方法不需要额外的 UI 开发,相对简单,但是并不一定适合所有的游戏。下面分享一个自己做的虚拟摇杆。

网上有一些模拟摇杆的实现,但都是基于 Cocos2d 的,我这个就不在 Cocos2d 上做了。


先上个 demo 的效果图。

joystick 虚拟摇杆 普通状态

joystick 虚拟摇杆 操作移动

左下角的就是虚拟摇杆了。为它单独做一个类,继承UIView

@interface JoyStickView : UIView
{
    IBOutlet UIImageView *stickViewBase;
    IBOutlet UIImageView *stickView;
    
    UIImage *imgStickNormal;
    UIImage *imgStickHold;
    
    CGPoint mCenter;
}

mCenter 是摇杆的中心位置,我的摇杆图片都是 128 * 128 的,所以 mCenter 在初始化函数中设置为 (64, 64)

stickViewBase 是摇杆的底盘

stickView     是摇杆的操纵杆

这两个 UIImageView 都直接在 xib 中配置好。我的底盘是不变的,所以在 xib 中直接指定了图片。而操纵杆有两种状态,普通状态和手握状态。手指没有触摸摇杆时,操纵杆处于普通状态,设置 stickView.image = imgStickNormal; 当手触摸摇杆时,设置 stickView.image = imgStickHold;具体的实现在 UIView 的三个 touch event 中进行。

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    stickView.image = imgStickHold;
    [self touchEvent:touches];
}

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
    [self touchEvent:touches];
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    stickView.image = imgStickNormal;
    CGPoint dtarget, dir;
    dir.x = dtarget.x = 0.0;
    dir.y = dtarget.y = 0.0;
    [self stickMoveTo:dtarget];
    
    [self notifyDir:dir];
}

touchesBegan 首先修改摇杆状态。 然后调用另一个函数计算摇杆的位置,这个和 touchesMoved 一样。

touchesEnded 恢复摇杆的状态和位置。

在 touchEvent 里面计算并设置摇杆的位置,见如下代码。

- (void)touchEvent:(NSSet *)touches
{

    if([touches count] != 1)
        return ;
    
    UITouch *touch = [touches anyObject];
    UIView *view = [touch view];
    if(view != self)
        return ;
    
    CGPoint touchPoint = [touch locationInView:view];
    CGPoint dtarget, dir;
    
    // calculate stick direction to the center
    dir.x = touchPoint.x - mCenter.x;
    dir.y = touchPoint.y - mCenter.y;
    double len = sqrt(dir.x * dir.x + dir.y * dir.y);
    if(len < 10.0 && len > -10.0)
    {
        // on center pos
        dtarget.x = 0.0;
        dtarget.y = 0.0;
        dir.x = 0;
        dir.y = 0;
    }
    else
    {
        double len_inv = (1.0 / len);
        dir.x *= len_inv;
        dir.y *= len_inv;
        dtarget.x = dir.x * STICK_CENTER_TARGET_POS_LEN;
        dtarget.y = dir.y * STICK_CENTER_TARGET_POS_LEN;
    }
    [self stickMoveTo:dtarget];
    
    [self notifyDir:dir];
}
代码中 dir 即为摇杆中心到触摸位置的方向,我这里规定当触摸位置离开中心小于 10 的时候,认为摇杆不动。有需要可以根据自己的实际情况修改。如果距离大于 10 ,对 dir 做归一化,然后算一个摇杆和中心位置的偏离 dtarget ,我这里用于计算的常数值 STICK_CENTER_TARGET_POS_LEN 为 20。
最后调用 stickMoveTo 修改摇杆位置,发送摇杆变化的通知给游戏逻辑。
- (void)notifyDir:(CGPoint)dir
{
    NSAutoreleasePool * pool = [[NSAutoreleasePoolalloc] init];
    
    NSValue *vdir = [NSValuevalueWithCGPoint:dir];
    NSDictionary *userInfo = [NSDictionarydictionaryWithObjectsAndKeys:
                              vdir, @"dir", nil];
    
    NSNotificationCenter *notificationCenter = [NSNotificationCenterdefaultCenter];
    [notificationCenter postNotificationName:@"StickChanged"object:niluserInfo:userInfo];
    
    [pool release];
}

- (void)stickMoveTo:(CGPoint)deltaToCenter
{
    // because the original position of stickView is (0, 0)
    // so just set its position to the delta is ok
    CGRect fr = stickView.frame;
    fr.origin = deltaToCenter;
    stickView.frame = fr;
}

 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值