Sprite kit 场景中来自不同层的节点将不会交互
提前道歉,因为这个问题涉及代码分配。 我有一个游戏场景,有多个层包含HUD/分数/等的节点/精灵节点。其中一个层,LayerProjectile,包含一个武器实体 所述实体具有精灵和物理组件。 问题是LayerProjectle中的投射节点不与游戏场景的主层(worldLayer)中的节点交互 所有物理实体都是动态的,游戏场景有其物理世界大门Sprite kit 场景中来自不同层的节点将不会交互,sprite-kit,swift2,collision-detection,game-physics,Sprite Kit,Swift2,Collision Detection,Game Physics,提前道歉,因为这个问题涉及代码分配。 我有一个游戏场景,有多个层包含HUD/分数/等的节点/精灵节点。其中一个层,LayerProjectile,包含一个武器实体 所述实体具有精灵和物理组件。 问题是LayerProjectle中的投射节点不与游戏场景的主层(worldLayer)中的节点交互 所有物理实体都是动态的,游戏场景有其物理世界大门 class GamePlayMode: SGScene, SKPhysicsContactDelegate {... //武器属性(SGEntity是G
class GamePlayMode: SGScene, SKPhysicsContactDelegate {...
//武器属性(SGEntity是GK实体)
类throwEapon:SGEntity{
var spriteComponent: SpriteComponent!
var physicsComponent: PhysicsComponent
init(position: CGPoint, size: CGSize, texture:SKTexture){
super.init();
//Initilse Compnemnets
spriteComponent = SpriteComponent(entity: self, texture: texture, size: size, position: position);
addComponent(spriteComponent);
physicsComponent = PhysicsComponent(entity: self, bodySize: CGSize(width: spriteComponent.node.size.width * 0.8, height: spriteComponent.node.size.height * 0.8), bodyShape: .square, rotation: true);
physicsComponent.setCategoryBitmask(ColliderType.Projectile.rawValue, dynamic: true);
physicsComponent.setPhysicsCollisions(ColliderType.None.rawValue);
physicsComponent.setPhysicsContacts( ColliderType.Destroyable.rawValue | ColliderType.Enemy.rawValue);
physicsComponent.setEffectedByGravity(false);
addComponent(physicsComponent);
//Final Steps of compnements
spriteComponent.node.physicsBody = physicsComponent.physicsBody;
spriteComponent.node.name = "weapon";
name = "weapon";
spriteComponent.node.zPosition = 150;
spriteComponent.node.userData = ["startX" : position.x];
//处理联系人
覆盖func contactWith(实体:SGEntity){
//如果与GemeScene中的Enity接触
switch entity.name {
case "destructableEntity":
//Remove from Scsene self.parent?.parent?.runAction(SKAction.playSoundFileNamed("110548__noisehag__comp-cover-02.wav", waitForCompletion: false))
if let spriteComponentDestructable = entity.componentForClass(SpriteComponent.self){
let pos = spriteComponentDestructable.node.position;
spriteComponent.node.removeFromParent();
spriteComponentDestructable.node.parent?.runAction(SKAction.playSoundFileNamed("110548__noisehag__comp-cover-02.wav", waitForCompletion: false));
spriteComponentDestructable.node.removeAllActions();
spriteComponentDestructable.node.removeFromParent();
emitterExplosion(pos);
}
// self.runAction(SKAction.sequence([SKAction.fadeAlphaTo(0.0, duration: 0.5), SKAction.removeFromParent()]))
break;
case "enemyEntity":
if let spriteComponentEnemy = entity.componentForClass(SpriteComponent.self){
let pos = spriteComponentEnemy.node.position;
spriteComponent.node.removeFromParent();
spriteComponentEnemy.node.parent?.runAction(SKAction.playSoundFileNamed("110548__noisehag__comp-cover-02.wav", waitForCompletion: false));
spriteComponentEnemy.node.removeAllActions();
spriteComponentEnemy.node.removeFromParent();
emitterExplosion(pos);
} break;
default:
//
break;
}
LayerProjectile,继承自Layer-a SKNode,处理添加到游戏场景中的所有武器实体
class LayerProjectiles: Layer {
override func updateNodes(delta:CFTimeInterval,childNumber:Int,childNode: SKNode) {
print("Player movenment direction: \(playerMovingRighToLeft)");
if playerMovingRighToLeft {
// player moving to right so throw weapon same direction
childNode.position = childNode.position + CGPoint(x: delta * -weaponSpeed, y: 0.0);
childNode.zRotation = childNode.zRotation - (CGFloat(delta) * 10);
} else{
childNode.position = childNode.position + CGPoint(x: delta * weaponSpeed, y: 0.0)
childNode.zRotation = childNode.zRotation - (CGFloat(delta) * 10)
}
// When arrow within this layer moves out of the screen remove it, and the reverse
if childNode.position.x > ((childNode.userData!["startX"] as! CGFloat) + (SKMSceneSize!.width * 1.2)) || childNode.position.x < ((childNode.userData!["startX"]as! CGFloat) - (SKMSceneSize!.width * 1.2)){
childNode.removeFromParent()
}
}
最后是可破坏实体的物理/精灵组件设置,该实体是worldLayer的子实体(与LayerProject一起添加到GaemScene)
初始化游戏场景并添加所有精灵节点时武器投射物(当用户在游戏中点击投掷按钮时)和可破坏实体的实例化:
let throwWeapon = ThrowWeapon(position: CGPoint(x: self.spriteComponent.node.position.x, y: self.spriteComponent.node.position.y + (self.spriteComponent.node.size.height / 2)), size: CGSize(width: 9, height: 40), texture: textureAtlas.textureNamed("kunai"));
playerEnt.gameScene.layerProjectile.addChild(throwWeapon.spriteComponent.node);
//可破坏实体
gs.worldLayer.enumerateChildNodesWithName("placeholder_Destructable") { (node, stop) -> Void in
let crate = Destructable(position: node.position, size: CGSize(width: 32, height: 32), texture: tileAtlasInstance.textureNamed("Crate"));
//crate.name = "placeholder_Destructable";
//crate.spriteComponent.node.zPosition = GameSettings.GameParams.zValues.zWorldFront;
self.gs.addEntity(crate, toLayer: self.gs.worldLayer)
}
欢迎您的任何意见
添加:碰撞类型的类别位掩码枚举:
enum ColliderType:UInt32 {
case Player = 0
case Destroyable = 0b1
case Wall = 0b10
case Collectable = 0b100 // get points
case EndLevel = 0b1000
case Projectile = 0b10000
case None = 0b100000
case KillZone = 0b1000000
case arrow = 0b10000000;
case fire = 0b100000000; // die
case blueFire = 0b1000000000; // die
case greenCrystal = 0b10000000000; //more points like collectables
case barrel1 = 0b100000000000; //die
case barrell2 = 0b1000000000000; //die
case swordPoints = 0b10000000000000; //points
case spikes = 0b100000000000000; //die
case Enemy = 0b1000000000000000; // see Eneemy Entity
// against arrow and fire
}
//SGEnity类,其中在实体(武器、可破坏性)类中调用并重写处理ENITY的物理触点的func
类SGEntity:GKEntity{
var name=“”
func联系人(实体:SGEntity){
//被子类覆盖
}
//物理成分
enum PhysicsBodyShape {
case square
case squareOffset;// so the player knowns where the tile physics body is
case circle
case topOutline
case bottomOutline
}
class PhysicsComponent: GKComponent {
var physicsBody = SKPhysicsBody()
init(entity: GKEntity, bodySize: CGSize, bodyShape: PhysicsBodyShape, rotation: Bool) {
switch bodyShape {
case.square:
physicsBody = SKPhysicsBody(rectangleOfSize: bodySize)
break
case.squareOffset:
physicsBody = SKPhysicsBody(rectangleOfSize: bodySize, center: CGPoint(x: 0, y: bodySize.height/2 + 2))
break
case .circle:
physicsBody = SKPhysicsBody(circleOfRadius: bodySize.width / 2)
break
case .topOutline:
physicsBody = SKPhysicsBody(edgeFromPoint: CGPoint(x: (bodySize.width/2) * -1, y: bodySize.height/2), toPoint: CGPoint(x: bodySize.width/2, y: bodySize.height/2))
break
case .bottomOutline:
physicsBody = SKPhysicsBody(edgeFromPoint: CGPoint(x: (bodySize.width/2) * -1, y: (bodySize.height/2) * -1), toPoint: CGPoint(x: bodySize.width/2, y: (bodySize.height/2) * -1))
break
}
physicsBody.allowsRotation = rotation
//Defaults
physicsBody.dynamic = true
physicsBody.contactTestBitMask = ColliderType.None.rawValue
physicsBody.collisionBitMask = ColliderType.None.rawValue
}
func setCategoryBitmask(bitmask:UInt32, dynamic: Bool) {
physicsBody.categoryBitMask = bitmask
physicsBody.dynamic = dynamic
}
func setPhysicsCollisions(bitmask:UInt32) {
physicsBody.collisionBitMask = bitmask
}
func setPhysicsContacts(bitmask:UInt32) {
physicsBody.contactTestBitMask = bitmask
}
func setEffectedByGravity (gravity: Bool){
physicsBody.affectedByGravity = gravity;
}
}
因此,contactsBegan通过游戏场景的物理层调用:
if let bodyA = contact.bodyA.node as? EntityNode, //SpriteNode
let bodyAent = bodyA.entity as? SGEntity, // COnverted to SGEntity
let bodyB = contact.bodyB.node as? EntityNode, //SprtiteNode
let bodyBent = bodyB.entity as? SGEntity //ERROR HERE : Cast to SGEnity
{
print("SGENity Description: \(bodyBent)");
contactBegan(bodyAent, nodeB: bodyBent)
contactBegan(bodyBent, nodeB: bodyAent)
}else{
print("Cast error")
}
问题似乎是将射弹实体强制转换为SGEntity,此操作失败,并且从未调用射弹实体的…联系。所有其他SGEntity(可销毁)首先,你确定你的碰撞类型设置了正确的类别吗?例如,1,2,4…而不是1,2,3?正如我在上一个问题中所说的,检查是否至少有一个物体是动态的-这意味着,如果你的射弹与可摧毁的物体碰撞,至少其中一个物体必须是动态的。是的,你有set投射和可破坏节点为Dynamic,当我看到以下内容时,已将类别位掩码发布到Question:case“destructableEntity”:,我想到的第一个想法是-typo:)如果重复使用同一个字符串,请使用常量。现在,在处理投射对象和可破坏对象之间的接触的方法中放置一个断点,然后查看它在哪一点失败。您是否确定所有实体都设置了名称?我看不到处理项目之间接触的部分ectile&Destructurable实际上是可以的,但是如果它没有被调用,那么你应该仔细检查这些对象上的联系人和类别位掩码。我不知道还能说什么。代码太多了,所以我可能遗漏了一些东西。一个问题…你在哪里处理联系人?哪个类实现了didBeginContact和didEndContact方法?编辑:哦,我明白了…你处理每个实体中的联系人,对吗?是什么触发了contactWith:(entity:)方法?我的意思是,在你的代码中,你有类似于didBeginContact的东西,它会被物理引擎自动调用?
enum PhysicsBodyShape {
case square
case squareOffset;// so the player knowns where the tile physics body is
case circle
case topOutline
case bottomOutline
}
class PhysicsComponent: GKComponent {
var physicsBody = SKPhysicsBody()
init(entity: GKEntity, bodySize: CGSize, bodyShape: PhysicsBodyShape, rotation: Bool) {
switch bodyShape {
case.square:
physicsBody = SKPhysicsBody(rectangleOfSize: bodySize)
break
case.squareOffset:
physicsBody = SKPhysicsBody(rectangleOfSize: bodySize, center: CGPoint(x: 0, y: bodySize.height/2 + 2))
break
case .circle:
physicsBody = SKPhysicsBody(circleOfRadius: bodySize.width / 2)
break
case .topOutline:
physicsBody = SKPhysicsBody(edgeFromPoint: CGPoint(x: (bodySize.width/2) * -1, y: bodySize.height/2), toPoint: CGPoint(x: bodySize.width/2, y: bodySize.height/2))
break
case .bottomOutline:
physicsBody = SKPhysicsBody(edgeFromPoint: CGPoint(x: (bodySize.width/2) * -1, y: (bodySize.height/2) * -1), toPoint: CGPoint(x: bodySize.width/2, y: (bodySize.height/2) * -1))
break
}
physicsBody.allowsRotation = rotation
//Defaults
physicsBody.dynamic = true
physicsBody.contactTestBitMask = ColliderType.None.rawValue
physicsBody.collisionBitMask = ColliderType.None.rawValue
}
func setCategoryBitmask(bitmask:UInt32, dynamic: Bool) {
physicsBody.categoryBitMask = bitmask
physicsBody.dynamic = dynamic
}
func setPhysicsCollisions(bitmask:UInt32) {
physicsBody.collisionBitMask = bitmask
}
func setPhysicsContacts(bitmask:UInt32) {
physicsBody.contactTestBitMask = bitmask
}
func setEffectedByGravity (gravity: Bool){
physicsBody.affectedByGravity = gravity;
}
}
if let bodyA = contact.bodyA.node as? EntityNode, //SpriteNode
let bodyAent = bodyA.entity as? SGEntity, // COnverted to SGEntity
let bodyB = contact.bodyB.node as? EntityNode, //SprtiteNode
let bodyBent = bodyB.entity as? SGEntity //ERROR HERE : Cast to SGEnity
{
print("SGENity Description: \(bodyBent)");
contactBegan(bodyAent, nodeB: bodyBent)
contactBegan(bodyBent, nodeB: bodyAent)
}else{
print("Cast error")
}