AgentsCatalog是Apple的一个例子,他是基于OC的,我认为重写这些例子是个学习语言的好方法。首先,你的目标是正确的,通过观摩源码,你知道如何达到目标,其次你所使用的手段也是正确的,你可以从中学到某个类的用法,几个类的相互关系等等。
前几天我一直纠结一个事情,我打算把工具条合并到窗口的标题栏上去,就像Safari那样,我查了很多资料一直没能解决,但是这个例子无意间解决了这个问题。而且只有一行代码。你建立一个Cocoa应用,就像下面这样。
@NSApplicationMain class AppDelegate: NSObject,NSApplicationDelegate { @IBOutlet weak var window: NSWindow! @IBOutlet weak var skView: SKView! @IBOutlet weak var sceneControl: NSSegmentedControl! @IBAction func selectScene(sender: NSSegmentedControl) { let sceneTYpe = AAPLSceneType(rawValue: sender.selectedSegment) let scene = AAPLGameScene.sceneWithType( sceneTYpe!,size: CGSizeMake(800,600)) scene.scaleMode = SKSceneScaleMode.AspectFit self.skView.presentScene(scene) } func applicationDidFinishLaunching(aNotification: NSNotification) { // Insert code here to initialize your application self.window.titleVisibility = NSWindowTitleVisibility.Hidden // Configure the view. self.skView.ignoresSiblingOrder = true self.skView.showsFPS = true self.skView.showsNodeCount = true // Present the scene. self.selectScene(self.sceneControl ) } func applicationWillTerminate(aNotification: NSNotification) { // Insert code here to tear down your application }
你的工具条就合并到window标题栏上去了。其他什么也不用做。接下来你要重写下面这个类:
这是所有后面用到的 Scene 类基类,他本身是SKSence的子类。你会看到 SKComponentSystem(组件系统)和 GKAgent2D(跟踪代理)的用法。这里处理了游戏事件循环和对鼠标的响应。
import Cocoa import SpriteKit import GameplayKit enum AAPLSceneType: Int { case AAPLSceneTypeSeek = 0,AAPLSceneTypeWander,AAPLSceneTypeFlee,AAPLSceneTypeAvoid,AAPLSceneTypeSeparate,AAPLSceneTypeAlign,AAPLSceneTypeFlock,AAPLSceneTypePath,AAPLSceneTypesCount } let AAPLDefaultAgentRadius: CGFloat = 40.0 class AAPLGameScene: SKScene { var sceneName: String? required override init(size: CGSize) { super.init(size: size) } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } // A component system to manage per-frame updates for all agents. var agentSystem: GKComponentSystem? // An agent whose position tracks that of mouseDragged (OS X) or touchesMoved (iOS) events. // This agent has no display representation,but can be used to make other agents follow the mouse/touch. var trackingAgent: GKAgent2D? // YES when the mouse is dragging (OS X) or a touch is moving var seeking: Bool = false var stopGoal: GKGoal? var lastUpdateTime: NSTimeInterval = 0 class func sceneWithType( sceneType: AAPLSceneType,size: CGSize) -> AAPLGameScene { var sceneClass: AAPLGameScene.Type switch (sceneType) { case AAPLSceneType.AAPLSceneTypeSeek: sceneClass = AAPLSeekScene.self break; case AAPLSceneType.AAPLSceneTypeWander: sceneClass = AAPLWanderScene.self break; case AAPLSceneType.AAPLSceneTypeFlee: sceneClass = AAPLFleeScene.self break; case AAPLSceneType.AAPLSceneTypeAvoid: sceneClass = AAPLAvoidScene.self break; case AAPLSceneType.AAPLSceneTypeSeparate: sceneClass = AAPLSeparateScene.self break; case AAPLSceneType.AAPLSceneTypeAlign: sceneClass = AAPLAlignScene.self break; case AAPLSceneType.AAPLSceneTypeFlock: sceneClass = AAPLFlockScene.self break; case AAPLSceneType.AAPLSceneTypePath: sceneClass = AAPLPathScene.self break; default: sceneClass = AAPLGameScene.self break; } return sceneClass.init(size: CGSizeMake(800,600)) } override func didMoveToView(view: SKView) { self.agentSystem = GKComponentSystem( componentClass: GKAgent2D.self ) self.trackingAgent = GKAgent2D() let x = CGRectGetMidX(self.frame) let y = CGRectGetMidY(self.frame) self.trackingAgent!.position = vector_float2( Float(x),Float(y)) } override func update(currentTime: NSTimeInterval) { // Calculate delta since last update and pass along to the agent system. if (lastUpdateTime == 0) { lastUpdateTime = currentTime; } let delta = currentTime - lastUpdateTime lastUpdateTime = currentTime self.agentSystem!.updateWithDeltaTime( delta ) } override func mouseDown(theEvent: NSEvent) { self.seeking = true } override func mouseUp(theEvent: NSEvent) { self.seeking = false } override func mouseDragged(theEvent: NSEvent) { let position = theEvent.locationInNode(self) self.trackingAgent!.position = vector_float2 (Float(position.x),Float(position.y)) } }
import Cocoa import SpriteKit import GameplayKit class AAPLAgentNode: SKNode,GKAgentDelegate{ var agent = GKAgent2D() var color: SKColor = SKColor.highlightColor() var drawsTrail: Bool = false var triangleShape: SKShapeNode! var particles: SKEmitterNode! var defaultParticleRate: CGFloat = 0 init( scene: SKScene,radius: CGFloat,position: CGPoint ){ super.init() self.position = position; self.zPosition = 10; scene.addChild(self) // An agent to manage the movement of this node in a scene. agent = GKAgent2D() agent.radius = Float(radius) agent.position = (vector_float2)( Float(position.x),Float(position.y)) agent.delegate = self; agent.maxSpeed = 100; agent.maxAcceleration = 50; // A circle to represent the agent's radius in the agent simulation. let circleShape = SKShapeNode(circleOfRadius: radius) circleShape.lineWidth = 2.5 circleShape.fillColor = SKColor.grayColor() circleShape.zPosition = 1 self.addChild(circleShape) // A triangle to represent the agent's heading (rotation) in the agent simulation. var points = Array(count: 4,repeatedValue: CGPoint()) let triangleBackSideAngle = CGFloat((135.0 / 360.0) * (2 * M_PI)) points[0] = CGPointMake(radius,0); // Tip. points[1] = CGPointMake(radius * cos(triangleBackSideAngle),radius * sin(triangleBackSideAngle)); // Back bottom. points[2] = CGPointMake(radius * cos(triangleBackSideAngle),-radius * sin(triangleBackSideAngle)); // Back top. points[3] = CGPointMake(radius,0); // Back top. let triangleShape = SKShapeNode(points: &points,count: 4) triangleShape.lineWidth = 2.5; triangleShape.zPosition = 1; self.addChild( triangleShape) // A particle effect to leave a trail behind the agent as it moves through the scene. particles = SKEmitterNode(fileNamed: "Trail.sks") defaultParticleRate = particles!.particleBirthRate; particles!.position = CGPointMake(-radius + 5,0); particles!.targetNode = scene; particles!.zPosition = 0; self.addChild( particles!) } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } // GKAgentDelegate func agentWillUpdate(agent: GKAgent){ } /* * Called after [GKAgent updateWithDeltaTime:] is called each frame. */ func agentDidUpdate(agent: GKAgent){ // Agent and sprite use the same coordinate system (in this app),// so just convert vector_float2 position to CGPoint. let agent2D = agent as! GKAgent2D self.position = CGPointMake( CGFloat(agent2D.position.x),CGFloat(agent2D.position.y)) self.zRotation = CGFloat(agent2D.rotation) } }
// // AAPLWanderScene.swift // TestAgents // // Created by wuzhiqiang on 15/11/14. // Copyright © 2015年 wuzhiqiang. All rights reserved. // import Cocoa import SpriteKit import GameplayKit class AAPLWanderScene: AAPLGameScene { override func didMoveToView(view: SKView) { super.didMoveToView(view) let pt = CGPointMake(CGRectGetMidX(self.frame),CGRectGetMidY(self.frame)) let wanderer = AAPLAgentNode( scene: self,radius: 40,position: pt ) wanderer.color = SKColor.cyanColor() wanderer.agent.behavior = GKBehavior( goal: GKGoal( toWander:10),weight: 100) self.agentSystem!.addComponent( wanderer.agent) } }
下面我们来描述一下程序的工作过程。
在AppDelegate里面,我们建立一个Scence,8个中的一个,这里是AAPLWanderScene,漫游型。
这个 AAPLWanderScene 建立一个自己的 Node (一艘船),然后建立并将 GKBehavior 对象赋给了 节点的agent.behavior 属性。
最后,将这个节点作为一个组件加入到组件系统。
就是这样。程序就会运行,组件系统会工作,定时循环更新他的每个组件。你的小船会自动出发漫游。
在节点里,甚至还加入了粒子效果,你能看到小船后面的水泡。
原文链接:/swift/325421.html