Tag: Andy Novak

将.dae模型导入SceneKit

我们最近一直在开发一款相对知名的“不稳定方块塔”游戏的AR版本,我们决定将其命名为Toppler。 我们采取的第一步就是使用Blender设计木块,然后直接在SceneKit中使用它们。 我将详细介绍将3D模型导出为.dae (数字资产交换)文件的过程以及如何将其与SceneKit一起使用。 您可能倾向于将其视为一个简单的步骤,但是需要注意一些事项,并且如果您以前没有做过此主题,那么缺少有关该主题的文档就尤其具有挑战性。 1.导出.dae文件 我使用Blender来制作木制积木(我将跳过积木创建步骤,这可能是以后的主题)。 您将在Blender中采取的最后一步是导出您的创作。 经典菜单,只需点击文件>导出> Collada(.dae)。 您将看到一个带有多个选项的导出窗口。 我们将感兴趣的选项是Selection Only 。 取消选中该复选框将导出场景中的所有内容(例如:灯光,照相机等)。 在这里,我们只希望将木块导出,因此我们将确保之前已选择它,然后将其选中。 选择一个适当的路径,然后单击右上角的“ 导出COLLADA”按钮。 导出后,您将在其纹理旁边找到导出的DAE文件(如果有的话)。 您甚至可以通过QuickLook获得不错的预览。 2. .dae文件 .dae文件格式(或COLLADA文件)已由“ 协作设计活动”定义。 就像定义3D对象各种特征的XML文件一样简单。 您将在文件中找到各种库,这些库将用于描述场景。 例如,我们将找到library_images来引用我们的纹理, 引用了我们的纹理和效果的library_geometries ,声明了可用几何形状的library_visual_scenes ,以及保存我们的场景元素并引用所需材质和几何形状的library_visual_scenes部分。 这里没有其他小节。 随时使用您喜欢的文本编辑器打开.dae文件,以亲自检查一下。 3.导入Xcode 使用Blender建模3D对象时要了解的一件事是与Xcode使用不同的坐标系: 在Xcode中,Y轴描述高度,而Blender中的Y轴描述深度(并且反向观察适用于Z轴)。 幸运的是,Xcode知道如何处理坐标系之间的这种差异。 如果查看Xcode中的scnassets资源文件夹,您会注意到“ 始终使用Y轴 ”选项。 意思是 : Xcode将强制执行自己的坐标系,并将转换任何使用不同坐标系的对象。 现在,只需将.dae文件及其纹理拖放到.scnassets文件夹中即可。 Xcode将自动使用适当的轴设置对其进行转换,您将能够使用Xcode Scene Editor打开它并预览3D对象。 如果最终将纹理.png文件移动到其他位置,请确保使用“材质检查器”将其重新分配给所需的材质。 4.转换为.scn 如果要使用场景编辑器(或任何特定于SceneKit的设置)更改3D对象的物理行为,则需要将模型转换为.scn文件。 在Xcode中预览模型时,请点击编辑器菜单,然后点击转换为SceneKit场景文件格式 。 然后你走了! 您最终将获得一个.scn文件,准备在SceneKit中完全使用它。 现在,您可以将其拖放到另一个场景中,或者可以通过代码将其导入并将其根节点添加到父SCNNode 。 […]

一个不真正使用反应性可可的案例

在生产项目中,我已经在生产项目中使用了功能性反应式编程(FRP)和反应性可可粉(以及最近的反应性Swift),并且看到有人采用它。 在整个过程中,我们不仅学会了如何使用FRP,还学会了如何不使用它。 在本文中,我将反思我自己犯下的一些典型的新手失误,以便来自传统命令式或混合语言(如Objective-C,Java或C#)背景的人也许可以从我的错误中学到东西。 我们将考虑一个问题以及三个不同的解决方案: 天真的(和错误的)命令式解决方案, 正确的命令,以及 正确的FRP样式的解决方案 希望最后,您将了解FRP如何有助于解决与UI和异步编程有关的一些问题。 本文假定您熟悉Reactive Swift的基础知识(尤其是Signals和SignalProducers的概念)。 您可以使用ReactiveSwift自述文件快速赶上那些。 问题 假设我们开发了一个带有视图控制器的购物应用程序,该控制器需要显示可从远程API获得的产品描述列表。 有文字说明和图片网址。 该图像将必须使用网络请求进行下载。 假设网络请求是使用Reactive Swift的SignalProducer提取的,我们将专注于以MVVM方式为表视图单元格编写代码。 天真的解决方案 事实证明,这不是我们使用此代码可以获得的唯一问题。 考虑下面的序列图,其中下载发生的速度比滚动使单元1离开屏幕的速度更快。 当重复使用单元格中的产品a的图像替换为正确的产品b的图像时,我们将再次观察到图像的错误归因。 让我们来解决它! 我们是强大的! 我们可以立即修复所有问题! (实际上,这将需要一些时间,但是请注意!)当单元格收到新的viewModel值时,我们将终止任何先前的下载信号订阅。 这样,我们将解决序列1的问题。 然后,对于每个新的viewModel值,我们将使用占位符(在本例中为nil )替换单元格中的图像,以防止显示的文本内容与图像之间的不匹配,如序列2中所述 。 听起来像是个计划? 使用这些修复程序后,单元将仅显示与分配的产品或占位符相对应的图像。 我们终于都准备好了,不是吗?—看这段代码,让我们问问自己,为什么我们这里甚至使用了活性可可粉? 我们从学习和使用新图书馆中获得了哪些好处? 可变属性! —并非如此,我们可以在这里使用内置的Swift的didSet观察器。 信号产生器在此处封装了异步操作的状态! —是的,但是众所周知的Foundation的Operation对象也是如此。 我们可以定义一个具有依赖BlockOperation的DownloadImageOperation ,并且甚至不需要学习Reactive Cocoa就可以完成该任务。 我们可以做得更好吗? —是的。 这里发生的事情是,我们使用FRP的方式与使用常规命令式工具的方式相同,而没有考虑该方法对于在此处理的UI和异步编程问题必须提供的功能。 玻璃钢解决方案 函数式反应式编程可让我们使用(并为方便起见而使用)的两个出色工具是: UI编程的绑定 将信号与功能样式运算符(例如贴图,过滤器和展平器)结合使用,并自然地管理所得信号的寿命。 这是我们如何将其应用于问题的方法(为清楚起见,我们将只专注于awakeFromNib的实现(其余原始代码将保持不变): 让我们确切说明我们在这里做什么。 <~是一个绑定运算符,作用于实现BindingTargetProtocol (左侧)和BindingSourceProtocol (右侧)的值。 将运算符应用于这些值会在目标指定的生存期内(在我们的示例中,这是UILabel和UIImageView的生存期)将目标与源发出的值进行订阅,即,保证订阅将在指定的生存时间内终止。 请注意,在第3行和第4行中,我们如何直接映射属性而不是映射信号生成器。 属性的此功能仅可从Reactive […]