How to Limit the Movement of Two Anchored Lines So They Swing Continually Like a Pendulum

How to keep a 30˚ distance between two lines anchored at a point

To keep your two lines separated by exactly 30°, you can use an SKPhysicsJointFixed, which is just what it sounds like: it pins two physicsBodies together in a fixed position. Since you already have them positioned the way you want, just add this code where you have the other SKPhysicsJoints to hold them that way:

let fixArms = SKPhysicsJointFixed.joint(withBodyA: armLeft.physicsBody!, bodyB: armRight.physicsBody!, anchor: CGPoint.zero)
self.physicsWorld.add(fixArms)

Result:

Result image

How To Enforce A Pendulum Path

Here's an example of how to implement an SKPhysicsJointPin:

-(id)initWithSize:(CGSize)size {

if (self = [super initWithSize:size]) {

CGPoint location = CGPointMake(self.frame.size.width/2, self.frame.size.height/2);

// Create the pendulum's pivot
SKSpriteNode *sprite = [SKSpriteNode spriteNodeWithColor:[SKColor whiteColor] size:size];
sprite.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:sprite.size];
sprite.physicsBody.dynamic = NO;

sprite.position = location;
sprite.size = CGSizeMake(8, 8);

[self addChild:sprite];

location = CGPointMake(self.frame.size.width/2-100, self.frame.size.height/2);
size = CGSizeMake(50, 200);

// Create the pendulum's bob
SKSpriteNode *sprite2 = [SKSpriteNode spriteNodeWithColor:[SKColor whiteColor] size:size];
sprite2.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:sprite.size];
sprite2.physicsBody.dynamic = YES;
sprite2.physicsBody.affectedByGravity = YES;
sprite2.physicsBody.linearDamping = 0;

sprite2.physicsBody.mass = 0.1;

sprite2.size = CGSizeMake(32, 32);
sprite2.position = location;
[self addChild:sprite2];

CGPoint point = CGPointMake(self.frame.size.width/2, self.frame.size.height/2);

// Create a joint that connects the pivot and the bob
SKPhysicsJointPin *pinJoint = [SKPhysicsJointPin jointWithBodyA:sprite.physicsBody
bodyB:sprite2.physicsBody anchor:point];

// Add the joint to the world
[self.physicsWorld addJoint:pinJoint];
}
return self;
}

SpriteKit stop spinning wheel in a defined angle

Kinematics makes my head hurt, but here you go. I made it to where you can input the amount of rotations and the wheel will rotate that many times as its slowing down to the angle you specify. The other function and extension are there to keep the code relatively clean/readable. So if you just want one giant mess function go ahead and modify it.

• Make sure the node's angularDampening = 0.0

• Make sure the node has a circular physicsbody

// Stops a spinning SpriteNode at a specified angle within a certain amount of rotations
//NOTE: Node must have a circular physicsbody
// Damping should be from 0.0 to 1.0
func decelerate(node: SKSpriteNode, toAngle: CGFloat, rotations: Int) {

if node.physicsBody == nil { print("Node doesn't have a physicsbody"); return } //Avoid crash incase node's physicsbody is nil
var cw:CGFloat { if node.physicsBody!.angularVelocity < CGFloat(0.0) { return -1.0} else { return 1.0} } //Clockwise - using int to reduce if statments with booleans

let m = node.physicsBody!.mass // Mass
let r = CGFloat.squareRoot(node.physicsBody!.area / CGFloat.pi)() // Radius
let i = 0.5 * m * r.squared // Intertia

let wi = node.physicsBody!.angularVelocity // Initial Angular Velocity
let wf:CGFloat = 0 // Final Angular Velocity

let ti = CGFloat.unitCircle(node.zRotation) // Initial Theta
var tf = CGFloat.unitCircle(toAngle) // Final Theta

//Correction constant based on rate of rotation since there seems to be a delay between when the action is calcuated and when it is run
//Without the correction the node stops a little off from its desired stop angle
tf -= 0.00773889 * wi //Might need to change constn

let dt = deltaTheta(ti, tf, Int(cw), rotations)

let a = -cw * 0.5 * wi.squared / abs(dt) // Angular Acceleration - cw used to determine direction
print("A:\(a)")
let time:Double = Double(abs((wf-wi) / a)) // Time needed to stop
let torque:CGFloat = i * a // Torque needed to stop

node.run(SKAction.applyTorque(torque, duration: time))
}

func deltaTheta(_ ti:CGFloat, _ tf:CGFloat, _ clockwise: Int, _ rotations: Int) -> CGFloat {

let extra = CGFloat(rotations)*2*CGFloat.pi

if clockwise == -1 {
if tf>ti { return tf-ti-2*CGFloat.pi-extra }else{ return tf-ti-extra }
}else{
if tf>ti { return tf-ti+extra }else{ return tf+2*CGFloat.pi+extra-ti }
}
}

}

extension CGFloat {

public var squared:CGFloat { return self * self }

public static func unitCircle(_ value: CGFloat) -> CGFloat {
if value < 0 { return 2 * CGFloat.pi + value }
else{ return value }
}
}

Move sprite based upon rotation

moveByX/Y moves your sprite based on the screen coordinates, not the position of your ship, so moving will always be based on the x or y axis. You need to incorporate some trig functions (sin and cos) on your moveby to get it to move in the path you want:

let movespriteLeft = SKAction.moveByX(-100 *  sin(ANGLE), y: -100 * -cos(ANGLE),  duration: 1)
let movespriteRight = SKAction.moveByX(100 * sin(ANGLE), y: 100 * -cos(ANGLE), duration: 1)

Where ANGLE is in a randian value from 0 to 2PI

You may have to play around with sin and cos a bit depending on your coordinate system

Crash in msvcp90d.dll when retrieving an iterator from a boost::tokenizer

There is a bug in Visual C++ with std::ostringstream when _HAS_ITERATOR_DEBUGGING is disabled.

If I recall correctly, the std::string copy constructor copies iterators. You can get around this by using the std::string conversion constructor taking a char* instead.

If you change

std::string mystr(input.str());

to

std::string mystr(input.str().c_str());

then no exception is thrown.



Related Topics



Leave a reply



Submit