提前道歉,因为这个问题涉及分配代码。 我有一个GameScene,有多个层,用于HUD / Scores等的Nodes / SpriteNodes。一层LayerProjectile拥有一个武器实体。
所述实体具有Sprite和Physics Components。 问题是LayerProjectile中的Projectile节点不与GameScene的主层(worldLayer)中的节点交互。
所有物理机构都是动态的,GameScene有它的PhysicWorldDelgate
class GamePlayMode: SGScene, SKPhysicsContactDelegate {...
//武器恩赐(SGEntity是一个GKEntity)
类ThrowWeapon: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(entity: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,并处理添加到GameScene的所有武器实体
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()
}
}
添加LayerProjectile和worldLayer的实例(保存所有其他节点,其中一些节点将catBitMask设置为在与武器实体联系时通知),添加到GameScene(GamePlayMode的实例,SGScene)
class GameSceneState: GKState {
unowned let gs: GamePlayMode
init(scene: GamePlayMode) {
self.gs = scene
}
}
gs.physicsWorld.contactDelegate = gs
gs.physicsWorld.gravity = CGVector(dx: 0.0, dy: -1.0)
//Layers
gs.layerProjectile = LayerProjectiles();
gs.worldLayer = TileLayer(levelIndex: gs.levelIndex, typeIndex: .setMain)
gs.backgroundLayer = SKNode()
gs.overlayGUI = SKNode()
gs.addChild(gs.worldLayer)
gs.addChild(gs.layerProjectile);// For throwing wepaons, made in GamePlayMode
最后是Destrutable实体的物理/精灵组件设置,它是worldLayer的子项(与LayerProjectile一起添加到GaemScene中)
class Destructable : SGEntity{
var spriteComponent: SpriteComponent!
var animationComponent: AnimationComponent!
var physicsComponent: PhysicsComponent!
var scrollerComponent: FullControlComponent!
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: false);
physicsComponent.setCategoryBitmask(ColliderType.Destroyable.rawValue , dynamic: true);
physicsComponent.setPhysicsCollisions(ColliderType.Wall.rawValue | ColliderType.Player.rawValue | ColliderType.Destroyable.rawValue); // collides with so bpounces off
physicsComponent.setPhysicsContacts(ColliderType.Wall.rawValue | ColliderType.Player.rawValue | ColliderType.Projectile.rawValue);
physicsComponent.setEffectedByGravity(true);
addComponent(physicsComponent);
//Final Steps of compnements
spriteComponent.node.physicsBody = physicsComponent.physicsBody;
spriteComponent.node.name = "destructableEntity";
name = "destructableEntity";
spriteComponent.node.zPosition = 150;
//spriteComponent.node.userData = ["startX" : position.x];
}
// Handle contacts
override func contactWith(entity: SGEntity) {
//
if entity.name == "weapon"{
print("Crate hit Projectile");
}
}
当初始化GameScene并添加所有精灵节点时,武器射弹(当用户在游戏期间点击投掷按钮时)和可破坏实体的实施:
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)
}
任何意见都赞赏。
已添加:ColliderTypes的类别位掩码枚举:
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
}
//在实体(武器,可破坏)类中调用和覆盖处理Enities物理联系人的函数的SGEnity类
class SGEntity:GKEntity {
var name =“”
func contactWith(entity:SGEntity){ //由子类重写
}
// PhyscisComponent
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是通过GameScene的PhysicsDelage调用的:
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,这失败了,并且从未调用与弹丸实体有关的......。所有其他SGEnities(Destructible)都没有问题地投射到SGEntity。,...