所以我有一个由玩家控制的精灵倾斜他们的设备,我需要让其他精灵具有相同的“细节/特征”,就像转弯作为第一个,但是跟随它而不是被设备控制瓷砖。这是我的代码:
import SpriteKit
import CoreMotion
let Pi = CGFloat(M_PI)
let DegreesToRadians = Pi / 180
let RadiansToDegrees = 180 / Pi
class GameScene: SKScene {
var snakeHead = SKSpriteNode()
var snakeBody = SKSpriteNode()
var food = SKSpriteNode()
var Obstacle = SKSpriteNode()
var accelerometerX: UIAccelerationValue = 0
var accelerometerY: UIAccelerationValue = 0
let motionManager = CMMotionManager()
var lastUpdateTime: CFTimeInterval = 0
var playerAcceleration = CGVector(dx: 0, dy: 0)
var playerVelocity = CGVector(dx: 0, dy: 0)
let MaxPlayerAcceleration: CGFloat = 150
let MaxPlayerSpeed: CGFloat = 100
//Change speed of character and acceleration
let BorderCollisionDamping: CGFloat = 0.8
//Change speed after colliding with border
var playerAngle: CGFloat = 0
var previousAngle: CGFloat = 0
let ObstacleCollisionRadius: CGFloat = 35
let PlayerHeadCollisionRadius: CGFloat = 30
//Radius of collision zone for the player and the obstacles
let PlayerBodyCollisionRadius: CGFloat = 0
//*** IGNORE ***
let collisionSound = SKAction.playSoundFileNamed("Collision/Death.wav", waitForCompletion: false)
//File name to play on player's collision with obstacle
let CollisionDamping: CGFloat = 0.8
//*** TO BE REMOVED - JUST FOR EXPERIMENTAL *** Change bounce off obstacle
override func didMoveToView(view: SKView) {
/* Setup your scene here */
snakeHead = SKSpriteNode(imageNamed: "snakeHead")
snakeHead.size = CGSize(width: 60, height: 60)
snakeHead.position = CGPoint(x: self.frame.midX, y: self.frame.midY - 50)
self.addChild(snakeHead)
snakeBody = SKSpriteNode(imageNamed: "snakeBody")
snakeBody.size = CGSize(width: 50, height: 50)
snakeBody.position = CGPoint(x: self.frame.midX, y: self.frame.midY - 100)
self.addChild(snakeBody)
Obstacle = SKSpriteNode(imageNamed: "Obstacle")
Obstacle.size = CGSize(width: 70, height: 70)
Obstacle.position = CGPoint(x: self.frame.midX, y: self.frame.midY)
self.addChild(Obstacle)
startMonitoringAcceleration()
}
deinit {
stopMonitoringAcceleration()
}
func startMonitoringAcceleration() {
if motionManager.accelerometerAvailable {
motionManager.startAccelerometerUpdates()
NSLog("accelerometer updates on...")
}
}
func stopMonitoringAcceleration() {
if motionManager.accelerometerAvailable && motionManager.accelerometerActive {
motionManager.stopAccelerometerUpdates()
NSLog("accelerometer updates off...")
}
}
func updatePlayerAccelerationFromMotionManager() {
if let acceleration = motionManager.accelerometerData?.acceleration {
let FilterFactor = 0.75
accelerometerX = acceleration.x * FilterFactor + accelerometerX * (1 - FilterFactor)
accelerometerY = acceleration.y * FilterFactor + accelerometerY * (1 - FilterFactor)
playerAcceleration.dx = CGFloat(accelerometerY) * -MaxPlayerAcceleration
playerAcceleration.dy = CGFloat(accelerometerX) * MaxPlayerAcceleration
}
}
func checkShipCannonCollision() {
let deltaX = snakeHead.position.x - Obstacle.position.x
let deltaY = snakeHead.position.y - Obstacle.position.y
let distance = sqrt(deltaX * deltaX + deltaY * deltaY)
if distance <= ObstacleCollisionRadius + PlayerHeadCollisionRadius {
runAction(collisionSound)
playerAcceleration.dx = -playerAcceleration.dx * CollisionDamping
playerAcceleration.dy = -playerAcceleration.dy * CollisionDamping
playerVelocity.dx = -playerVelocity.dx * CollisionDamping
playerVelocity.dy = -playerVelocity.dy * CollisionDamping
//This code adds the bouce when it collides, this is experimental
let offsetDistance = ObstacleCollisionRadius + PlayerHeadCollisionRadius - distance
let offsetX = deltaX / distance * offsetDistance
let offsetY = deltaY / distance * offsetDistance
snakeHead.position = CGPoint(
x: snakeHead.position.x + offsetX,
y: snakeHead.position.y + offsetY)
}
}
func updatePlayer(dt: CFTimeInterval) {
// 1
playerVelocity.dx = playerVelocity.dx + playerAcceleration.dx * CGFloat(dt)
playerVelocity.dy = playerVelocity.dy + playerAcceleration.dy * CGFloat(dt)
// 2
playerVelocity.dx = max(-MaxPlayerSpeed, min(MaxPlayerSpeed, playerVelocity.dx))
playerVelocity.dy = max(-MaxPlayerSpeed, min(MaxPlayerSpeed, playerVelocity.dy))
// 3
var newX = snakeHead.position.x + playerVelocity.dx * CGFloat(dt)
var newY = snakeHead.position.y + playerVelocity.dy * CGFloat(dt)
var collidedWithVerticalBorder = false
var collidedWithHorizontalBorder = false
if newX < 0 {
newX = 0
collidedWithVerticalBorder = true
} else if newX > size.width {
newX = size.width
collidedWithVerticalBorder = true
}
if newY < 0 {
newY = 0
collidedWithHorizontalBorder = true
} else if newY > size.height {
newY = size.height
collidedWithHorizontalBorder = true
}
if collidedWithVerticalBorder {
playerAcceleration.dx = -playerAcceleration.dx * BorderCollisionDamping
playerVelocity.dx = -playerVelocity.dx * BorderCollisionDamping
playerAcceleration.dy = playerAcceleration.dy * BorderCollisionDamping
playerVelocity.dy = playerVelocity.dy * BorderCollisionDamping
}
if collidedWithHorizontalBorder {
playerAcceleration.dx = playerAcceleration.dx * BorderCollisionDamping
playerVelocity.dx = playerVelocity.dx * BorderCollisionDamping
playerAcceleration.dy = -playerAcceleration.dy * BorderCollisionDamping
playerVelocity.dy = -playerVelocity.dy * BorderCollisionDamping
}
snakeHead.position = CGPoint(x: newX, y: newY)
let RotationThreshold: CGFloat = 10
let RotationBlendFactor: CGFloat = 0.2
let speed = sqrt(playerVelocity.dx * playerVelocity.dx + playerVelocity.dy * playerVelocity.dy)
if speed > RotationThreshold {
let angle = atan2(playerVelocity.dy, playerVelocity.dx)
// did angle flip from +π to -π, or -π to +π?
if angle - previousAngle > Pi {
playerAngle += 2 * Pi
} else if previousAngle - angle > Pi {
playerAngle -= 2 * Pi
}
previousAngle = angle
playerAngle = angle * RotationBlendFactor + playerAngle * (1 - RotationBlendFactor)
snakeHead.zRotation = playerAngle - 90 * DegreesToRadians
}
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
/* Called when a touch begins */
}
override func update(currentTime: CFTimeInterval) {
/* Called before each frame is rendered */
// to compute velocities we need delta time to multiply by points per second
// SpriteKit returns the currentTime, delta is computed as last called time - currentTime
let deltaTime = max(1.0/30, currentTime - lastUpdateTime)
lastUpdateTime = currentTime
updatePlayerAccelerationFromMotionManager()
updatePlayer(deltaTime)
checkShipCannonCollision()
}
}