您的位置:首页 > 移动开发 > Swift

用swift 重写 AgentsCatalog

2015-11-15 11:23 405 查看
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 属性。

最后,将这个节点作为一个组件加入到组件系统。

就是这样。程序就会运行,组件系统会工作,定时循环更新他的每个组件。你的小船会自动出发漫游。

在节点里,甚至还加入了粒子效果,你能看到小船后面的水泡。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: