gpt4 book ai didi

ios - GKAgent 不会更新在 ARKit/SCNScene/GamplayKit 游戏中注册为实体的 SCNNode 的位置

转载 作者:可可西里 更新时间:2023-11-01 01:50:28 26 4
gpt4 key购买 nike

我正在使用 GKAgent 移动注册为实体的 SCNNode,分配了一个团队组件和一个移动组件。正在触发 agentWillUpdate 和 agentDidUpdate 方法,但添加到场景的实体的位置拒绝更新它们的位置。有没有办法让 GKAgent 根据以下移动行为更新位置?

亲切的问候,

蒙特勒

移动组件.swift

import SceneKit
import GameplayKit

extension float3 {
var length: Float {
return sqrt(x*x + y*y + z*z)
}
}

class MoveComponent: GKAgent3D, GKAgentDelegate {
let entityManager: EntityManager!

init(maxSpeed: Float, maxAcceleration: Float, radius: Float, entityManager: EntityManager) {
self.entityManager = entityManager
super.init()
self.delegate = self
self.maxSpeed = maxSpeed
self.maxAcceleration = maxAcceleration
self.radius = radius
print(self.mass)
self.mass = 0.01
}


func agentWillUpdate(_ agent: GKAgent) {

guard let spriteComponent = entity?.component(ofType: SpriteComponent.self) else
{
return
}


let pos = spriteComponent.node.presentation.position
print("Agent Will Update \(spriteComponent.node.name) from \(pos) to \(self.position)")

self.position = float3(pos)

}

func agentDidUpdate(_ agent: GKAgent) {
guard let spriteComponent = entity?.component(ofType: SpriteComponent.self) else {
return

}
spriteComponent.node.position = vec3(self.position)

print("Agent DID Update to: \(spriteComponent.node.name) to \(position)")


let xVelocity = self.velocity.x
let zVelocity = self.velocity.z

let angle = -Float(atan2(zVelocity, xVelocity)) + Float.pi/2

spriteComponent.node.rotation = SCNVector4(0,1,0, angle)


}
func closestMoveComponent(_ team: Team) -> GKAgent3D? {
let moveComponents = entityManager.moveComponentsForTeam(team)
var closestMoveComponent: GKAgent3D? = nil
var closestDistance: Float = MAXFLOAT

for component in moveComponents {
let distance = (self.position - component.position).length
if distance < closestDistance {
closestDistance = distance
closestMoveComponent = component
}
}
return closestMoveComponent
}


override func update(deltaTime seconds: TimeInterval) {


// Determine team
guard let entity = entity,
let teamComponent = entity.component(ofType: TeamComponent.self) else {
return
}

// Find team castle
guard let team = entityManager.castleForTeam(teamComponent.team),
let teamCastleComponent = team.component(ofType: HeroComponent.self),
let teamMoveComponent = team.component(ofType: MoveComponent.self) else {
return
}

var targetMoveComponent: GKAgent3D

if teamCastleComponent.attacking {

// Find closest enemy
guard let enemyMoveComponent = closestMoveComponent( teamComponent.team.oppositeTeam()) else {
print("No Opposite enemy components for Agent!!!")
return
}
targetMoveComponent = enemyMoveComponent

// Override target for ranged attackers
if let fireComponent = entity.component(ofType: ParticleComponent.self) {
let newTarget = GKAgent3D()
let node1Pos = SCNVector3ToGLKVector3(SCNVector3(targetMoveComponent.position))
let node2Pos = SCNVector3ToGLKVector3(SCNVector3(position))
let distance = GLKVector3Distance(node1Pos, node2Pos)

newTarget.position = float3(x: targetMoveComponent.position.x, y: targetMoveComponent.position.y, z: targetMoveComponent.position.z * Float(fireComponent.range))
// newTarget.position = float3(targetMoveComponent.position + direction * fireComponent.range)
targetMoveComponent = newTarget
}
} else {

targetMoveComponent = teamMoveComponent

}

// Find allies
let alliedMoveComponents = entityManager.moveComponentsForTeam(teamComponent.team)

// Reset behavior
// print("Reset move behavior")
self.behavior = MoveBehavior(targetSpeed: maxSpeed, seek: targetMoveComponent, avoid: alliedMoveComponents)
print("Agent moving to \(targetMoveComponent), avoiding \(alliedMoveComponents)")
super.update(deltaTime: seconds)

}

required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}


}

移动行为.swift

import GameplayKit
import SceneKit

class MoveBehavior: GKBehavior {

init(targetSpeed: Float, seek: GKAgent3D, avoid: [GKAgent3D]) {
super.init()

if targetSpeed > 0 {
print("Running Move Behavior")
setWeight(0.1, for: GKGoal(toReachTargetSpeed: targetSpeed))
setWeight(0.5, for: GKGoal(toSeekAgent: seek))
setWeight(1.0, for: GKGoal(toAvoid: avoid, maxPredictionTime: 1.0))
}
}
}

EntityManager.swift

import Foundation
import Foundation
import ARKit
import SceneKit
import GameplayKit

class EntityManager {
var toRemove = Set<GKEntity>()
let costQuirk = 20
lazy var componentSystems: [GKComponentSystem] = {
let moveSystem = GKComponentSystem(componentClass: MoveComponent.self)
let meleeSystem = GKComponentSystem(componentClass: MeleeComponent.self)
let firingSystem = GKComponentSystem(componentClass: ParticleComponent.self)
let castleSystem = GKComponentSystem(componentClass: HeroComponent.self)
let heroSystem = GKComponentSystem(componentClass: HeroComponent.self)
let aiSystem = GKComponentSystem(componentClass: AiComponent.self)
let nodeComponent = GKComponentSystem(componentClass: NodeComponent.self)
return [moveSystem, meleeSystem, firingSystem, castleSystem, aiSystem,heroSystem,nodeComponent]
}()

// 1
var entities: Set<GKEntity>

let scene: SCNScene

// 2
init(scene: SCNScene) {
self.scene = scene
self.entities = Set<GKEntity>()
}

// 3
func add(_ entity: GKEntity) {

if let spriteNode = entity.component(ofType: SpriteComponent.self)?.node {
scene.rootNode.addChildNode(spriteNode)
let speed = Int.random(in: 7 ... 10)
let smoke = SCNParticleSystem(named: "art.scnassets/Models/spawnSmoke.scnp", inDirectory: nil)
let smokeNode = SCNNode()
spriteNode.addChildNode(smokeNode)
print("Monster Added")
}
for componentSystem in componentSystems {
componentSystem.addComponent(foundIn: entity)
}
entities.insert(entity)
}

// 4
func remove(_ entity: GKEntity) {
if let spriteNode = entity.component(ofType: SpriteComponent.self)?.node {
let confetti = SCNParticleSystem(named: "Media.scnassets/Fire.scnp", inDirectory: nil)
confetti?.loops = false
confetti?.particleLifeSpan = 0.05
confetti?.particleSize -= 1
confetti?.particleIntensity -= 0.5
print("Making Explosion")
if let geometry = spriteNode.geometry {
confetti?.emitterShape = geometry
}
spriteNode.addParticleSystem(confetti!)
print("Exploding Node!")
DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(3)) {
spriteNode.removeFromParentNode()
spriteNode.removeAllActions()
self.entities.remove(entity)
self.toRemove.insert(entity)

}

}
entities.remove(entity)
}
func update(_ deltaTime: CFTimeInterval) {
// 1
for system in componentSystems {
system.update(deltaTime: deltaTime)
}

// 2
for currentRemove in toRemove {
for componentSystem in componentSystems {
componentSystem.removeComponent(foundIn: currentRemove)
}
}
toRemove.removeAll()

}
func castle(for team: Team) -> GKEntity? {
for entity in self.entities {
if let teamComponent = entity.component(ofType: TeamComponent.self),
let _ = entity.component(ofType: HeroComponent.self) {
if teamComponent.team == team {
return entity
}
}
}
return nil
}

func spawnQuirk(team: Team , positon: SCNVector3) {
// 1
guard let teamEntity = castle(for: team) else {return}


// 2
if let teamCastleComponent = teamEntity.component(ofType: HeroComponent.self) {
if teamCastleComponent.coins < costQuirk , team == .team1{
return
}
teamCastleComponent.coins -= costQuirk
}



// 3
guard let floor = GAMEFLOOR as? SCNNode else {return}
let monster = Quirk(team: team, entityManager: self, floor:floor)
if let spriteComponent = monster.component(ofType: SpriteComponent.self) {
let randomX = Float.random(in: -10.0 ... -0.0)
let randomZ = Float.random(in: -10.0 ... -1.0)
spriteComponent.node.position = positon
let teamRing = SCNParticleSystem(named: "Media.scnassets/teamRing.scnp", inDirectory: nil)

switch team {
case .team1 :
teamRing?.particleColor = .blue
case .team2:
teamRing?.particleColor = .red


}
spriteComponent.node.addParticleSystem(teamRing!)
}


add(monster)

}
func spawnZap(_ team: Team, positon: SCNVector3) {
guard let teamEntity = castle(for: team) else {return}

if let teamCastleComponent = teamEntity.component(ofType: HeroComponent.self) {
if teamCastleComponent.coins < costZap , team == .team1{
return
}

teamCastleComponent.coins -= costZap

let monster = Zap(team: team, entityManager: self)
if let spriteComponent = monster.component(ofType: SpriteComponent.self) {
let randomX = Float.random(in: -10.0 ... -0.0)
let randomZ = Float.random(in: -10.0 ... -1.0)
spriteComponent.node.position = positon

}
add(monster)
}
}

func spawnMunch(_ team: Team, positon: SCNVector3) {
guard let teamEntity = castleForTeam(team),
let teamCastleComponent = teamEntity.component(ofType: HeroComponent.self),
let teamSpriteComponent = teamEntity.component(ofType: SpriteComponent.self) else {
return
}

if teamCastleComponent.coins < costMunch {
return
}

teamCastleComponent.coins -= costMunch
guard let floor = GAMEFLOOR as? SCNNode else {return}

let monster = Munch(team: team, entityManager: self, floor:floor)
if let spriteComponent = monster.component(ofType: SpriteComponent.self) {
let randomX = Float.random(in: -10.0 ... -0.0)
let randomZ = Float.random(in: -10.0 ... -1.0)
spriteComponent.node.position = positon

}
add(monster)
}
func entitiesForTeam(_ team: Team) -> [GKEntity] {

return entities.compactMap{ entity in
if let teamComponent = entity.component(ofType: TeamComponent.self) {
if teamComponent.team == team {
return entity
}
}
return nil
}

}

func moveComponentsForTeam(_ team: Team) -> [MoveComponent] {
let entities = entitiesForTeam(team)
var moveComponents = [MoveComponent]()
for entity in entities {
if let moveComponent = entity.component(ofType: MoveComponent.self) {
moveComponents.append(moveComponent)
}
}
return moveComponents
}

func castleForTeam(_ team: Team) -> GKEntity? {
for entity in entities {
if let teamComponent = entity.component(ofType: TeamComponent.self),
let _ = entity.component(ofType: HeroComponent.self) {
if teamComponent.team == team {
return entity
}
}
}
return nil
}
func entities(for team: Team) -> [GKEntity] {
return entities.compactMap{ entity in
if let teamComponent = entity.component(ofType: TeamComponent.self) {
if teamComponent.team == team {
return entity
}
}
return nil
}
}

func moveComponents(for team: Team) -> [MoveComponent] {
let entitiesToMove = entities(for: team)
var moveComponents = [MoveComponent]()
for entity in entitiesToMove {
if let moveComponent = entity.component(ofType: MoveComponent.self) {
moveComponents.append(moveComponent)
}
}
return moveComponents
}
}

最佳答案

长话短说

我宁愿使用 GKSCNNodeComponent 作为代理的委托(delegate),它会自动处理相互位置更新。

如果一个组件被添加到一个组件系统,更新实体将不会影响它。

也许更新组件系统的顺序很重要。

关于ios - GKAgent 不会更新在 ARKit/SCNScene/GamplayKit 游戏中注册为实体的 SCNNode 的位置,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54792972/

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