我正在尝试为我的游戏加水。除了不同的背景颜色,它没有多少。
但是,我希望player-sprite
能够漂浮在它上面(或者在它的中间)。如果玩家只是从下面走进水里,我希望他漂浮到顶端。如果他摔倒了,我希望他慢慢改变方向并漂浮起来。
当他在水中时,我尝试使重力为负,但这给了我一些稍微不想要的效果。例如,当他(玩家)浮出水面时,正常的重力会将他推倒,水将推动他,等等。最终,玩家将在水中“弹跳”,从一端推到另一端。当他浮出水面时,我希望他能够平静地留在水面上。我怎样才能做到这一点?
以下是我update-loop
中的代码:
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
。
谢谢!
答案 0 :(得分:20)
我相信您在模拟水方面有三种可能的选择。
1)如评论中所述,您可以尝试使用SKFieldNode(iOS 8+)。但是从个人经验来看,现场节点对我来说并没有真正做到这一点,因为除非你对其进行大量定制,否则你无法用它来控制你的模拟,在这种情况下你也可以从头开始自己进行计算并减少复杂性。
2)你可以在水中调整精灵的线性和旋转阻尼。事实上,甚至苹果在他们的文档引用中也提到了这一点。然而,这不会给你带来浮力。
linearDamping和angularDamping属性用于计算 在身体穿过世界时身体上的摩擦力。例如,这个 可能用于模拟空气或水的摩擦。
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)}
}
<强>目标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
答案 1 :(得分:0)
当你的球员与水接触时,将他推开,直到他不再接触到水。此时,修改玩家的接触位掩码以与水碰撞,从而“让他在水上行走”。
或者,您可以通过策略性放置的隐形节点触发水接触位掩码修改,而不是等待水接触发生。
要将玩家的接触位掩码恢复正常,请使用玩家将使用的其他预定接触(例如陆地或不可见节点)作为触发器。