【问题标题】:Sprite Kit: How To Subclass SKNode to create a Vehicle class (complex object with joints)Sprite Kit:如何对 SKNode 进行子类化以创建 Vehicle 类(具有关节的复杂对象)
【发布时间】:2013-11-30 21:15:10
【问题描述】:

有没有人(本机)想出如何将 SKNode 子类化以包括通过关节连接的多个主体 - 例如汽车?

似乎没有办法将子类的关节添加到父场景的物理世界属性中。

另外,当尝试编译和运行下面的对象时,即使没有关节,我也会收到 BAD_EXC_ACCESS 错误。

感谢@Smick 提供此处发布的初始车辆代码:Sprite Kit pin joints appear to have an incorrect anchor

卡车类:

#import "Truck.h"

@implementation Truck


-(id)initWithPosition:(CGPoint)pos {


SKSpriteNode *carBody = [SKSpriteNode spriteNodeWithColor:[UIColor whiteColor] size:CGSizeMake(120, 8)];
carBody.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:carBody.size];
carBody.position = pos;
carBody.physicsBody.mass = 1.0;


SKSpriteNode *carTop = [SKSpriteNode spriteNodeWithColor:[UIColor whiteColor] size:CGSizeMake(50, 8)];
carTop.position = CGPointMake(230, 708);
carTop.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:carTop.size];
carTop.physicsBody.mass = 0;

SKPhysicsJointFixed *carBodyJoint = [SKPhysicsJointFixed jointWithBodyA:carBody.physicsBody
                                                                  bodyB:carTop.physicsBody
                                                                 anchor:CGPointMake(0, 0)];



return self;
}

+(Truck*)initWithPosition:(CGPoint)pos {
return [[self alloc] initWithPosition:pos];
}


@end

我的场景:

【问题讨论】:

  • 您是否在调试模式下逐步确定它在哪一行崩溃?崩溃前的输出中还有其他信息吗?另外,如果这是子类化,您不应该调用 [super init] 吗?也很高兴看到您的 .h 代码
  • 不需要子类,只需使用多个 SKNode 实例。每个节点只能有一个主体。
  • @prototypical 谢谢,if (self = [super init]) 工作。现在我只需要找到一种方法将我的卡车对象的关节连接到主场景的physicsWorld 属性中。我需要使 MyScene 中的 physicsWorld 属性可用于我的 Truck 对象,以便我可以在类中附加关节。代码待定。
  • @LearnCocos2D 我想要车辆代码 - 底盘部件、车轮、接头(滑块和弹簧)在它自己的类中。与在主场景中包含所有代码相比,这不是最好的方法吗?
  • 最好将您的问题限制在具体问题上。我认为问题是您在尝试子类化时收到的错误,这就是为什么我要求提供更多信息并质疑缺少 init 调用的原因。关节问题是一个单独的问题。你说“关节”,但我在上面的代码中只看到一个关节。您需要将这一切分解并形成一个包含某人需要的所有信息的问题。不花时间这样做,只会减少有人花时间帮助你的机会。

标签: subclass sprite-kit sknode


【解决方案1】:

抱歉,帖子迟了,但我自己打这个。

除非附加的节点已经添加到 SKScene 的场景图中,否则物理关节不起作用。

在上面的 initWithPosition 期间,情况并非如此。 传入 SKScene 对我也不起作用,我怀疑是因为 Vehicle 节点仍未添加到场景图中。

你仍然可以在类中封装你的物理关节,但是你必须在

之后调用另一个方法
[self addChild:car]

这是我对您已有内容的改进:

Vehicle.h

@interface Vehicle : SKNode

@property (nonatomic) SKSpriteNode *leftWheel;
@property (nonatomic) SKSpriteNode *ctop;

-(id)initWithPosition:(CGPoint)pos;
-(void)initPhysics;

@end

Vehicle.m

//

#import "Vehicle.h"

@implementation Vehicle {
    SKSpriteNode *chassis;
    SKSpriteNode *rightWheel;
    SKSpriteNode *leftShockPost;
    SKSpriteNode *rightShockPost;
    int wheelOffsetY;
    CGFloat damping;
    CGFloat frequency;
}

- (SKSpriteNode*) makeWheel
{
    SKSpriteNode *wheel = [SKSpriteNode spriteNodeWithImageNamed:@"Wheel.png"];
    //    wheel.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:wheel.size.width/2];
    return wheel;
}

-(id)initWithPosition:(CGPoint)pos {

    if (self = [super init]) {

        wheelOffsetY    =   60;
        damping         =   1;
        frequency       =   4;

        chassis = [SKSpriteNode spriteNodeWithColor:[UIColor whiteColor] size:CGSizeMake(120, 8)];
        chassis.position = pos;
        [self addChild:chassis];

        _ctop = [SKSpriteNode spriteNodeWithColor:[UIColor greenColor] size:CGSizeMake(70, 16)];
        _ctop.position = CGPointMake(chassis.position.x+20, chassis.position.y+12);

        [self addChild:_ctop];

        _leftWheel = [self makeWheel];
        _leftWheel.position = CGPointMake(chassis.position.x - chassis.size.width / 2, chassis.position.y - wheelOffsetY);  //Always set position before physicsBody

        [self addChild:_leftWheel];

        rightWheel = [self makeWheel];
        rightWheel.position = CGPointMake(chassis.position.x + chassis.size.width / 2, chassis.position.y - wheelOffsetY);
        [self addChild:rightWheel];

        //------------- LEFT SUSPENSION ----------------------------------------------------------------------------------------------- //

        leftShockPost = [SKSpriteNode spriteNodeWithColor:[UIColor blueColor] size:CGSizeMake(7, wheelOffsetY)];
        leftShockPost.position = CGPointMake(chassis.position.x - chassis.size.width / 2, chassis.position.y - leftShockPost.size.height/2);
        [self addChild:leftShockPost];


        //------------- RIGHT SUSPENSION ----------------------------------------------------------------------------------------------- //

        rightShockPost = [SKSpriteNode spriteNodeWithColor:[UIColor blueColor] size:CGSizeMake(7, wheelOffsetY)];
        rightShockPost.position = CGPointMake(chassis.position.x + chassis.size.width / 2, chassis.position.y - rightShockPost.size.height/2);
        [self addChild:rightShockPost];

    }

    return self;
}

-(void) initPhysics {

    chassis.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:chassis.size];
    _ctop.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:_ctop.size];

    SKPhysicsJointFixed *cJoint = [SKPhysicsJointFixed jointWithBodyA:chassis.physicsBody
                                                                bodyB:_ctop.physicsBody
                                                               anchor:CGPointMake(_ctop.position.x, _ctop.position.y)];

    _leftWheel.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:_leftWheel.size.width/2];
    _leftWheel.physicsBody.allowsRotation = YES;

    rightWheel.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:rightWheel.size.width/2];
    rightWheel.physicsBody.allowsRotation = YES;

    leftShockPost.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:leftShockPost.size];
    SKPhysicsJointSliding  *leftSlide = [SKPhysicsJointSliding jointWithBodyA:chassis.physicsBody
                                                                        bodyB:leftShockPost.physicsBody
                                                                       anchor:CGPointMake(leftShockPost.position.x, leftShockPost.position.y)
                                                                         axis:CGVectorMake(0, 1)];

    leftSlide.shouldEnableLimits = TRUE;
    leftSlide.lowerDistanceLimit = 5;
    leftSlide.upperDistanceLimit = wheelOffsetY;


    SKPhysicsJointSpring *leftSpring = [SKPhysicsJointSpring jointWithBodyA:chassis.physicsBody bodyB:_leftWheel.physicsBody
                                                                    anchorA:CGPointMake(chassis.position.x - chassis.size.width / 2, chassis.position.y)
                                                                    anchorB:_leftWheel.position];
    leftSpring.damping = damping;
    leftSpring.frequency = frequency;

    SKPhysicsJointPin *lPin = [SKPhysicsJointPin jointWithBodyA:leftShockPost.physicsBody bodyB:_leftWheel.physicsBody anchor:_leftWheel.position];

    rightShockPost.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:rightShockPost.size];
    SKPhysicsJointSliding  *rightSlide = [SKPhysicsJointSliding jointWithBodyA:chassis.physicsBody
                                                                         bodyB:rightShockPost.physicsBody
                                                                        anchor:CGPointMake(rightShockPost.position.x, rightShockPost.position.y)
                                                                          axis:CGVectorMake(0, 1)];

    rightSlide.shouldEnableLimits = TRUE;
    rightSlide.lowerDistanceLimit = 5;
    rightSlide.upperDistanceLimit = wheelOffsetY;


    SKPhysicsJointSpring *rightSpring = [SKPhysicsJointSpring jointWithBodyA:chassis.physicsBody bodyB:rightWheel.physicsBody
                                                                     anchorA:CGPointMake(chassis.position.x + chassis.size.width / 2, chassis.position.y)
                                                                     anchorB:rightWheel.position];
    rightSpring.damping = damping;
    rightSpring.frequency = frequency;

    SKPhysicsJointPin *rPin = [SKPhysicsJointPin jointWithBodyA:rightShockPost.physicsBody bodyB:rightWheel.physicsBody anchor:rightWheel.position];

    // Add all joints to the array.
    // Add joints to scene's physics world

    [self.scene.physicsWorld addJoint: cJoint];
    [self.scene.physicsWorld addJoint: leftSlide];
    [self.scene.physicsWorld addJoint: leftSpring];
    [self.scene.physicsWorld addJoint: lPin];
    [self.scene.physicsWorld addJoint: rightSlide];
    [self.scene.physicsWorld addJoint: rightSpring];
    [self.scene.physicsWorld addJoint: rPin];

}
@end

并从 MyScene.m 中调用它

_car = [[DMVehicle alloc] initWithPosition:location];
[self addChild:_car];
[_car initPhysics];

希望对您有所帮助,我知道这对我有所帮助

【讨论】:

  • 我绝对和你在同一条船上,处理封装的挫败感。这对我帮助很大。谢谢。
  • b2DistanceJointDef::Initialize 的某处获得了 EXC_BAD_ACCESS。你刚刚拯救了我的一天!
【解决方案2】:

这就是我想出的。

我唯一的问题是它不是完全独立的,因为关节必须添加到类之外的物理世界中 - 很简单,你会看到使用两行代码。

编辑我的答案。与通过滑动接头连接车轮相比,悬架需要将车轮连接到滑动体上。做前者可以让轮子旋转。后者没有。

更新:我已取消将此标记为答案。原因是,虽然它在模拟器上运行良好,但当我尝试在我的 iPad(运行 iOS7)上运行它时收到以下错误。当我删除我的车辆类并将使用该 UIColor 方法的车辆组件之一放入我的主场景时,不会引发错误。

UICachedDeviceWhiteColor addObject:]: unrecognized selector sent to instance 0x15e21360
2013-12-14 22:44:19.790 SKTestCase[1401:60b] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[UICachedDeviceWhiteColor addObject:]: unrecognized selector sent to instance 

由于某种原因,我不再收到 UICashed... 错误(是的,车辆仍然是一个类)现在我收到:

-[PKPhysicsJointWeld name]: unrecognized selector sent to instance 0x1464f810
2013-12-15 15:28:24.081 MTC[1747:60b] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[PKPhysicsJointWeld name]: unrecognized selector sent to instance 0x1464f810'
*** First throw call stack:
(0x30eaff53 0x3b5186af 0x30eb38e7 0x30eb21d3 0x30e01598 0x3352837d 0x335284d5 0x33527b97 0x33525ca5 0x87385 0x335064f5 0x87ccb 0x33620fe1 0x332aa24b 0x332a5a5b 0x332d4b7d 0x3369e39b 0x3369ca03 0x3369bc53 0x3369bbdb 0x3369bb73 0x33694681 0x3362703f 0x3369b8c1 0x3369b38d 0x3362c21d 0x33629763 0x33694a55 0x33691811 0x3368bd13 0x336266a7 0x336259a9 0x3368b4fd 0x35ab270d 0x35ab22f7 0x30e7a9e7 0x30e7a983 0x30e79157 0x30de3ce7 0x30de3acb 0x3368a799 0x33685a41 0x8a52d 0x3ba20ab7)
libc++abi.dylib: terminating with uncaught exception of type NSException

车辆.h:

#import <SpriteKit/SpriteKit.h>

@interface Vehicle : SKNode


@property (nonatomic,assign) NSMutableArray *joints;
@property (nonatomic) SKSpriteNode *leftWheel;
@property (nonatomic) SKSpriteNode *ctop;

-(id)initWithPosition:(CGPoint)pos;

@end

Vehicle.m

#import "Vehicle.h"

@implementation Vehicle

- (SKSpriteNode*) makeWheel
{
    SKSpriteNode *wheel = [SKSpriteNode spriteNodeWithImageNamed:@"wheel.png"];
//    wheel.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:wheel.size.width/2];
    return wheel;
}

-(id)initWithPosition:(CGPoint)pos {

    if (self = [super init]) {

        _joints = [NSMutableArray array];

        int wheelOffsetY    =   60;
        CGFloat damping     =   1;
        CGFloat frequency   =   4;

        SKSpriteNode *chassis = [SKSpriteNode spriteNodeWithColor:[UIColor whiteColor] size:CGSizeMake(120, 8)];
        chassis.position = pos;
        chassis.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:chassis.size];
        [self addChild:chassis];

        _ctop = [SKSpriteNode spriteNodeWithColor:[UIColor greenColor] size:CGSizeMake(70, 16)];
        _ctop.position = CGPointMake(chassis.position.x+20, chassis.position.y+12);
        _ctop.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:_ctop.size];
        [self addChild:_ctop];

        SKPhysicsJointFixed *cJoint = [SKPhysicsJointFixed jointWithBodyA:chassis.physicsBody
                                                                    bodyB:_ctop.physicsBody
                                                                   anchor:CGPointMake(_ctop.position.x, _ctop.position.y)];


        _leftWheel = [self makeWheel];
        _leftWheel.position = CGPointMake(chassis.position.x - chassis.size.width / 2, chassis.position.y - wheelOffsetY);  //Always set position before physicsBody
        _leftWheel.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:_leftWheel.size.width/2];
        _leftWheel.physicsBody.allowsRotation = YES;
        [self addChild:_leftWheel];

        SKSpriteNode *rightWheel = [self makeWheel];
        rightWheel.position = CGPointMake(chassis.position.x + chassis.size.width / 2, chassis.position.y - wheelOffsetY);
        rightWheel.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:rightWheel.size.width/2];
        rightWheel.physicsBody.allowsRotation = YES;
        [self addChild:rightWheel];

//------------- LEFT SUSPENSION ----------------------------------------------------------------------------------------------- //

        SKSpriteNode *leftShockPost = [SKSpriteNode spriteNodeWithColor:[UIColor blueColor] size:CGSizeMake(7, wheelOffsetY)];
        leftShockPost.position = CGPointMake(chassis.position.x - chassis.size.width / 2, chassis.position.y - leftShockPost.size.height/2);
        leftShockPost.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:leftShockPost.size];
        [self addChild:leftShockPost];

       SKPhysicsJointSliding  *leftSlide = [SKPhysicsJointSliding jointWithBodyA:chassis.physicsBody
                                                                           bodyB:leftShockPost.physicsBody
                                                    anchor:CGPointMake(leftShockPost.position.x, leftShockPost.position.y)
                                                      axis:CGVectorMake(0, 1)];

        leftSlide.shouldEnableLimits = TRUE;
        leftSlide.lowerDistanceLimit = 5;
        leftSlide.upperDistanceLimit = wheelOffsetY;


        SKPhysicsJointSpring *leftSpring = [SKPhysicsJointSpring jointWithBodyA:chassis.physicsBody bodyB:_leftWheel.physicsBody
                                                                        anchorA:CGPointMake(chassis.position.x - chassis.size.width / 2, chassis.position.y)
                                                                        anchorB:_leftWheel.position];
        leftSpring.damping = damping;
        leftSpring.frequency = frequency;

        SKPhysicsJointPin *lPin = [SKPhysicsJointPin jointWithBodyA:leftShockPost.physicsBody bodyB:_leftWheel.physicsBody anchor:_leftWheel.position];


//------------- RIGHT SUSPENSION ----------------------------------------------------------------------------------------------- //

        SKSpriteNode *rightShockPost = [SKSpriteNode spriteNodeWithColor:[UIColor blueColor] size:CGSizeMake(7, wheelOffsetY)];
        rightShockPost.position = CGPointMake(chassis.position.x + chassis.size.width / 2, chassis.position.y - rightShockPost.size.height/2);
        rightShockPost.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:rightShockPost.size];
        [self addChild:rightShockPost];

        SKPhysicsJointSliding  *rightSlide = [SKPhysicsJointSliding jointWithBodyA:chassis.physicsBody
                                                                            bodyB:rightShockPost.physicsBody
                                                                           anchor:CGPointMake(rightShockPost.position.x, rightShockPost.position.y)
                                                                             axis:CGVectorMake(0, 1)];

        rightSlide.shouldEnableLimits = TRUE;
        rightSlide.lowerDistanceLimit = 5;
        rightSlide.upperDistanceLimit = wheelOffsetY;


        SKPhysicsJointSpring *rightSpring = [SKPhysicsJointSpring jointWithBodyA:chassis.physicsBody bodyB:rightWheel.physicsBody
                                                                        anchorA:CGPointMake(chassis.position.x + chassis.size.width / 2, chassis.position.y)
                                                                        anchorB:rightWheel.position];
        rightSpring.damping = damping;
        rightSpring.frequency = frequency;

        SKPhysicsJointPin *rPin = [SKPhysicsJointPin jointWithBodyA:rightShockPost.physicsBody bodyB:rightWheel.physicsBody anchor:rightWheel.position];


        // Add all joints to the array.

        [_joints addObject:cJoint];

        [_joints addObject:leftSlide];
        [_joints addObject:leftSpring];
        [_joints addObject:lPin];

        [_joints addObject:rightSlide];
        [_joints addObject:rightSpring];
        [_joints addObject:rPin];

    }

    return self;
}


@end

MyScene.m:

#import "MyScene.h"
#import "Vehicle.h"

@implementation MyScene {

    Vehicle *car;
}

-(id)initWithSize:(CGSize)size {

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

        self.physicsBody = [SKPhysicsBody bodyWithEdgeLoopFromRect:CGRectMake(0, 0, self.size.width, self.size.height)];

    }

    return self;
}

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    /* Called when a touch begins */

    for (UITouch *touch in touches) {

        CGPoint location = [touch locationInNode:self];

        car = [[Vehicle alloc] initWithPosition:location];
        [self addChild:car];

        // Add joints to scene's physics world
        for (SKPhysicsJoint *j in car.joints) {
               [self.physicsWorld addJoint:j];
        }
    }

}

【讨论】:

    【解决方案3】:

    1) 添加关节:为什么不让车辆的 init 方法获取一个 SKScene 对象?然后您可以在该方法中添加关节。否则,您对 _joints 数组所做的工作有效,但由于那里需要额外的代码,看起来不太干净。

    2) BAD_EXC_ACCESS:我在学习关节时也得到了这个。当参与联合的节点被添加到 SKScene 而不是其他一些子节点时,它就消失了。我能在Apple documentation 中找到的最接近的信息是:“将物理实体附加到场景中的一对 SKNode 对象上。”这并没有说明这是否意味着直接指向 SKScene,或者指向 SKScene 中节点树中的任何节点。

    【讨论】:

    • 感谢您的回复。但是,我将回到我的 SK 项目并尝试您在第 1 点提出的建议)。目前,我已经回到了 Chipmunk (Chipmunk Pro)。
    【解决方案4】:

    我遇到了同样的问题,这种方法对我有用:

    如果您尝试从场景中添加关节(在卡车类中定义),您将收到 Exc_bad_access。你必须跑 [self.scene.physicsWorld addJoint:joint] 在您的卡车课程中。

    但是,您不能添加 [self.scene.physicsWorld addJoint:joint] 进入 Truck 的 init 方法,因为在场景中运行 Truck 的 init 方法时,尚未将 Truck 添加到场景中。

    您必须在 Truck 类中编写另一个方法(比如 addJointsIntoScene)才能运行 [self.scene.physicsWorld addJoint:joint]。 将卡车添加到场景后,运行“addJointsIntoScene”方法来添加关节。

    例如, 卡车.m -(instancetype)initWithPosition:(CGPoint) triggerPosition{ …… 联合=…… …… } //还有另一个方法 -(void)addJointsIntoScene{ [self.scene.physicsWorld addJoint:joint];enter code here }

    MyScene.m
    Truck *truck = [[Truck alloc]initWithPosition:triggerPosition];
    [self addChild:truck];
    [truck addJointsIntoScene];
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多