Движущаяся платформа с игровым комплектом
Создаю 2d игру и хочу добавить движущиеся платформы, где я могу контролировать рисунок и поворот платформы.
Пример:
Я хочу, чтобы эта платформа двигалась по часовой стрелке, также, когда она достигает вершины и дна, я хочу, чтобы она вращалась соответствующим образом, как если бы она смотрела в направлении, в котором она движется (поэтому платформа, по существу, поворачивается на 180 градусов, когда она изгибается сверху и снизу).
Я не могу использовать SKActions, потому что мне нужна физика для правильной работы.
Моя идея заключается в том, что я могу использовать агента с поведением и целями для этого. Не уверен, что мне понадобится поиск пути.
Я изучаю, как использовать эти функции, но документацию и отсутствие учебных пособий трудно расшифровать. Я надеюсь, что кто-то может сэкономить мое время проб и ошибок, предоставив пример того, как это будет работать.
Заранее спасибо!
1 ответ
Использование SKActions или ручная регулировка положения будет недостаточным для того, чтобы работать так, как вы хотите, НО всегда стоит попробовать, потому что на его макет уйдет 2 минуты, и вы увидите...
Я бы предложил сделать что-то вроде Path
класс, который отправляет команды скорости на платформу каждый кадр...
На самом деле, это может быть хорошим упражнением в изучении конечного автомата..
MOVE RIGHT STATE: если позиция X> начальная позиция X + 200, войдите в состояние "двигаться вниз"
MOWE DOWN STATE: если позиция Y <начальная позиция Y - 200, войдите в состояние "двигаться влево"
ПЕРЕМЕСТИТЬ ВЛЕВОЕ СОСТОЯНИЕ: если позиция X <начальная позиция X, введите состояние "двигаться вверх"
MOVE UP STATE: если позиция Y> начальная позиция Y, введите состояние "двигаться вправо"
.. есть способы, которые вы могли бы придать большей кривизне, а не просто под прямым углом (при изменении направления)
В противном случае вам придется перевести это в класс / структуру / компонент и дать каждой платформе свой собственный экземпляр.
///
Другой вариант - вывести физику из уравнения и создать playerIsOnPlatform
свойство... тогда вы вручную настраиваете положение игрока в каждом кадре... (или, возможно, SKConstraint)
Это потребует больше кода для прыжков и тому подобного, и довольно быстро превращает вещи в спагетти (когда я в последний раз пробовал)
Но я смог успешно клонировать это, используя правильное обнаружение попадания по этому пути:
https://www.youtube.com/watch?v=cnhlFZeIR7Q
ОБНОВИТЬ:
Вот рабочий проект:
https://github.com/fluidityt/exo2/tree/master
Быстрая посылка:
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
}
}
}