我一直在尝试使用sprite kit,为我的想法构建原型.我一直用一个SKPhysicsJointPin将一串物理体连在一起,制作一根绳子(实际上更像是一条自行车链条,但它已经足够好了).在场景中也有很多球,当我点击它们时我可以放下它们.这导致以下结果:

然而,当我丢掉更多球时,链条似乎无法处理它,并且“打破”:

这是一个movie showing the phenomenon

发生了什么?文档从未建议SKPhysicsJointPin具有有限的最大强度或弹性或类似.这是sprite工具包中的“bug”,还是我使用了错误的方法?

解决方法

我遇到了一个类似于绳子模拟的弹性错误,最终可能会找到一种解决方法.

这是我的绳索界面:

#import <SpriteKit/SpriteKit.h>

@interface ALRope : NSObject

@property(nonatomic,readonly) NSArray *ropeRings;

@property(nonatomic) int ringCount;

@property(nonatomic) CGFloat ringScale;

@property(nonatomic) CGFloat ringsdistance;

@property(nonatomic) CGFloat jointsFrictionTorque;

@property(nonatomic) CGFloat ringsZPosition;

@property(nonatomic) CGPoint startRingPosition;

@property(nonatomic) CGFloat ringFriction;

@property(nonatomic) CGFloat ringRestitution;

@property(nonatomic) CGFloat ringMass;


@property(nonatomic) BOOL shouldEnableJointsAngleLimits;

@property(nonatomic) CGFloat jointsLowerAngleLimit;

@property(nonatomic) CGFloat jointsUpperAngleLimit;



-(instancetype)initWithRingTexture:(SKTexture *)ringTexture;


-(void)buildropeWithScene:(SKScene *)scene;

-(void)adjustRingPositions;

-(SKSpriteNode *)startRing;

-(SKSpriteNode *)lastRing;

@end

绳索实施:

#import "ALRope.h"

@implementation ALRope

{
    SKTexture *_ringTexture;

    NSMutableArray *_ropeRings;
}

static CGFloat const RINGS_disTANCE_DEFAULT = 0;

static CGFloat const JOINTS_FRICTION_TORQUE_DEFAULT = 0;

static CGFloat const RING_SCALE_DEFAULT = 1;

static int const RING_COUNT_DEFAULT = 30;

static CGFloat const RINGS_Z_POSITION_DEFAULT = 1;

static BOOL const SHOULD_ENABLE_JOINTS_ANGLE_LIMITS_DEFAULT = NO;

static CGFloat const JOINT_LOWER_ANGLE_LIMIT_DEFAULT = -M_PI / 3;

static CGFloat const JOINT_UPPER_ANGLE_LIMIT_DEFAULT = M_PI / 3;

static CGFloat const RING_FRICTION_DEFAULT = 0;

static CGFloat const RING_RESTITUTION_DEFAULT = 0;

static CGFloat const RING_MASS_DEFAULT = -1;


-(instancetype)initWithRingTexture:(SKTexture *)ringTexture
{
    if(self = [super init]) {
        _ringTexture = ringTexture;

        //apply defaults
        _startRingPosition = CGPointMake(0,0);
        _ringsdistance = RINGS_disTANCE_DEFAULT;
        _jointsFrictionTorque = JOINTS_FRICTION_TORQUE_DEFAULT;
        _ringScale = RING_SCALE_DEFAULT;
        _ringCount = RING_COUNT_DEFAULT;
        _ringsZPosition = RINGS_Z_POSITION_DEFAULT;
        _shouldEnableJointsAngleLimits = SHOULD_ENABLE_JOINTS_ANGLE_LIMITS_DEFAULT;
        _jointsLowerAngleLimit = JOINT_LOWER_ANGLE_LIMIT_DEFAULT;
        _jointsUpperAngleLimit = JOINT_UPPER_ANGLE_LIMIT_DEFAULT;
        _ringFriction = RING_FRICTION_DEFAULT;
        _ringRestitution = RING_RESTITUTION_DEFAULT;
        _ringMass = RING_MASS_DEFAULT;
    }
    return self;
}


-(void)buildropeWithScene:(SKScene *)scene
{
    _ropeRings = [NSMutableArray new];
    SKSpriteNode *firstRing = [self addRopeRingWithPosition:_startRingPosition underScene:scene];

    SKSpriteNode *lastRing = firstRing;
    CGPoint position;
    for (int i = 1; i < _ringCount; i++) {
        position = CGPointMake(lastRing.position.x,lastRing.position.y - lastRing.size.height - _ringsdistance);
        lastRing = [self addRopeRingWithPosition:position underScene:scene];
    }

    [self addJointsWithScene:scene];
}

-(SKSpriteNode *)addRopeRingWithPosition:(CGPoint)position underScene:(SKScene *)scene
{
    SKSpriteNode *ring = [SKSpriteNode spriteNodeWithTexture:_ringTexture];
    ring.xScale = ring.yScale = _ringScale;
    ring.position = position;
    ring.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:ring.size.height / 2];
    ring.physicsBody.allowsRotation = YES;
    ring.physicsBody.friction = _ringFriction;
    ring.physicsBody.restitution = _ringRestitution;
    if(_ringMass > 0) {
        ring.physicsBody.mass = _ringMass;
    }

    [scene addChild:ring];
    [_ropeRings addobject:ring];
    return ring;
}

-(void)addJointsWithScene:(SKScene *)scene
{
    for (int i = 1; i < _ropeRings.count; i++) {
        SKSpriteNode *nodeA = [_ropeRings objectAtIndex:i-1];
        SKSpriteNode *nodeB = [_ropeRings objectAtIndex:i];
        SKPhysicsJointPin *joint = [SKPhysicsJointPin jointWithBodyA:nodeA.physicsBody
                                                               bodyB:nodeB.physicsBody
                                                              anchor:CGPointMake(nodeA.position.x,nodeA.position.y - (nodeA.size.height + _ringsdistance) / 2)];
        joint.frictionTorque = _jointsFrictionTorque;
        joint.shouldEnableLimits = _shouldEnableJointsAngleLimits;
        if(_shouldEnableJointsAngleLimits) {
            joint.lowerAngleLimit = _jointsLowerAngleLimit;
            joint.upperAngleLimit = _jointsUpperAngleLimit;
        }
        [scene.physicsWorld addJoint:joint];
    }
}

//workaround for elastic effect should be called from didSimulatePhysics
-(void)adjustRingPositions
{
    //based on zRotations of all rings and the position of start ring adjust the rest of the rings positions starting from top to bottom
    for (int i = 1; i < _ropeRings.count; i++) {
        SKSpriteNode *nodeA = [_ropeRings objectAtIndex:i-1];
        SKSpriteNode *nodeB = [_ropeRings objectAtIndex:i];
        CGFloat thetaA = nodeA.zRotation - M_PI / 2,thetaB = nodeB.zRotation + M_PI / 2,joinTradius = (_ringsdistance + nodeA.size.height) / 2,xJoint = joinTradius * cosf(thetaA) + nodeA.position.x,yJoint = joinTradius * sinf(thetaA) + nodeA.position.y,theta = thetaB - M_PI,xB = joinTradius * cosf(theta) + xJoint,yB = joinTradius * sinf(theta) + yJoint;
        nodeB.position = CGPointMake(xB,yB);
    }
}

-(SKSpriteNode *)startRing
{
    return _ropeRings[0];
}

-(SKSpriteNode *)lastRing
{
    return [_ropeRings lastObject];
}

@end

用于展示如何使用绳索的场景代码:

#import "ALRopeDemoScene.h"
#import "ALRope.h"

@implementation ALRopeDemoScene
{
    __weak SKSpriteNode *_branch;

    CGPoint _touchLastPosition;

    BOOL _branchIsMoving;

    ALRope *_rope;
}

-(id)initWithSize:(CGSize)size {
    if (self = [super initWithSize:size]) {
        /* Setup your scene here */

        self.backgroundColor = [SKColor colorWithRed:0.2 green:0.5 blue:0.6 alpha:1.0];

        [self buildScene];
    }
    return self;
}

-(void) buildScene {
    SKSpriteNode *branch = [SKSpriteNode spriteNodeWithImageNamed:@"Branch"];
    _branch = branch;
    branch.position = CGPointMake(CGRectGetMaxX(self.frame) - branch.size.width / 2,CGRectGetMidY(self.frame) + 200);
    branch.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:CGSizeMake(2,10)];
    branch.physicsBody.dynamic = NO;
    [self addChild:branch];
    _rope = [[ALRope alloc] initWithRingTexture:[SKTexture textureWithImageNamed:@"rope_ring"]];

    //configure rope params if needed
    //    _rope.ringCount = ...;//default is 30
    //    _rope.ringScale = ...;//default is 1
    //    _rope.ringsdistance = ...;//default is 0
    //    _rope.jointsFrictionTorque = ...;//default is 0
    //    _rope.ringsZPosition = ...;//default is 1
    //    _rope.ringFriction = ...;//default is 0
    //    _rope.ringRestitution = ...;//default is 0
    //    _rope.ringMass = ...;//ignored unless mass > 0; default -1
    //    _rope.shouldEnableJointsAngleLimits = ...;//default is NO
    //    _rope.jointsLowerAngleLimit = ...;//default is -M_PI/3
    //    _rope.jointsUpperAngleLimit = ...;//default is M_PI/3

    _rope.startRingPosition = CGPointMake(branch.position.x - 100,branch.position.y);//default is (0,0)

    [_rope buildropeWithScene:self];

    //attach rope to branch
    SKSpriteNode *startRing = [_rope startRing];
    CGPoint jointAnchor = CGPointMake(startRing.position.x,startRing.position.y + startRing.size.height / 2);
    SKPhysicsJointPin *joint = [SKPhysicsJointPin jointWithBodyA:branch.physicsBody bodyB:startRing.physicsBody anchor:jointAnchor];
    [self.physicsWorld addJoint:joint];
}

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    UITouch *touch = [touches anyObject];
    CGPoint location = [touch locationInNode:self];
    if(CGRectContainsPoint(_branch.frame,location)) {
        _branchIsMoving = YES;
        _touchLastPosition = location;
    }
}

-(void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    _branchIsMoving = NO;

}

-(void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{

    if(_branchIsMoving) {
        UITouch *touch = [touches anyObject];
        CGPoint location = [touch locationInNode:self],branchCurrentPosition = _branch.position;
        CGFloat dx = location.x - _touchLastPosition.x,dy = location.y - _touchLastPosition.y;
        _branch.position = CGPointMake(branchCurrentPosition.x + dx,branchCurrentPosition.y + dy);
        _touchLastPosition = location;
    }
}

-(void)didSimulatePhysics
{
    //workaround for elastic effect
    [_rope adjustRingPositions];
}


@end

注意来自[scene didSimulatePhysics]的[rope adjustRingPositions]调用.这是弹性bug的实际解决方法.

完整的演示代码是here.我希望这有帮助!

ios – SKPhysics:制作一根绳子,它为什么会断裂?的更多相关文章

  1. ios – SKPhysics:制作一根绳子,它为什么会断裂?

    文档从未建议SKPhysicsJointPin具有有限的最大强度或弹性或类似.这是sprite工具包中的“bug”,还是我使用了错误的方法?

  2. php – 具有Array数组结构的字符串

    )感谢帮助,PK鉴于价值观这里有一些代码我躺在那里做你需要的:Seeitinaction.实际上它稍微多于它:它可以简单地封装在一个函数中,并且可以在所有三个输入值上进行配置.

  3. PHP / SimpleXML – 为单个子项和多个子项生成不同的数组

    我正在使用SimpleXML来解析来自不同房地产经纪人的属性列表的XML提要.XMLFeed的相关部分看起来像这样:然后转换为这样的数组:我遇到的问题是,当创建数组时,单个列表的数据在数组中与多个列表的位置不同–我不确定如何解释这个,但如果我var_dump()它看起来像这样的多个项目的数组:如果我var_dump()单个列表的数组,它看起来像这样:但我需要它看起来像这样:这些数组中的每一个都代表

  4. angularjs – 角度ui路由器中的三级嵌套路由

    我试图让我的嵌套路线工作,但它给了我两天的困难时间:(一级工作正常两级工作正常三级不工作!

  5. angular tree 异步加载下一级菜单 的正确修改方式

    angular中的tree树形结构在github上也越来越丰富,使用起来也蛮方便的,可是项目中有这么一个现实情况,导致静态页面加载数据后造成明显卡顿。我找到的插件是叫angular-bootstrap-nav-tree,github上地址是这里,使用方法是讲一个嵌套结构的的json一起赋值给指令中的tree-data属性,就能生成一个tree型结构的list。这就需要把abn_tree_directive指令改一下。在abn_tree_directive第11行原来i里边是这么写的ng-click=’a.

  6. 防止编译器在C 03中考虑隐式声明的复制构造函数

    在Branch的初始化列表中初始化Fixture时,编译器仍然会考虑这些私有声明:我希望编译器根本不考虑这些复制构造函数.我可以通过自己做一点扭曲来做到这一点:…但我宁愿不是,因为它有点臭我的鼻子,非复制能力是我要通过派生Fixture从boost::noncopyable的语义.有没有办法阻止编译器在这种情况下考虑隐式声明的复制构造函数,而无需更改调用站点处的代码:?

  7. java – 无法实例化泛型中的类型

    我有这门课我正在尝试使用此类创建一个变量它给了我这个错误解决方法虽然实例化泛型应该用相应的对象替换.例如:

随机推荐

  1. iOS实现拖拽View跟随手指浮动效果

    这篇文章主要为大家详细介绍了iOS实现拖拽View跟随手指浮动,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  2. iOS – genstrings:无法连接到输出目录en.lproj

    使用我桌面上的项目文件夹,我启动终端输入:cd然后将我的项目文件夹拖到终端,它给了我路径.然后我将这行代码粘贴到终端中找.-name*.m|xargsgenstrings-oen.lproj我在终端中收到此错误消息:genstrings:无法连接到输出目录en.lproj它多次打印这行,然后说我的项目是一个目录的路径?没有.strings文件.对我做错了什么的想法?

  3. iOS 7 UIButtonBarItem图像没有色调

    如何确保按钮图标采用全局色调?解决方法只是想将其转换为根注释,以便为“回答”复选标记提供更好的上下文,并提供更好的格式.我能想出这个!

  4. ios – 在自定义相机层的AVFoundation中自动对焦和自动曝光

    为AVFoundation定制图层相机创建精确的自动对焦和曝光的最佳方法是什么?

  5. ios – Xcode找不到Alamofire,错误:没有这样的模块’Alamofire’

    我正在尝试按照github(https://github.com/Alamofire/Alamofire#cocoapods)指令将Alamofire包含在我的Swift项目中.我创建了一个新项目,导航到项目目录并运行此命令sudogeminstallcocoapods.然后我面临以下错误:搜索后我设法通过运行此命令安装cocoapodssudogeminstall-n/usr/local/bin

  6. ios – 在没有iPhone6s或更新的情况下测试ARKit

    我在决定下载Xcode9之前.我想玩新的框架–ARKit.我知道要用ARKit运行app我需要一个带有A9芯片或更新版本的设备.不幸的是我有一个较旧的.我的问题是已经下载了新Xcode的人.在我的情况下有可能运行ARKit应用程序吗?那个或其他任何模拟器?任何想法或我将不得不购买新设备?解决方法任何iOS11设备都可以使用ARKit,但是具有高质量AR体验的全球跟踪功能需要使用A9或更高版本处理器的设备.使用iOS11测试版更新您的设备是必要的.

  7. 将iOS应用移植到Android

    我们制作了一个具有2000个目标c类的退出大型iOS应用程序.我想知道有一个最佳实践指南将其移植到Android?此外,由于我们的应用程序大量使用UINavigation和UIView控制器,我想知道在Android上有类似的模型和实现.谢谢到目前为止,guenter解决方法老实说,我认为你正在计划的只是制作难以维护的糟糕代码.我意识到这听起来像很多工作,但从长远来看它会更容易,我只是将应用程序的概念“移植”到android并从头开始编写.

  8. ios – 在Swift中覆盖Objective C类方法

    我是Swift的初学者,我正在尝试在Swift项目中使用JSONModel.我想从JSONModel覆盖方法keyMapper,但我没有找到如何覆盖模型类中的Objective-C类方法.该方法的签名是:我怎样才能做到这一点?解决方法您可以像覆盖实例方法一样执行此操作,但使用class关键字除外:

  9. ios – 在WKWebView中获取链接URL

    我想在WKWebView中获取tapped链接的url.链接采用自定义格式,可触发应用中的某些操作.例如HTTP://我的网站/帮助#深层链接对讲.我这样使用KVO:这在第一次点击链接时效果很好.但是,如果我连续两次点击相同的链接,它将不报告链接点击.是否有解决方法来解决这个问题,以便我可以检测每个点击并获取链接?任何关于这个的指针都会很棒!解决方法像这样更改addobserver在observeValue函数中,您可以获得两个值

  10. ios – 在Swift的UIView中找到UILabel

    我正在尝试在我的UIViewControllers的超级视图中找到我的UILabels.这是我的代码:这是在Objective-C中推荐的方式,但是在Swift中我只得到UIViews和CALayer.我肯定在提供给这个方法的视图中有UILabel.我错过了什么?我的UIViewController中的调用:解决方法使用函数式编程概念可以更轻松地实现这一目标.

返回
顶部