Создание столкновения skspritenode с другим skspritenode с помощью изображения снаряда
Мне очень трудно понять, почему мой снаряд не выстрелит в образ люка. Я перепробовал много различных методов, чтобы попытаться противодействовать этому, но ни одна из стратегий, похоже, не сработала. Я бы очень хотел получить некоторые рекомендации и заранее извиниться за количество кода.
import SpriteKit import GameplayKit import AVFoundation import CoreMotion func +(left: CGPoint, right: CGPoint) -> CGPoint { return CGPoint(x: left.x + right.x, y: left.y + right.y) } func -(left: CGPoint, right: CGPoint) -> CGPoint { return CGPoint(x: left.x - right.x, y: left.y - right.y) } func *(point: CGPoint, scalar: CGFloat) -> CGPoint { return CGPoint(x: point.x * scalar, y: point.y * scalar) } func /(point: CGPoint, scalar: CGFloat) -> CGPoint { return CGPoint(x: point.x / scalar, y: point.y / scalar) } #if !(arch(x86_64) || arch(arm64)) func sqrt(a: CGFloat) -> CGFloat { return CGFloat(sqrtf(Float(a))) } #endif extension CGPoint { func length() -> CGFloat { return sqrt(x*x + y*y) } func normalized() -> CGPoint { return self / length() } } class GameScene: SKScene { struct PhysicsCategory { static let none : UInt32 = 0 static let all : UInt32 = UInt32.max static let enemy : UInt32 = 0b1 // 1 This is a way of saying each of the 32-bits in the integer represents a single category (and hence you can have 32 categories max). static let projectile: UInt32 = 0b10 // 2 Same as 1 } // let Interaction:UInt32 = 0x1 << 1 // let CollisionCategory:UInt32 = 0x1 << 0 var boxlabel:SKShapeNode! var starfield:SKEmitterNode! var player: SKSpriteNode! var player2 : SKSpriteNode! var ScoreLabel: SKLabelNode! var score: Int = 0 { didSet { ScoreLabel.text = "Score: \(score)" } } var seconds = 120 @objc var timer: Timer? override func didMove(to view: SKView) { func main() { // Create sprite let enemy = SKSpriteNode(imageNamed: "luke") enemy.physicsBody = SKPhysicsBody(rectangleOf: enemy.size) // This allows the card size to be equal to a rectangle enemy.physicsBody?.isDynamic = true // This says that the physics engine will not control the card enemy.physicsBody?.categoryBitMask = PhysicsCategory.enemy// 3 Set the category bit mask to be the main category defined earlier enemy.physicsBody?.contactTestBitMask = PhysicsCategory.projectile // 4 contactTestBitMask indicates when categories this object notify the contact listener when they intersect. You choose projectiles here enemy.physicsBody?.collisionBitMask = PhysicsCategory.none // 5 collisionBitMask indicates what categories of objects this object that the physics engine handle contact responses to (i.e. bounce off of). You don't want the monster and projectile to bounce off each other — it's OK for them to go right through each other in this game — so you set this to .none. // Determine where to spawn the card along the Y axis let actualY = random(min: enemy.size.width/2, max: size.width - enemy.size.width/2) // Position the card slightly off-screen along the right edge, // and along a random position along the Y axis as calculated above enemy.position = CGPoint(x: actualY, y: size.width + enemy.size.width/2) // Add the card to the scene addChild(enemy) // Determine speed of the card let actualDuration = random(min: CGFloat(2.0), max: CGFloat(6.0)) // Create the actions let actionMove = SKAction.move(to: CGPoint(x: actualY, y: - enemy.size.width/10), duration: TimeInterval(actualDuration)) let actionMoveDone = SKAction.removeFromParent() enemy.run(SKAction.sequence([actionMove, actionMoveDone])) } player = SKSpriteNode(imageNamed: "spaceship-modified") // The line below with the numbers 45, 25 and 540 are also stubs player.position = CGPoint(x: self.frame.size.width/45, y: player.frame.size.height/25 - 410) addChild(player) physicsWorld.gravity = .zero physicsWorld.contactDelegate = self run(SKAction.repeatForever( SKAction.sequence([ SKAction.run(main), SKAction.wait(forDuration: 1.0) ]) )) func random() -> CGFloat { return CGFloat(Float(arc4random()) / 4294967295) } func random(min: CGFloat, max: CGFloat) -> CGFloat { return random() * (max - min) + min } func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) { // 1 - Choose one of the touches to work with guard let touch = touches.first else { return } let touchLocation = touch.location(in: self) // 2 - Set up initial location of projectile let projectile = SKSpriteNode(imageNamed: "projectile") projectile.position = player.position projectile.physicsBody = SKPhysicsBody(circleOfRadius: projectile.size.width/2) projectile.physicsBody?.isDynamic = true projectile.physicsBody?.categoryBitMask = PhysicsCategory.projectile projectile.physicsBody?.contactTestBitMask = PhysicsCategory.enemy projectile.physicsBody?.collisionBitMask = PhysicsCategory.none projectile.physicsBody?.usesPreciseCollisionDetection = true // 3 - Determine offset of location to projectile let offset = touchLocation - projectile.position // 4 - Bail out if you are shooting down or backwards if offset.x < 0 { return } // 5 - OK to add now - you've double checked position addChild(projectile) // 6 - Get the direction of where to shoot let direction = offset.normalized() // 7 - Make it shoot far enough to be guaranteed off screen let shootAmount = direction * 1000 // 8 - Add the shoot amount to the current position let realDest = shootAmount + projectile.position // 9 - Create the actions let actionMove = SKAction.move(to: realDest, duration: 4.0) let actionMoveDone = SKAction.removeFromParent() projectile.run(SKAction.sequence([actionMove, actionMoveDone])) } } } func projectileDidCollideWithMonster(projectile: SKSpriteNode, enemy: SKSpriteNode) { print("Hit") projectile.removeFromParent() enemy.removeFromParent() } extension GameScene: SKPhysicsContactDelegate { func didBegin(_ contact: SKPhysicsContact) { // 1 var firstBody: SKPhysicsBody var secondBody: SKPhysicsBody if contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask { firstBody = contact.bodyA secondBody = contact.bodyB } else { firstBody = contact.bodyB secondBody = contact.bodyA } // 2 if ((firstBody.categoryBitMask & PhysicsCategory.enemy != 0) && (secondBody.categoryBitMask & PhysicsCategory.projectile != 0)) { if let enemy = firstBody.node as? SKSpriteNode, let projectile = secondBody.node as? SKSpriteNode { projectileDidCollideWithMonster(projectile: projectile, enemy: enemy ) } } } }
Что я уже пробовал:
Я пытался изменить расположение некоторых элементов, но, как бы я ни старался, снаряд не показывается. Честно говоря, я не знаю, что еще попробовать.