创建一个2D游戏,并希望添加移动平台,我可以控制平台的模式和旋转。
示例:
我希望这个平台以顺时针方向运动,当它到达顶部和底部时,我希望它相应地旋转,好像它面向它的方向(所以平台基本上会旋转180度,因为它顶部和底部的拱门。)
我不能使用SKActions,因为我需要物理学才能正常工作。
我的想法是,我可以使用具有行为和目标的代理来执行此操作。不确定我是否也需要路径查找。
我正在研究如何使用这些功能,但文档和缺少教程很难解读。我希望有人可以通过提供一个如何运作的例子来节省我的试验和错误时间。
提前致谢!
答案 0 :(得分:1)
使用SKActions或手动调整位置会让你按照你想要的方式工作,但是它总是值得一试,因为它需要2分钟来模拟它并看到......
我建议做类似Path
类的事情,每一帧都向平台发送速度命令......
实际上,这可能是学习状态机的一个很好的练习。
移动正确状态:如果X位置>起始位置X + 200,输入状态“向下移动”
向下移动状态:如果Y位置<起始位置Y - 200,进入状态“向左移动”
MOVE LEFT STATE:如果X位置&lt;起始位置X,输入状态“向上移动”
移动状态:如果Y位置&gt;起始位置Y,输入状态“向右移动”
..有一些方法你可以想出给它更多的曲率而不是直角(当改变方向时)
否则你必须将它转换为类/结构/组件,并为每个平台提供它自己的实例。
///
另一种选择是将物理学从等式中取出,并创建一个playerIsOnPlatform
属性......然后你手动调整每帧的玩家位置......(或者可能是SKConstraint)
这将需要更多的跳跃等代码,并且很快将事情转化为意大利面(上次我尝试过)
但是,我能够成功地克隆它,使用适当的命中检测去那条路线:
https://www.youtube.com/watch?v=cnhlFZeIR7Q
这是一个工作项目:
https://github.com/fluidityt/exo2/tree/master
Boilerplate swift stuff:
import SpriteKit
import GameplayKit
// Workaround to not having any references to the scene off top my head..
// Simply add `gScene = self` in your didMoveToViews... or add a base scene and `super.didMoveToView()`
var gScene = GameScene()
class GameScene: SKScene {
override func didMove(to view: SKView) {
gScene = self
}
var entities = [GKEntity]()
var graphs = [String : GKGraph]()
private var lastUpdateTime : TimeInterval = 0
func gkUpdate(_ currentTime: TimeInterval) -> TimeInterval {
if (self.lastUpdateTime == 0) {
self.lastUpdateTime = currentTime
}
let dt = currentTime - self.lastUpdateTime
for entity in self.entities {
entity.update(deltaTime: dt)
}
return currentTime
}
override func update(_ currentTime: TimeInterval) {
self.lastUpdateTime = gkUpdate(currentTime)
}
}
class Platforms_BoxPathComponent: GKComponent {
private enum MovingDirection: String { case up, down, left, right }
private var node: SKSpriteNode!
private var state: MovingDirection = .right
private lazy var startingPos: CGPoint = { self.node.position }()
@GKInspectable var startingDirection: String = "down"
@GKInspectable var uniqueName: String = "platform"
@GKInspectable var xPathSize: CGFloat = 400
@GKInspectable var yPathSize: CGFloat = 400
// Moves in clockwise:
private var isTooFarRight: Bool { return self.node.position.x > (self.startingPos.x + self.xPathSize) }
private var isTooFarDown: Bool { return self.node.position.y < (self.startingPos.y - self.yPathSize) }
private var isTooFarLeft: Bool { return self.node.position.x < self.startingPos.x }
private var isTooFarUp: Bool { return self.node.position.y > self.startingPos.y }
override func didAddToEntity() {
print("adding component")
// can't add node here because nodes aren't part of scene yet :(
// possibly do a thread?
}
override func update(deltaTime seconds: TimeInterval) {
if node == nil {
node = gScene.childNode(withName: uniqueName) as! SKSpriteNode
// for some reason this is glitching out and needed to be redeclared..
// showing 0 despite clearly not being 0, both here and in the SKS editor:
xPathSize = 300
}
let amount: CGFloat = 2 // Amount to move platform (could also be for for velocity)
// Moves in clockwise:
switch state {
case .up:
if isTooFarUp {
state = .right
fallthrough
} else { node.position.y += amount }
case .right:
if isTooFarRight {
state = .down
fallthrough
} else { node.position.x += amount }
case .down:
if isTooFarDown {
state = .left
fallthrough
} else { node.position.y -= amount }
case .left:
if isTooFarLeft {
state = .up
fallthrough
} else { node.position.x -= amount }
default:
print("this is not really a default, just a restarting of the loop :)")
node.position.y += amount
}
}
}