Есть два подхода, о которых я мог подумать.
1) Подход изгиба
Вы можете согнуть свою сцену, используя SKWarpGeometry. С семантической точки зрения вы представляете сетку квадрантов 2 x 2 на игровой сцене, описанную структурой данных 3 x 3 точки. Вы бы немного переместили левый и правый края и сделали их немного меньше. И вы бы сделали центральный вертикальный край немного длиннее.
В документации Apple также упоминается, что практически любой тип узла (включая SKEmitterNode) можно деформировать, поместив его в SKEffectNode и применив деформацию к который. См .: https://developer.apple.com/documentation/spritekit/skwarpgeometrygrid/animate_the_warping_of_a_sprite?language=objc.
Все, что нам нужно сделать, - это сделать узел эффекта элементом root всего и применить к нему деформацию. Теперь, это работает, но как только в нем появляется излучатель, деформация начинает заполняться приступами, похожими на судороги. Я считаю это ошибкой. В любом случае, я включу код, если он будет исправлен позже, потому что он должен работать в соответствии с документацией.
let sourcePoints = [
// bottom row: left, center, right
vector_float2(0.0, 0.0),
vector_float2(0.5, 0.0),
vector_float2(1.0, 0.0),
// middle row: left, center, right
vector_float2(0.0, 0.5),
vector_float2(0.5, 0.5),
vector_float2(1.0, 0.5),
// top row: left, center, right
vector_float2(0.0, 1.0),
vector_float2(0.5, 1.0),
vector_float2(1.0, 1.0)
]
var destinationPoints = sourcePoints
// Bring lefts in, and make the edge shorter
destinationPoints[0] = vector_float2(0.1, 0.1)
destinationPoints[3] = vector_float2(0.1, 0.4)
destinationPoints[6] = vector_float2(0.1, 0.9)
// Bring rights in, and make the edge shorter
destinationPoints[2] = vector_float2(0.9, 0.1)
destinationPoints[5] = vector_float2(0.9, 0.4)
destinationPoints[8] = vector_float2(0.9, 0.9)
// Make the center edge longer
destinationPoints[1] = vector_float2(0.5, -0.2)
destinationPoints[4] = vector_float2(0.5, 0.7)
destinationPoints[7] = vector_float2(0.5, 1.2)
// Need to set the no warp geometry first
effectNode.warpGeometry = SKWarpGeometryGrid(columns: 2, rows: 2)
let newGeometry = SKWarpGeometryGrid(columns: 2, rows: 2,
sourcePositions: sourcePoints,
destinationPositions: destinationPoints)
effectNode.run(SKAction.warp(to: newGeometry, duration: 1.0)!)
Использованные источники:
https://www.hackingwithswift.com/example-code/games/how-to-warp-a-sprite-using-skwarpgeometrygrid
http://sound-of-silence.com/?page=blog&sort=recent&count=0
2) Подход Live Copy
Это проще, кода гораздо меньше, и он гораздо более универсален; Вы можете делать такие вещи, как на этом уровне легенд Rayman https://youtu.be/7m5YQrucis8?t=1226. Кроме того, это работает.
По сути, у нас есть мастер SKView, показывающий главную сцену. Мы добавим копию SKView, показывающую сцену копирования. Сцена копирования будет иметь только один узел спрайта. В обновлении главной сцены l oop мы возьмем сплющенную текстуру сцены и назначим ее узлу спрайта в сцене копирования. Объект, являющийся делегатом сцены, может подключиться к этому обновлению l oop, поэтому мы приведем контроллер представления в соответствие с SKSceneDelegate.
class Playground_VC: UIViewController, SKSceneDelegate {
var sprite: SKSpriteNode?
override func loadView() {
self.view = SKView()
}
var skView: SKView {
return self.view as! SKView
}
override func viewWillAppear(_ animated: Bool) {
let scene = SKScene(size: self.skView.bounds.size)
scene.backgroundColor = UIColor.clear
scene.delegate = self
self.skView.presentScene(scene)
let e = newEmitter()
scene.addChild(e)
e.position = self.skView.midPoint
self.createCopy()
}
func update(_ currentTime: TimeInterval, for scene: SKScene) {
// Grab the root texture and assign to the sprite that's in the copy scene
let t = self.skView.texture(from: self.skView.scene!)
self.sprite?.texture = t
}
func createCopy() {
// Make a new SKView that's 4 times smaller
var f = self.skView.bounds
f.size.height *= 0.4
f.size.width *= 0.4
let copy = SKView(frame: f)
copy.presentScene(SKScene(size: f.size))
self.view.addSubview(copy)
let sprite = SKSpriteNode(texture: nil, size: f.size)
copy.scene?.addChild(sprite)
self.sprite = sprite
sprite.position = CGPoint(x: f.size.width / 2, y: f.size.height / 2)
}
func newEmitter() -> SKEmitterNode {
return SKEmitterNode(fileNamed: "Particle.sks")!
}
}
Любые манипуляции, которые вы выполняете на главном SKView, такие как наклон его в трехмерном пространстве не должно влиять на внешний вид копии, поскольку эти манипуляции не влияют на игровую сцену.
![enter image description here](https://i.stack.imgur.com/wL1kY.jpg)