Как я могу «сложить» UIView в 3D вдоль линии? - PullRequest
5 голосов
/ 19 января 2020

Если у вас есть UIView

enter image description here

Представьте, что представление заполнено текстом, анимацией, фотографией кошки, градиентом или любым другим материал, которым UIView может быть полон.

Легко наклонить его обратно влево в 3D

enter image description here

или вернуться к право ..

enter image description here

(Кстати, я настоятельно рекомендую идеальный OHCubeView ohcubeview , когда вам нужно сделать такого рода вещь.)

Но я хочу увеличить вид вдоль шва , и иметь одну сторону , идущую назад влево, а другую сторона, идущая назад вправо ..

enter image description here

!

Моё первое решение было простым: какой бы ни был вид (пользователь набрав текст, фотографию кота, что угодно), просто идеально продублируйте ее, а затем решите проблему очевидным образом.

Это не элегантно, но работает.

Но .. .

вещь, которую я хочу сложить л То есть ... это SKView с излучателем .

Излучатели частиц, конечно, случайны, и хотя два из них выглядят одинаково, это не настоящее решение .

По сути, если кто-то знает, как "скопировать" UIView в другой, ну, в представление или что-то в этом роде ...

enter image description here

проблема будет решена.

Для решения проблемы, подобной этой, в игровом движке, скажем, вы просто добавляете «виртуальную камеру» (какой бы концепция ни была в вашем любимом игровом движке) на предмет, о котором идет речь и поместите другую половину или что-то еще, куда хотите, но я не знаю аналогии с этим в iOS!

Кто-нибудь имеет угол на это:

enter image description here

Ответы [ 3 ]

1 голос
/ 20 февраля 2020

Есть два подхода, о которых я мог подумать.

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

0 голосов
/ 14 февраля 2020

В этом посте не объясняется, как сложить UIView в 3D . ОП упомянул:

«По сути, если кто-то знает, как« скопировать »UIView в другой, ну, вид или что-то ... проблема будет решена."

Если копирование представления может решить эту проблему, то вам следует рассмотреть этот вопрос Я попробовал этот ответ , и он работает нормально. Я попробовал:

enter image description here

Код для вышеприведенного вывода:

import UIKit
class ViewController: UIViewController {

    @IBOutlet weak var textField: UITextField!
    @IBOutlet weak var rightView: UIView!
    @IBOutlet weak var leftView: UIView!

    override func viewDidLoad() {
        super.viewDidLoad()
        textField.addTarget(self, action: #selector(didChange(textField:)), for: .editingChanged)
    }

    @objc func didChange(textField: UITextField){
        rightView.subviews.forEach{$0.removeFromSuperview()}
        let v = (try? leftView.copyObject()) as? UIView ?? UIView()
        rightView.addSubview(v)
        v.translatesAutoresizingMaskIntoConstraints = true
        NSLayoutConstraint.activate([
            v.topAnchor.constraint(equalTo: rightView.topAnchor),
            v.leadingAnchor.constraint(equalTo: rightView.leadingAnchor),
            v.bottomAnchor.constraint(equalTo: rightView.bottomAnchor),
            v.trailingAnchor.constraint(equalTo: rightView.trailingAnchor)
        ])
    }
}

extension NSObject {
    func copyObject<T:NSObject>() throws -> T? {
        let data = try NSKeyedArchiver.archivedData(withRootObject:self, requiringSecureCoding:false)
        return try NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data) as? T
    }
}
0 голосов
/ 13 февраля 2020

Я мог бы придумать пару вещей, которые нужно попробовать:

Скопировать содержимое UIView в нечто: Вы можете сделать снимок экрана:

... в изображение:

UIGraphicsBeginImageContextWithOptions(view.bounds.size, false, 
                                       UIScreen.mainScreen().scale)
view.drawViewHierarchyInRect(view.bounds, afterScreenUpdates: true)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()

... или к представлению (которое в соответствии с документами Apple быстрее, чем указано выше):

func snapshotView(afterScreenUpdates afterUpdates: Bool) -> UIView?

Наконец, этот проект довольно старый, не поддерживается и записан на Obj- C, но, возможно, это даст вам представление о том, как они сделали это для вас самостоятельно:

https://github.com/honcheng/PaperFold-for-iOS

...