gpt4 book ai didi

swift - 塔防 : turret tracking enemy and shooting issues

转载 作者:行者123 更新时间:2023-11-28 06:16:14 25 4
gpt4 key购买 nike

这是我的代码:

func bombTowerTurnShoot() {
var prevDistance:CGFloat = 1000000
var closesetZombie = zombieArray[0]
self.enumerateChildNodes(withName: "bomb tower") {
node, stop in
if self.zombieArray.count > 0 {
for zombie in self.zombieArray {
if let bombTower = node as? SKSpriteNode {
let angle = atan2(closesetZombie.position.x - bombTower.position.x , closesetZombie.position.y - bombTower.position.y)
let actionTurn = SKAction.rotate(toAngle: -(angle - CGFloat(Double.pi/2)), duration: 0.2)
bombTower.run(actionTurn)
let turretBullet = SKSpriteNode(imageNamed: "Level 1 Turret Bullet")
turretBullet.position = bombTower.position
turretBullet.zPosition = 20
turretBullet.size = CGSize(width: 20, height: 20)
//turretBullet.setScale (frame.size.height / 5000)
turretBullet.physicsBody = SKPhysicsBody(circleOfRadius: max(turretBullet.size.width / 2, turretBullet.size.height / 2))
turretBullet.physicsBody?.affectedByGravity = false
turretBullet.physicsBody!.categoryBitMask = PhysicsCategories.Bullet //new contact
turretBullet.physicsBody!.collisionBitMask = PhysicsCategories.None
turretBullet.physicsBody!.contactTestBitMask = PhysicsCategories.Zombie
self.addChild(turretBullet)
var dx = CGFloat(closesetZombie.position.x - bombTower.position.x)
var dy = CGFloat(closesetZombie.position.y - bombTower.position.y)
let magnitude = sqrt(dx * dx + dy * dy)
dx /= magnitude
dy /= magnitude
let vector = CGVector(dx: 4.0 * dx, dy: 4.0 * dy)
func fire () {
turretBullet.physicsBody?.applyImpulse(vector)
}
func deleteBullet() {
turretBullet.removeFromParent()
}
turretBullet.run(SKAction.sequence([SKAction.wait(forDuration: 0), SKAction.run(fire), SKAction.wait(forDuration: 2.0), SKAction.run(deleteBullet) ]))

let distance = hypot(zombie.position.x - bombTower.position.x, zombie.position.y - bombTower.position.y)
if distance < prevDistance {
prevDistance = distance
closesetZombie = zombie
}


}
}
}
}
}

此代码的作用是将炮塔转向最近的僵尸并向其射击。据我所知,炮塔正在转向最近的僵尸(如果你能判断这段代码是否真正实现了这一点,我想知道)。我遇到的更大问题是炮塔有时会发射不止一颗子弹。我认为这是因为它试图向阵列中的所有僵尸开火,而不是指定的僵尸(最靠近塔)。我怎样才能让炮塔只射击最近的僵尸?

class GameScene: SKScene, SKPhysicsContactDelegate {//new contact
var zombieArray:[SKSpriteNode] = []
...
...
}

我将所有僵尸添加到数组中,一旦它们死亡,我就将它们从数组中移除。

最佳答案

基本上,我不知道你究竟做错了什么。你有很多事情要做,试图找出错误可能比重写它花费的时间更长(至少对我而言)。这就是我所做的。

这里是github上项目的链接:

https://github.com/fluidityt/ShootClosestZombie/tree/master

对我来说,这就是将操作分离为不同的方法,并将一般操作与逻辑分离。

您有太多事情要做,很难测试/查看哪些部分工作正常或不正常。这就是使用更小的方法以及将操作与逻辑分开的地方。您的操作可能工作正常,但可能由于逻辑错误而未被调用。

所以,我实现它的方法是让你的炸弹炮塔成为它自己的类。这样我们就可以让炸弹炮塔负责它的大部分 Action ,然后让 gameScene 处理大部分的实现/和或逻辑。

我上传的演示展示了两个炮塔,它们每帧自动将自己定位到最近的僵尸,然后每秒向它们射击。点击屏幕添加更多僵尸。

炮塔独立地跟踪最近的僵尸到他们所以如果你在左边和右边生成一个僵尸,那么左边的炮塔会射击左边的僵尸,右边的炮塔会射击右边的僵尸(而且只有一次!)。

enter image description here

class BombTower: SKSpriteNode {

static let bombName = "bomb tower"

var closestZombie: SKSpriteNode!

func updateClosestZombie() {
let gameScene = (self.scene! as! GameScene)
let zombieArray = gameScene.zombieArray

var prevDistance:CGFloat = 1000000
var closestZombie = zombieArray[0]

for zombie in zombieArray {

let distance = hypot(zombie.position.x - self.position.x, zombie.position.y - self.position.y)
if distance < prevDistance {
prevDistance = distance
closestZombie = zombie
}
}
self.closestZombie = closestZombie
}

func turnTowardsClosestZombie() {
let angle = atan2(closestZombie.position.x - self.position.x , closestZombie.position.y - self.position.y)
let actionTurn = SKAction.rotate(toAngle: -(angle - CGFloat(Double.pi/2)), duration: 0.2)
self.run(actionTurn)
}

private func makeTurretBullet() -> SKSpriteNode {
let turretBullet = SKSpriteNode(imageNamed: "Level 1 Turret Bullet")
turretBullet.position = self.position
turretBullet.zPosition = 20
turretBullet.size = CGSize(width: 20, height: 20)
//turretBullet.setScale (frame.size.height / 5000)

turretBullet.physicsBody = SKPhysicsBody(circleOfRadius: max(turretBullet.size.width / 2, turretBullet.size.height / 2))
turretBullet.physicsBody?.affectedByGravity = false
// turretBullet.physicsBody!.categoryBitMask = PhysicsCategories.Bullet //new contact
// turretBullet.physicsBody!.collisionBitMask = PhysicsCategories.None
// turretBullet.physicsBody!.contactTestBitMask = PhysicsCategories.Zombie

return turretBullet
}

private func fire(turretBullet: SKSpriteNode) {
var dx = CGFloat(closestZombie.position.x - self.position.x)
var dy = CGFloat(closestZombie.position.y - self.position.y)
let magnitude = sqrt(dx * dx + dy * dy)
dx /= magnitude
dy /= magnitude

let vector = CGVector(dx: 4.0 * dx, dy: 4.0 * dy)

turretBullet.physicsBody?.applyImpulse(vector)
}

func addBulletThenShootAtClosestZOmbie() {
let bullet = makeTurretBullet()
scene!.addChild(bullet)
fire(turretBullet: bullet)
}
}

// TODO: delete bullets, hit detection, and add SKConstraint for tracking instead of update.
// Also, I think that we are iterating too much looking for nodes. Should be able to reduce that.
// Also also, there are sure to be bugs if zombieArray is empty.
class GameScene: SKScene {

var zombieArray: [SKSpriteNode] = []

private func makeBombArray() -> [BombTower]? {
guard self.zombieArray.count > 0 else { return nil }

var towerArray: [BombTower] = []
self.enumerateChildNodes(withName: BombTower.bombName) { node, _ in towerArray.append(node as! BombTower) }
guard towerArray.count > 0 else { return nil }

return towerArray
}

private func towersShootEverySecond(towerArray: [BombTower]) {

let action = SKAction.run {
for bombTower in towerArray {
guard bombTower.closestZombie != nil else { continue } // I haven't tested this guard statement yet.
bombTower.addBulletThenShootAtClosestZOmbie()
}
}
self.run(.repeatForever(.sequence([.wait(forDuration: 1), action])))
}

override func didMove(to view: SKView) {
// Demo setup:
removeAllChildren()

makeTestZombie: do {
spawnZombie(at: CGPoint.zero)
}
makeTower1: do {
let tower = BombTower(color: .yellow, size: CGSize(width: 55, height: 55))
let turretGun = SKSpriteNode(color: .gray, size: CGSize(width: 25, height: 15))
turretGun.position.x = tower.frame.maxX + turretGun.size.height/2
tower.name = BombTower.bombName
tower.addChild(turretGun)
addChild(tower)
}
makeTower2: do {
let tower = BombTower(color: .yellow, size: CGSize(width: 55, height: 55))
let turretGun = SKSpriteNode(color: .gray, size: CGSize(width: 25, height: 15))
turretGun.position.x = tower.frame.maxX + turretGun.size.height/2
tower.addChild(turretGun)
tower.position.x += 200
tower.name = BombTower.bombName
addChild(tower)
}

guard let towerArray = makeBombArray() else { fatalError("couldn't make array!") }

towersShootEverySecond(towerArray: towerArray)
}

private func spawnZombie(at location: CGPoint) {
let zombie = SKSpriteNode(color: .blue, size: CGSize(width: 35, height: 50))
zombieArray.append(zombie)
zombie.position = location
zombie.run(.move(by: CGVector(dx: 3000, dy: -3000), duration: 50))
addChild(zombie)
}

// Just change this to touchesBegan for it to work on iOS:
override func mouseDown(with event: NSEvent) {
let location = event.location(in: self)
spawnZombie(at: location)
}

// I think this could be a constrain or action, but I couldn't get either to work right now.
private func keepTowersTrackingNearestZombie() {
guard let towerArray = makeBombArray() else { return }
for tower in towerArray {
tower.updateClosestZombie()
tower.turnTowardsClosestZombie()
}
}

override func update(_ currentTime: TimeInterval) {
keepTowersTrackingNearestZombie()
}
}

关于swift - 塔防 : turret tracking enemy and shooting issues,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45071517/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com