但是,我希望玩家精灵浮在它上面(或者在其中间).如果玩家只是从下面走进水里,我希望他漂浮到顶端.如果他摔倒了,我希望他慢慢改变方向然后再回来.
当他在水中时我尝试使重力为负,但这给了我一些稍微不想要的效果.例如,当他(玩家)浮出水面时,正常的重力会将他推倒,水将推动他,等等.最终,玩家将在水中“弹跳”,从一端推到另一端.当他浮出水面时,我希望他能够平静地留在水面上.我怎样才能做到这一点?
这是我在更新循环中的代码:
SKNode *backgroundNodeAtPoint = [_bgLayer nodeAtPoint:_ball.position]; if ([backgroundNodeAtPoint.name isEqualToString:@"WATER"]) { self.physicsWorld.gravity = CGVectorMake(self.physicsWorld.gravity.dx,2); } else { if (self.physicsWorld.gravity.dy != -4) { self.physicsWorld.gravity = CGVectorMake(self.physicsWorld.gravity.dx,-4); } }
基本上,当玩家在水中时,这会将我的引力变为2,否则将其更改为-4,除非它已经是-4.
谢谢!
解决方法
1)如评论中所述,您可以尝试使用SKFieldNode(iOS 8).但是从个人经验来看,现场节点对我来说并没有真正做到这一点,因为除非你对其进行大量定制,否则你无法用它来控制你的模拟,在这种情况下你也可以从头开始自己进行计算并减少复杂.
2)您可以在水中调整精灵的线性和旋转阻尼.事实上,甚至苹果在他们的文档引用中都提到了这一点.然而,这不会给你带来浮力.
The linearDamping and angularDamping properties are used to calculate
friction on the body as it moves through the world. For example,this
might be used to simulate air or water friction.
3)自己进行计算.在更新方法中,检查身体何时进入“水”,何时进入,您可以计算粘度和/或浮力,并相应地调整节点的速度.在我看来,这是最好的选择,但也更难.
编辑:我刚刚在Swift中写了一个选项3的快速示例.我认为这就是你要找的东西.我在顶部添加了因子常数,因此您可以调整它以获得您想要的结果.动作是动态应用的,因此它不会干扰你当前的速度(即你可以在水中控制你的角色).下面是场景的代码和gif.请记住,增量时间假设为每秒60帧(1/60)并且没有速度钳制.根据您的游戏,这些是您可能想要或不想要的功能.
迅速
class GameScene: SKScene { //MARK: Factors let VISCOSITY: CGFloat = 6 //Increase to make the water "thicker/stickier," creating more friction. let BUOYANCY: CGFloat = 0.4 //Slightly increase to make the object "float up faster," more buoyant. let OFFSET: CGFloat = 70 //Increase to make the object float to the surface higher. //MARK: - var object: SKSpriteNode! var water: SKSpriteNode! override func didMoveToView(view: SKView) { object = SKSpriteNode(color: UIColor.whiteColor(),size: CGSize(width: 25,height: 50)) object.physicsBody = SKPhysicsBody(rectangleOfSize: object.size) object.position = CGPoint(x: self.size.width/2.0,y: self.size.height-50) self.addChild(object) water = SKSpriteNode(color: UIColor.cyanColor(),size: CGSize(width: self.size.width,height: 300)) water.position = CGPoint(x: self.size.width/2.0,y: water.size.height/2.0) water.alpha = 0.5 self.addChild(water) self.physicsBody = SKPhysicsBody(edgeLoopFromRect: self.frame) } override func update(currentTime: CFTimeInterval) { if water.frame.contains(CGPoint(x:object.position.x,y:object.position.y-object.size.height/2.0)) { let rate: CGFloat = 0.01; //Controls rate of applied motion. You shouldn't really need to touch this. let disp = (((water.position.y+OFFSET)+water.size.height/2.0)-((object.position.y)-object.size.height/2.0)) * BUOYANCY let targetPos = CGPoint(x: object.position.x,y: object.position.y+disp) let targetVel = CGPoint(x: (targetPos.x-object.position.x)/(1.0/60.0),y: (targetPos.y-object.position.y)/(1.0/60.0)) let relVel: CGVector = CGVector(dx:targetVel.x-object.physicsBody.velocity.dx*VISCOSITY,dy:targetVel.y-object.physicsBody.velocity.dy*VISCOSITY); object.physicsBody.velocity=CGVector(dx:object.physicsBody.velocity.dx+relVel.dx*rate,dy:object.physicsBody.velocity.dy+relVel.dy*rate); } } override func touchesEnded(touches: NSSet!,withEvent event: UIEvent!) {object.position = (touches.anyObject() as UITouch).locationInNode(self);object.physicsBody.velocity = CGVectorMake(0,0)} }
Objective-C的
#import "GameScene.h" #define VISCOSITY 6.0 //Increase to make the water "thicker/stickier," creating more friction. #define BUOYANCY 0.4 //Slightly increase to make the object "float up faster," more buoyant. #define OFFSET 70.0 //Increase to make the object float to the surface higher. @interface GameScene () @property (nonatomic,strong) SKSpriteNode* object; @property (nonatomic,strong) SKSpriteNode* water; @end @implementation GameScene -(void)didMoveToView:(SKView *)view { _object = [[SKSpriteNode alloc] initWithColor:[UIColor whiteColor] size:CGSizeMake(25,50)]; self.object.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:self.object.size]; self.object.position = CGPointMake(self.size.width/2.0,self.size.height-50); [self addChild:self.object]; _water = [[SKSpriteNode alloc] initWithColor:[UIColor cyanColor] size:CGSizeMake(self.size.width,300)]; self.water.position = CGPointMake(self.size.width/2.0,self.water.size.height/2.0); self.water.alpha = 0.5; [self addChild:self.water]; self.physicsBody = [SKPhysicsBody bodyWithEdgeLoopFromRect:self.frame]; } -(void)update:(NSTimeInterval)currentTime { if (CGRectContainsPoint(self.water.frame,CGPointMake(self.object.position.x,self.object.position.y-self.object.size.height/2.0))) { const CGFloat rate = 0.01; //Controls rate of applied motion. You shouldn't really need to touch this. const CGFloat disp = (((self.water.position.y+OFFSET)+self.water.size.height/2.0)-((self.object.position.y)-self.object.size.height/2.0)) * BUOYANCY; const CGPoint targetPos = CGPointMake(self.object.position.x,self.object.position.y+disp); const CGPoint targetVel = CGPointMake((targetPos.x-self.object.position.x)/(1.0/60.0),(targetPos.y-self.object.position.y)/(1.0/60.0)); const CGVector relVel = CGVectorMake(targetVel.x-self.object.physicsBody.velocity.dx*VISCOSITY,targetVel.y-self.object.physicsBody.velocity.dy*VISCOSITY); self.object.physicsBody.velocity=CGVectorMake(self.object.physicsBody.velocity.dx+relVel.dx*rate,self.object.physicsBody.velocity.dy+relVel.dy*rate); } } -(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { self.object.position = [(UITouch*)[touches anyObject] locationInNode:self]; self.object.physicsBody.velocity = CGVectorMake(0,0); } @end