有没有人知道一些开箱即用的库可能会为SKNode
提供相机抖动等效果?
如果不是,有一种简单的方法可以使用动作实现相机抖动吗?
由于
答案 0 :(得分:15)
我发现了一种使用SKAction的优雅方法,可以让你的节点震动。例如,水平摇晃:
-(void)shake:(NSInteger)times {
CGPoint initialPoint = self.position;
NSInteger amplitudeX = 32;
NSInteger amplitudeY = 2;
NSMutableArray * randomActions = [NSMutableArray array];
for (int i=0; i<times; i++) {
NSInteger randX = self.position.x+arc4random() % amplitudeX - amplitudeX/2;
NSInteger randY = self.position.y+arc4random() % amplitudeY - amplitudeY/2;
SKAction *action = [SKAction moveTo:CGPointMake(randX, randY) duration:0.01];
[randomActions addObject:action];
}
SKAction *rep = [SKAction sequence:randomActions];
[self runAction:rep completion:^{
self.position = initialPoint;
}];
}
答案 1 :(得分:13)
接受答案中的摇动方法有一个警告 - 它只能应用于没有x,y坐标被其他正在运行的SKAction修改的节点。这是因为我们在摇动完成后将节点的位置重置为其初始位置。
如果你想要一个同样适用于其他SKAction的摇动动作,它可以按顺序/并行方式修改摇动节点的位置(x或y坐标),你需要添加随机的反向动作你正在申请。
Swift扩展名供参考:
extension SKAction {
class func shake(duration:CGFloat, amplitudeX:Int = 3, amplitudeY:Int = 3) -> SKAction {
let numberOfShakes = duration / 0.015 / 2.0
var actionsArray:[SKAction] = []
for index in 1...Int(numberOfShakes) {
let dx = CGFloat(arc4random_uniform(UInt32(amplitudeX))) - CGFloat(amplitudeX / 2)
let dy = CGFloat(arc4random_uniform(UInt32(amplitudeY))) - CGFloat(amplitudeY / 2)
let forward = SKAction.moveByX(dx, y:dy, duration: 0.015)
let reverse = forward.reversedAction()
actionsArray.append(forward)
actionsArray.append(reverse)
}
return SKAction.sequence(actionsArray)
}
}
请注意,此修改不要求将节点作为参数传入
答案 2 :(得分:5)
如果您已经使用Swift,可以使用以下代码......
let shake = SKAction.shake(node.position, duration: 0.3)
node.runAction(shake)
或者对于更强烈的震动,您也可以配置振幅
let shake = SKAction.shake(node.position, duration: 0.3, amplitudeX: 12, amplitudeY: 3)
node.runAction(shake)
这是扩展....
extension SKAction {
class func shake(initialPosition:CGPoint, duration:Float, amplitudeX:Int = 12, amplitudeY:Int = 3) -> SKAction {
let startingX = initialPosition.x
let startingY = initialPosition.y
let numberOfShakes = duration / 0.015
var actionsArray:[SKAction] = []
for index in 1...Int(numberOfShakes) {
let newXPos = startingX + CGFloat(arc4random_uniform(UInt32(amplitudeX))) - CGFloat(amplitudeX / 2)
let newYPos = startingY + CGFloat(arc4random_uniform(UInt32(amplitudeY))) - CGFloat(amplitudeY / 2)
actionsArray.append(SKAction.moveTo(CGPointMake(newXPos, newYPos), duration: 0.015))
}
actionsArray.append(SKAction.moveTo(initialPosition, duration: 0.015))
return SKAction.sequence(actionsArray)
}
}
对于我刚刚将其移动到扩展程序的实现,信用点转到Stephen Haney
答案 3 :(得分:3)
这是我使用的方法。希望能帮助到你。根据需要修改它。
-(void)shakeScreenFor:(int)numberOfShakes withIntensity:(CGVector)intensity andDuration:(CGFloat)duration{
UIView *sceneView = self.scene.view;
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position"];
[animation setDuration:(duration/numberOfShakes)];
[animation setRepeatCount:numberOfShakes];
[animation setAutoreverses:YES];
[animation setFromValue:[NSValue valueWithCGPoint: CGPointMake([sceneView center].x - intensity.dx, [sceneView center].y - intensity.dy)]];
[animation setToValue:[NSValue valueWithCGPoint: CGPointMake([sceneView center].x + intensity.dx, [sceneView center].y + intensity.dy)]];
[[sceneView layer] addAnimation:animation forKey:@"position"];
}
答案 4 :(得分:3)
如果你想动摇整个场景,这里是用Swift编写的Rob的答案:
func sceneShake(shakeCount: Int, intensity: CGVector, shakeDuration: Double) {
let sceneView = self.scene!.view! as UIView
let shakeAnimation = CABasicAnimation(keyPath: "position")
shakeAnimation.duration = shakeDuration / Double(shakeCount)
shakeAnimation.repeatCount = Float(shakeCount)
shakeAnimation.autoreverses = true
shakeAnimation.fromValue = NSValue(cgPoint: CGPoint(x: sceneView.center.x - intensity.dx, y: sceneView.center.y - intensity.dy))
shakeAnimation.toValue = NSValue(cgPoint: CGPoint(x: sceneView.center.x + intensity.dx, y: sceneView.center.y + intensity.dy))
sceneView.layer.add(shakeAnimation, forKey: "position")
}
我在SKScene子类中包含此函数。这是一个示例调用:
sceneShake(shakeCount: 3, intensity: CGVector(dx: shakeIntensity, dy: shakeIntensity), shakeDuration: shakeDuration)
答案 5 :(得分:1)
来自@Benzi的Swift 4版本答案:
func shake(duration: Double, amplitudeX: CGFloat = 3, amplitudeY: CGFloat = 3) -> SKAction {
let numberOfShakes = duration / 0.015 / 2.0
var actionsArray:[SKAction] = []
for _ in 1...Int(numberOfShakes) {
let dx = CGFloat(arc4random_uniform(UInt32(amplitudeX))) - CGFloat(amplitudeX / 2)
let dy = CGFloat(arc4random_uniform(UInt32(amplitudeY))) - CGFloat(amplitudeY / 2)
let forward = SKAction.moveBy(x: dx, y:dy, duration: 0.015)
let reverse = forward.reversed()
actionsArray.append(forward)
actionsArray.append(reverse)
}
return SKAction.sequence(actionsArray)
}
答案 6 :(得分:0)
-(void)screen_shake
{
if (shake)
{
current_number_of_shakes++;
float randx = (float)[self randomValueBetween:1 and:90]/50.0f;
if ([self randomValueBetween:0 and:1] == 0)
randx = -randx;
float randy = (float)[self randomValueBetween:1 and:90]/50.0f;
if ([self randomValueBetween:0 and:1] == 0)
randy = -randy;
camera.position = CGPointMake(camera.position.x + randx, camera.position.y + randy);
if (current_number_of_shakes >= total_amount_of_shakes)
{
current_number_of_shakes = 0;
move_back_from_shake = YES;
[camera runAction:[SKAction sequence:@[[SKAction moveTo:start_point_before_shake duration:.7], [SKAction performSelector:@selector(shake_done) onTarget:self]]]];
}
}
}
经过一些工作并参考人们做到这一点的方式Cocoa2D就是我想出来的。在您的更新方法中,您将需要调用此方法。有些常量可以填空,但我希望这对所有需要它的人都有帮助。另外,shake_done所做的所有方法都是将Bool的抖动更新为false。