关于unity3d:Unity3D如何在一个项目建多个场景

举荐:将NSDT场景编辑器退出你的3D工具链3D工具集:NSDT简石数字孪生 设置多个场景您能够增加多个场景、编辑查看场景的形式以及更改场景设置。要创立新场景,请参阅创立、加载和保留场景。 增加场景有两种办法能够向我的项目增加新场景: 右键单击以在“我的项目”窗口中关上场景资源的菜单,而后抉择“关上场景增加”。  将一个或多个场景从“我的项目”窗口拖到“层次结构”窗口中。 查看场景“层次结构”窗口显示属于我的项目的所有场景:增加了多个场景的层次结构窗口。 答:未保留更改的场景在场景名称旁边有一个星号。 B:场景更多菜单容许您对场景执行操作。 C:场景分隔符(倒三角形)可让您折叠场景并从层次结构中暗藏内容,以更好地治理多个场景。 【提醒】要将场景增加到“层次结构”窗口而不加载它,请按 Alt(macOS:按下选项)并将场景拖到“层次结构”窗口中。这使您能够在不便时加载场景。 加载的场景:更多菜单您能够通过多种形式与加载的场景进行交互和编辑:加载场景的更多菜单。 卸载场景 更多菜单 (⋮)您能够对卸载的场景执行的操作较少:卸载场景的更多菜单。 播放模式下的多个场景当您处于“播放”模式并且“层次结构”窗口中有多个场景时,编辑器将显示一个名为 DontDestroyOnLoad 的附加场景。您无法访问场景,它在运行时也不可用。DontDestroyOnLoad 特定于场景的设置以下设置特定于每个场景: 渲染设置和光照贴图设置(均位于“光照”窗口中)。导航网格设置。遮挡剔除窗口中的场景设置。因为每个场景都治理本人的设置,因而只有与该场景关联的设置才会保留到场景文件中。要更改特定场景的设置,必须关上该特定场景并更改设置,或者将场景设置为流动场景并更改设置。否则,如果关上了多个场景,Unity 将应用流动场景中的渲染和导航网格设置。 在编辑器中或在运行时切换到新的流动场景时,Unity 会将所有以前的设置替换为新流动场景中的设置。 其余资源创立、加载和保留场景在多个场景中烘焙数据应用脚本编辑多个场景原文链接:https://www.mvrlink.com/unity3d-set-up-multiple-scenes/

July 7, 2023 · 1 min · jiezi

关于unity3d:Unity3D网格对齐

举荐:将NSDT场景编辑器退出你的3D工具链3D工具集:NSDT简石数字孪生 网格对齐Unity在编辑器的场景视图窗口中提供了一个可视化网格,该网格能够通过将游戏对象捕获(挪动)到最近的网格地位来帮忙准确对齐游戏对象。显示沿 x、y 和 z 轴的网格线的同一视图 能够通过几种形式沿 X、Y 或 Z 轴将游戏对象与网格对齐: 将所选游戏对象与最靠近的网格点对齐。在挪动、旋转或缩放游戏对象时开启网格对齐。还能以增量形式变换游戏对象,而无需将其与网格线对齐。 如果须要更改挪动、旋转或缩放的量,则能够更改递增的对齐值。默认状况下,网格是暗藏的,然而能够使其可见并可切换沿着哪个轴显示。 能够通过更改以下设置来自定义网格的外观和行为: 网格的大小(调整线之间的间隔)。网格线本身的色彩。网格线显示的透明度或不透明度。网格在“场景视图”窗口中的地位(将其移近或移远)。其中很多操作都反对键盘快捷键。 能够查看为这些操作调配了哪些组合键,并应用 Shortcuts Manager 对其进行自定义。 网格和对齐工具栏叠加网格和对齐工具栏叠加图标口头 注:栅格和捕获叠加上的设置对所有场景视图都是全局的。 对齐、捕获和增量挪动本节提供无关如何执行以下操作的信息: 对齐(推动)到网格激活主动贴靠增量式挪动、旋转和缩放 对齐(推送)到网格能够将游戏对象对齐到单个轴上的最近网格点,也能够一次性在所有轴上对齐游戏对象。 要将游戏对象与特定轴的网格上的最近点对齐,请执行以下操作:1、在网格和捕获叠加工具栏中,关上网格捕获下拉菜单 ()。2、在“对齐所选内容”局部中,单击与要推送到的轴匹配的 X、Y 或 Z 按钮。 将所选内容与网格和对齐窗口的网格对齐局部要一次性在所有轴上对齐游戏对象,请执行以下操作:1、抉择要与网格对齐的游戏对象。应用 Ctrl+\ (Windows) 或 Command+\ (macOS) 快捷键将游戏对象推动到所有轴上的网格上。或者,从“栅格和捕获叠加”工具栏中,关上网格可见性下拉菜单 (),而后在对齐所选局部中,单击“所有轴”。 激活主动捕获要开启主动贴靠网格,请执行以下操作:1、激活挪动工具,并确保工具设置叠加中的手柄方向设置为全局 ()。2、单击“网格和捕获”工具栏“叠加”中的网格捕获图标 ()。激活时图标为蓝色。 启用主动网格贴靠时,__Move、Rotate__ 和 Scale 变换工具会沿激活的辅助图标轴将选定的游戏对象贴靠到网格。 如果须要游戏对象以较小的增量挪动,也能够采纳增量形式变换游戏对象。 以增量挪动、旋转和缩放要按增量贴靠值来挪动、旋转或缩放,请执行以下操作:1、按住 Control 键 (Windows) 或 Command 键 (macOS),同时应用其中一个变换辅助图标。2、要更改默认的增量贴靠值,请执行以下操作:从栅格和捕获叠加工具栏中,关上捕获增量下拉菜单 ()。 Increment Snap 局部蕴含几个属性,可用于为所有轴设置雷同的值或不同的值:“栅格和捕获”窗口的“增量捕获”局部 挪动:选中链接图标后,为所有轴输出对立的增量捕获值,或勾销链接轴并在 X、Y 和 Z 轴属性中设置不同的增量捕获值。 旋转:输出以度为单位的旋转增量值。比例:输出比例增量值作为比例因子。例如,如果缩放值为 2,则所选游戏对象将以其原始大小两倍的增量进行缩放。自定义网格本节提供无关自定义以下设置的信息:显示和暗藏网格线更改显示网格的轴调整网格的大小更改网格线的默认色彩更改网格的不透明度调整网格的地位将值和设置重置为默认值 显示和暗藏网格线1、通过单击“网格和捕获叠加”工具栏上的网格可见性图标 () 来切换网格可见性,以在任何轴(X、Y、Z)上显示或暗藏网格。2、如果您处于正交模式 (Iso),Unity 将抉择视图。单击网格可见性按钮时,网格将显示在“场景视图”窗口中 更改网格显示的轴要更改显示网格的轴,请执行以下操作:1、从格网和捕获叠加工具栏中,关上格网可见性下拉菜单 ()。2、从“栅格立体”局部中,抉择要显示的轴。格网可见性下拉菜单下的格网轴局部 调整网格大小您能够设置网格线在“场景视图”窗口中显示时的大小。这会影响网格的外观以及游戏对象主动与网格对齐的形式,但不会影响游戏对象的挪动、旋转或增量缩放水平。 如果一次性为所有轴设置一个大小,则会显示一个平均(正方形)网格。 然而,也能够在三个轴的任何一个轴上应用不同的值,从而查看非平均(矩形)网格。 默认状况下,网格设置为平均间隔(所有轴上为 1)。 要调整网格的大小,请执行以下操作:1、从栅格和捕获叠加工具栏中,关上捕获增量下拉菜单 ()。2、应用选中链接图标的 Size 属性为可视网格输出对立值(所有网格线的长度雷同),或者勾销轴的链接并指定 X、Y 和 Z 网格线之间的非平均间隔。 例如,要在 x 和 y 轴上创立矩形网格,可勾销轴的链接并将 X 和 Y 设置为 1,将 Z 设置为 2。 如果要切换回网格线之间的均匀值,请执行以下操作:1、抉择链接图标。2、Size 属性当初通过 X 中输出的值显示所有轴的值。留神:还能够应用键盘快捷键来增大和减小网格的大小:1、要增大网格大小,请应用 Ctrl+] (Windows) 或 Command+] (macOS)。2、要减小网格大小,请应用 Ctrl+[ (Windows) 或 Command+[ (macOS)。 ...

June 30, 2023 · 1 min · jiezi

关于unity3d:Unity3D创建自定义叠加

举荐:将NSDT场景编辑器退出你的3D工具链3D工具集:NSDT简石数字孪生 创立自定义叠加您能够为场景视图窗口创立自定义面板叠加和工具栏叠加。 面板叠加工具栏叠加提醒:无关创立 UIE 的信息,请参阅 UI 元素开发人员指南。编辑器工具栏元素工具栏元素能够蕴含文本、图标或两者的组合。 应用 [] 注册要在实现中应用的工具栏元素。EditorToolbarElement(Identifier, EditorWindowType)ToolbarOverlay 您能够继承任何 VisualElement 类型并自行提供款式,但工具栏元素须要特定的款式,因而最好继承预约义类型之一:EditorToolbar 编辑器工具栏按钮 - 基于UnityEditor.UIElements.ToolbarButton编辑器工具栏下拉列表 - 基于EditorToolbarButton编辑器工具栏下拉切换 - 基于UnityEngine.UIElements.BaseField<bool>编辑器工具栏切换 - 基于UnityEditor.UIElements.ToolbarToggle提醒:如果工具栏程度或垂直停泊,则文本将被剪裁或不可见,因而请为每个工具栏指定一个图标。面板叠加所有 Overlay 都必须继承 Overlay 基类并实现 CreatePanelContent() 办法。这将创立一个根本面板,您能够按原样应用该面板或增加工具栏元素。 在编辑器文件夹中创立一个新的 C# 脚本并命名它。关上新脚本。删除主大括号之间的样板内容,并在命名空间中实现类。OverlayUnityEditor.Overlays重写函数并将内容增加到可视元素。CreatePanelContent将属性增加到类中,并指定此笼罩将在哪种类型的窗口中可用。 指定为类型将使叠加在所有编辑器窗口中可用,指定将使叠加仅在场景视图中可用。OverlayEditorWindowSceneView增加名称、ID 和显示名称。可选:将属性增加到类以指定在精简模式下应用的图标。如果未指定图标,则默认状况下,零碎应用笼罩名称的前两个字母(或前两个单词的前两个首字母)。IconOverlay 示例using UnityEditor;using UnityEditor.Overlays;using UnityEngine.UIElements;[Overlay(typeof(SceneView), "My Custom Toolbar", true)]public class MyToolButtonOverlay : Overlay{ public override VisualElement CreatePanelContent() { var root = new VisualElement() { name = "My Toolbar Root" }; root.Add(new Label() { text = "Hello" }); return root; }}工具栏叠加工具栏笼罩是保留工具栏项的容器,由 的汇合组成。EditorToolbarElement ...

June 30, 2023 · 7 min · jiezi

关于unity3d:Unity3DPick-and-select-GameObjects

举荐:将NSDT场景编辑器退出你的3D工具链3D工具集:NSDT简石数字孪生 Pick and select GameObjects能够在 Scene 视图中或从 Hierarchy 窗口中抉择一个游戏对象。也能够一次抉择多个游戏对象。 Unity 会在 Scene 视图中突出显示抉择的游戏对象及其子项。默认状况下,抉择轮廓色彩为橙色,子项轮廓色彩为蓝色。还能够抉择以其余色彩突出显示所选游戏对象的线框。在 Unity Preferences 窗口(在 macOS 上抉择 Unity > Preferences__,或在 Windows 上抉择 Edit > Preferences__)中能够更改所有这些轮廓突出显示色彩。 要理解对于轮廓和线框抉择可视化的更多信息,请参阅无关 Gizmos 菜单的文档。 Select GameObjects要抉择一个游戏对象,请采纳以下办法之一:在 Scene 视图中单击游戏对象。如果重复单击重叠的游戏对象之间的共享空间,抉择将在这些游戏对象之间循环。 或在 Hierarchy 窗口中单击游戏对象的名称。要抉择或勾销抉择多个游戏对象,请采纳以下办法之一:围绕多个游戏对象拖出一个矩形。 Unity 会抉择此突围框内的所有对象。或在按住 Shift 键的同时在场景中单击游戏对象。也能够应用 Ctrl (Windows) 或 Command (macOS) 键,在抉择范畴内增加或删除游戏对象。 留神:在 Editor 中须要抉择单个游戏对象来执行操作时,它将寻找“激活的”对象。例如,在轴心模式下,Unity 必须决定将哪个游戏对象用作变换组件工具的轴心。默认状况下,Unity 会将您抉择的第一个游戏对象视为“激活的”对象。每次按住 Shift 键并单击几个选定游戏对象之一时,即可更改哪个游戏对象处于激活状态。 某个游戏对象在 Scene 视图中处于激活状态时,Unity 不会显示任何可见的提醒来批示该游戏对象处于激活状态。然而,在 Scene 视图中,在轴心模式下抉择多个对象并按住 Shift 键重复单击时,即可看到哪个游戏对象处于激活状态。 然而,如果所解决的大型场景中蕴含很多场景项(例如游戏对象、地形对象、摄像机和光源),则抉择多个对象可能会十分辣手。为了不便仅抉择所需的项,能够应用场景拾取控件来阻止拾取某些对象。 场景拾取控件能够关上和敞开场景拾取控件来标记在 Editor 中工作时能够拾取的项。默认状况下,所有项都可拾取,然而您能够抉择在单击场景项时 Unity 跳过哪些项而不将它们增加到抉择范畴中。例如,如果在具备 10,000 多个对象的大型场景中工作,能够临时阻止抉择特定的游戏对象以避免误编辑。 将某一项标记为不可拾取后,即便无奈再在 Scene 视图中抉择或编辑该项,Unity 也会持续渲染该项。可拾取性状态仅在 Editor 中继续存在,并且仅在设置它的我的项目中针对该用户而继续存在。更改拾取状态不会“净化”场景(即算作批改)。 场景拾取控件与场景可见性控件十分类似。 Toggle pickability能够从 Hierarchy 窗口管制各个游戏对象在场景中的可拾取性。 ...

June 29, 2023 · 1 min · jiezi

关于unity3d:Unity3DScene-视图导航

举荐:将NSDT场景编辑器退出你的3D工具链3D工具集:NSDT简石数字孪生 Scene 视图导航场景视图具备一组导航控件,可帮忙您高效地到处挪动: 场景视图辅助图标挪动、旋转和缩放工具居中工具场景视图辅助图标场景辅助图标将显示在场景视图中。这将显示场景视图摄像机的以后方向,并容许您批改视角和投影模式。场景小控件在立方体的每一侧都有一个圆锥形臂。最后面的手臂标记为 X、Y 和 Z。单击任何锥形轴臂,将场景视图摄像机捕捉到它所示意的轴(例如:俯视图、左视图和前视图)。也能够右键单击立方体以查看蕴含视角列表的菜单。要返回到默认视角,请右键单击场景辅助图标,而后抉择自在。 您还能够关上和敞开透视。这会在透视和正交(有时称为“等轴测”)之间更改场景视图的投影模式。为此,请单击场景辅助图标核心的立方体或其下方的文本。正交视图没有透视,与单击其中一个圆锥轴臂联合应用以取得侧面、顶部或侧面立面十分有用。以透视模式(左)和正交模式(右)显示的场景 在正交模式下以顶部和右侧视图查看的同一场景 如果您的场景视图处于一个难堪的视点(颠倒或只是您感觉令人困惑的角度),请按住 Shift 并单击场景辅助图标核心的立方体以返回到透视视图,其角度从侧面和稍微从上方查看场景。 单击场景辅助图标右上角的挂锁以启用或禁用场景旋转。禁用场景旋转后,右键单击以平移视图,而不是旋转视图。这与视图工具雷同。 请留神,在 2D 模式下,不会显示场景辅助图标。2D 模式下惟一的视图选项是垂直查看 XY 立体。 Mac 触控板手势在带触控板的 Mac 上,可用两根手指拖动来缩放视图。 还能够应用三根手指来模仿单击__场景视图辅助图标__锥形臂的成果:向上、向左、向右或向下拖动可将 Scene 视图摄像机对齐到相应的方向。 在场景视图中挪动、盘绕和缩放挪动、动静察看和缩放是场景视图导航中的要害操作。Unity 提供了多种办法来执行它们以实现最大的可拜访性: 箭头挪动视图工具飞越模式摄像机速度挪动快捷键箭头挪动您能够应用箭头键在场景中挪动,就像在场景中“行走”一样。向上和向下箭头键可沿摄像机面向的方向向前和向后挪动摄像机。向左和向右箭头键可横向平移视图。按住 Shift 键和箭头键可放慢挪动速度。 视图工具抉择“视图”工具(快捷方式:Q)后,能够应用以下鼠标控件:管制:形容:挪动单击并拖动以挪动摄像机。旋转按住 Alt (Windows) 或 Option (macOS),而后左键单击并拖动以围绕以后枢轴点旋转相机。此选项在 2D 模式下不可用,因为视图是正交的。缩放按住 Alt (Windows) 或 Option (macOS),而后单击鼠标右键并拖动可缩放 Scene 视图。在 macOS 上也能够按住 Control,而后左键单击并拖动。按住 Shift 可进步挪动和缩放的速度。 飞越模式应用飞越模式以第一人称视角在场景视图中航行,相似于在许多游戏中的导航形式: 单击并按住鼠标右键。应用鼠标挪动视图,应用 WASD 键向左/向右/向前/向后挪动,应用 Q 和 E 键向上和向下挪动。按住 Shift 键能够放慢挪动速度。飞越模式是专为__透视模式__设计的。 在__正交模式__中,按住鼠标右键并挪动鼠标会使摄像机旋转。请留神,飞越模式在 2D 模式下不可用。相同,在挪动鼠标的同时按住鼠标右键会在场景视图中平移。 摄像机速度要在场景视图中更改摄像机的以后速度,请单击工具栏中的摄像机图标。在飞越模式下,您能够在场景中挪动时更改摄像机速度。为此,请应用鼠标滚轮或在触控板上拖动两根手指。 无关更多信息,请参阅摄像机设置文档。挪动快捷键为了提高效率,无论抉择哪种变换工具,都能够应用这些控件。 最不便的管制取决于您应用的鼠标或触控板:操作3 键鼠标2 键鼠标或触控板只有一个鼠标键或触控板的 Mac挪动按住 Alt+ 中键单击,而后拖动按住 Alt+Control+左键单击,而后拖动按住 Option+Command+左键单击,而后拖动旋转__(在 2D 模式中不可用) |按住 Alt+左键单击,而后拖动 |按住 Alt+左键单击,而后拖动 | Hold Option+left-click, then drag | | 缩放__应用鼠标滚轮,或按住 Alt+右键单击,而后拖动按住 Alt+右键单击,而后拖动应用双指轻扫办法向内和向外滚动,或按住 Option+Control +左键单击,而后拖动__更改速度__(仅在飞越模式中可用)在挪动时应用滚轮。挪动时用两根手指拖动挪动时用两根手指拖动 将视图居中置于游戏对象上要将 Scene 视图居中于游戏对象上,请在层级视图中抉择该游戏对象,而后将鼠标移到 Scene 视图上并按 F。 如果曾经抉择了游戏对象,按 F 会放大到轴心点。 此性能也可在菜单栏中的 Edit > Frame Selected 下找到。 要在游戏对象挪动时将视图锁定到游戏对象,请按 Shift+F。此性能也位于“编辑>锁定视图”下的菜单栏中。 此文由3D建模学习工作室整顿翻译,转载请注明出处!

June 29, 2023 · 1 min · jiezi

关于unity3d:Unity3DProject窗口

举荐:将NSDT场景编辑器退出你的3D工具链3D工具集:NSDT简石数字孪生 Project 窗口“我的项目”窗口显示与我的项目相干的所有文件,是您在应用程序中导航和查找资源和其余我的项目文件的次要形式。默认状况下,当您启动新我的项目时,此窗口处于关上状态。然而,如果找不到它,或者它已敞开,您能够通过“惯例>我的项目”窗口>或按 Ctrl+5 (macOS: Cmd+5) 关上它。处于 Tall 布局中的 Project 窗口 您能够通过单击拖动窗口顶部来挪动“我的项目”窗口。您能够将其停靠在编辑器中的地位,也能够将其拖出编辑器窗口以将其用作自在浮动窗口。您还能够更改窗口自身的布局。为此,请抉择窗口右上角的“更多”菜单 (⋮),而后从“单列布局”或“两列布局”中进行抉择。两列布局有一个额定的窗格,显示每个文件的可视预览。设置为 Two Column Layout 的 Project 窗口 浏览器的左侧面板将我的项目的文件夹构造显示为层级列表。 从列表中抉择文件夹时,Unity 将在右侧面板中显示其内容。 可单击小三角形来开展或折叠文件夹,显示文件夹蕴含的任何嵌套文件夹。 单击时按住 Alt 键将以递归形式开展或折叠所有嵌套文件夹。各个资源在右侧面板中显示为图标,这些图标批示了资源的类型(例如,脚本、材质、子文件夹)。 要调整图标的大小,可应用面板底部的滑动条; 如果滑动条挪动到最左侧,这些图标将替换为层级列表视图。 滑动条左侧的空白地位显示以后选定项,包含该项的残缺门路(如果正在执行搜寻)。 我的项目构造列表上方是 Favorites 局部,可在其中保留罕用项以不便拜访。 可将所需项从我的项目构造列表拖动到 Favorites 局部,也可在此处保留搜寻查问后果。 Project 窗口工具栏沿窗口顶部边缘的是浏览器的工具栏。 属性形容创立菜单显示能够增加到以后选定文件夹的资源和其余子文件夹的列表。搜寻栏应用搜寻栏来搜寻我的项目中的文件。 能够抉择在整个我的项目 (All)、我的项目的顶级文件夹(独自列出)、以后抉择的文件夹或 Asset Store 中进行搜寻。在搜寻中关上关上 Unity 搜寻工具以优化搜寻。按类型搜寻抉择此属性可将搜寻限度为特定类型,例如“网格”、“预制件”、“场景”。按标签搜寻抉择此属性可抉择要在其中搜寻的标签。保留搜寻将您的搜寻保留在左侧面板中的收藏夹下。暗藏的包裹计数抉择此属性可在 Project 窗口中切换包的可见性。搜寻筛选条件搜寻筛选器通过在搜寻文本中增加额定术语来工作。以“t:”结尾的术语按指定的资产类型进行筛选,而“l:”按标签进行筛选。如果您晓得要查找的内容,则能够间接在搜寻框中键入这些术语,而不是应用菜单。您能够一次搜寻多个类型或标签。增加多个类型将扩大搜寻以包含所有指定的类型(即,类型将一起进行 OR 运算)。增加多个标签会将搜寻范畴放大到具备任何指定标签的我的项目(即,标签将一起进行 OR 运算)。 搜寻 Asset StoreProject Browser 的搜寻也可利用于 Unity Asset Store 中可用的资源。 如果从示踪导航栏的菜单中选择 __Asset Store__,则会显示 Asset Store 中与查问匹配的所有收费和付费资源。 按类型和标签搜寻的工作形式与 Unity 我的项目雷同。 首先依据资源名称查看搜寻查问词,而后按程序查看资源包名称、资源包标签和资源包形容(因而,名称中蕴含搜索词的项的排名将高于资源包形容中蕴含该搜索词的项)。 如果从列表中抉择一项,该项的详细信息将显示在 Inspector 中,同时还提供购买和/或下载选项。 有些资源类型在此局部中提供了预览,因而能够在购买前旋转 3D 模型。 Inspector 还提供了一个选项容许在惯例 Asset Store 窗口中查看资源以理解更多详细信息。 ...

June 9, 2023 · 1 min · jiezi

关于unity3d:Unity-2022-Android-接入微信登录

实现Unity接入安卓端的微信登录分为五个大步骤 生成keystore安卓利用开发者签名在微信开放平台申请挪动利用接入编写Java Android局部代码, 生成arr文件编写 Unity C# 代码Unity打apk包, 装置到手机中进行测试倡议依照程序逐渐进行, 1, 2 步如果曾经实现, 可间接跳过. 尽管步骤有些多, 但这些步骤只有做一次就好, 往后点击两个按钮就能够实现代码更新. 生成keystore安卓利用开发者签名关上 IDEA , 新建我的项目 抉择上方工具栏, Generate Signed Bundle/ APK生成密钥点击 Create new别离填入 PasswordConfirm (再填一次明码)AliasAlias PasswordAlias ConfirmCertificate 中填一个就好 keystore签名蕴含一个密钥与多个子签名. 密钥用于开启 keystore 文件, 而一个子签名Key Alias 可用于对一个 Android 利用加密.这时可在 key store path 中看见文件须要将该文件转为 .keystore 文件我的testKey文件门路为 /Users/chenyuanzhen/Desktop/testKey执行以下命令 keytool -importkeystore -srckeystore /Users/chenyuanzhen/Desktop/testKey -srcstoretype JKS -deststoretype PKCS12 -destkeystore /Users/chenyuanzhen/Desktop/testKey.p12keytool -v -importkeystore -srckeystore /Users/chenyuanzhen/Desktop/testKey.p12 -srcstoretype PKCS12 -destkeystore /Users/chenyuanzhen/Desktop/testKey.keystore -deststoretype JKS实现后会失去 keystore 文件只须要保留 .keystore 文件就好.到此第一步完结 ...

May 14, 2023 · 4 min · jiezi

关于unity3d:Unity-3D游戏开发在Unity使用NoSQL数据库方法介绍

随着游戏体积和性能的一直叠加,游戏中的数据也变得越来越庞杂,这其中既包含玩家产生的游戏存档等数据,例如关卡数、金币等,也包含游戏配置数据,例如每一关的配置状况。只管Unity提供了PlayerPrefs用于存储用户数据,然而也仅实用于数据量较小的状况,一旦数据变得复杂起来,PlayerPrefs就变成了劫难。 NoSQL数据库 对于须要客户端存储数据的我的项目,本地数据库在此种状况下是最优解。Unity中须要保留的数据类型多样,甚至很多为资产内容而并不仅仅是二进制,NoSQL数据库显然更适宜Unity,LiteDB就是这样一款本地数据库,100%基于C#开发,收费开源,能够间接导入Unity应用。 一、导入Unity1. 应用VS关上Unity我的项目。 2. 进入Nuget包管理器VS中找到工具--Nuget包管理器--程序包管理器控制台 3. 装置LiteDB装置脚本 https://www.nuget.org/package... LiteDB -Version 5.0.11输出后回车即可装置4. 导入Unity工程 刚刚应用Nuget曾经下载到最新的包,接下来将它导入Unity工程即可。将LiteDB.dll和LiteDB.xml一起导入到Unity工程的Plugins门路下。 应用Unity从新生成VS工程删除我的项目中原来的VS工程文件,从新生成,以便对dll文件生成援用。 指定依赖脚本为了防止Unity的代码剪裁,在Unity工程门路下创立link.xml 二、应用LiteDBUnity调用如下 三、最终成果 四、3DCAT实时云渲染为云游戏提供坚实基础凭借业界当先的企业级一站式云游戏平台计划,3DCAT将继续在全国范畴内搭建超低提早的边缘计算节点,确保平台云游戏晦涩度。3DCAT在给游戏玩家提供超高清云游戏服务的同时,凭借高速带宽和疾速响应的个性,给玩家带来专业级精美画质和动静渲染的成果,并通过动静检测、智能举荐等伎俩,让用户随时随地、即点即玩。 在将来的长期倒退中,云游戏平台除了深挖游戏内容,向游戏产业链上下游衍生,拓展游戏研发及散发业务,3DCAT也可将基于游戏开发引擎(Unity、UE4等)制作的超大型元宇宙社区+内容进行云端计算渲染,并通过网络及串流技术,实时推送到终端。满足宽广用户随时随地跨终端、可交互、超高清、沉迷式、线上社交的拜访需要。 当初注册立赠79分钟实时云渲染收费体验! 点击注册本文《【Unity 3D游戏开发】在Unity应用NoSQL数据库办法介绍》内容由3DCAT实时云渲染解决方案提供商整顿公布,如需转载,请注明出处及链接:https://www.3dcat.live/share/...

February 17, 2023 · 1 min · jiezi

关于unity3d:C速成指南从入门到进阶实战WPF与Unity3D开发

download:C#速成指南:从入门到进阶,实战WPF与Unity3D开发备:https://www.97yrbl.com/t-1374... 浅谈AB包Unity资源管理在Unity中,一般来说,资源加载形式次要分为Resources加载和AssetBundle加载。 Unity有个非凡文件夹Resources,放在这个文件夹下的资源能够通过Resources.Load()来间接加载。即Resources加载资源形式。 当取得AssetBundle之后,也能够调用AssetBundle对应的API来加载资源。 什么是AB包AB包全名AssetBundle(资源包)。是一种Unity提供的用于寄存资源的包。通过将资源散布在不同的AB包中能够最大水平地缩小运行时的内存压力,并且能够有选择地加载内容。 为什么要用AB包1、热更新。(要热更新须要确保AB包打进去的资源具备唯一性,且雷同资源的AB包检验码雷同。) 2、Resources加载尽管简略不便,然而也有很多问题: 对内存治理造成肯定的累赘。在关上利用时加载工夫很长。Resources文件夹下的所有资源对立合并到一个序列化文件中(能够看成对立打一个大包,巨型AB包有什么问题它就有什么问题),对资源优化有肯定的限度。不倡议大量应用Resources。应用办法 打AB包:public static AssetBundleManifest BuildAssetBundles(string outputPath, BuildAssetBundleOptions assetBundleOptions, BuildTarget targetPlatform); 1BuildAssetBundleOptions枚举类型的值转化为二进制都是只有一位是1,其余位都是0。如UncompressedAssetBundle是0000 0000 0001,IgnoreTypeTreeChanges是0000 0100 0000,DisableLoadAssetByFileName是1000 0000 0000。 BuildAssetBundles底层会对传入的BuildAssetBundleOptions值进行解决,依据二进制位数来判断应用哪种策略构建AB包。因而如果在构建AB包时想要应用多种策略,用&连贯即可。 BuildTarget参数用来抉择针对的平台,因为AB包在不同平台下是不兼容的。 设置资源AB包名: `AssetImporter.assetBundleName // AB包名AssetImporter.assetBundleVariant // AB包变体名` 获取AB包办法:`AssetBundle.LoadFromFile(string path)AssetBundle.LoadFromFileAsync(string path)AssetBundle.LoadFromMemory(byte[] binary)AssetBundle.LoadFromMemoryAsync(byte[] binary)AssetBundle.LoadFromStream(Stream stream)AssetBundle.LoadFromStreamAsync(Stream stream)WWW.assetBundle`

March 21, 2022 · 1 min · jiezi

关于unity3d:C速成指南从入门到进阶实战WPF与Unity3D开发吾爱fen享

download:C#速成指南:从入门到进阶,实战WPF与Unity3D开发无密AOP产生背景应用面向对象编程 ( OOP )有一些弊病,当须要为多个不具备继承关系的对象引人同一个公共行为时,例如日志、平安检测等,咱们只有在每个对象里援用公共行为,这样程序中就产生了大量的反复代码,程序就不便于保护了,所以就有了一个对面向对象编程的补充,即面向方面编程 ( AOP ), AOP 所关注的方向是横向的,区别于 OOP 的纵向。 什么是AOP什么是面向方面编程,3个过程: 找到横切点:首要指标确定在程序的哪个地位进行横切逻辑横切逻辑(业务代码):横切逻辑代码,这个就是横切业务代码,与aop无关织入:将横切逻辑织入到横切点开发者次要关怀的是横切逻辑的编写,只须要很少的代码编写确定横切点有哪些,而不须要去为每个横切点增加横切逻辑,不然就是面向对象编程了。 既然是横向的编程,那么在咱们的程序中,哪些能够作为横线切入点呢? 看下示例代码: public class Test { public static void main(String[] args) { //@1 B b = new B(); //@2 b.method(); //@3 B.say(); } static class B { //字段 //@4 private String name; //构造方法 public B() { //@1.1 } //对象办法 public void method(){ //@2.2 } //静态方法 static void say(){ //@3.3

March 16, 2022 · 1 min · jiezi

关于unity3d:C速成指南从入门到进阶实战WPF与Unity3D开发

download:C#速成指南:从入门到进阶,实战WPF与Unity3D开发第一局部:在集成HMS Core SDK之前,您须要先注册成为开发者,并增加本人的我的项目和利用。 首先,拜访华为开发者官网,点击HUAWEI MOBILE SERVICES,进入华为挪动服务开发者网站;点击管理中心,进入登录页面;点击注册按钮,进入华为账号注册页面,输出相干信息进行注册即可。 账号注册胜利后,接下来增加我的项目:先登录华为开发者网站,输出用户名和明码,登录胜利后,点击“AppGallery Connect”,进入AppGallery Connect页面,点击“我的我的项目”,点击“增加我的项目”,输出“项目名称”,点击“确认”后即可增加我的项目。 我的项目增加胜利后,接下来增加利用:点击“增加利用”,抉择平台,目前DTM反对Android、iOS和Web平台,抉择反对的设施,填写利用名称和利用包名,抉择利用分类和默认语言,点击“确认”即可增加利用。 第二局部:接下来,咱们学习如何集成DTM Android SDK:1. APPGallery Connect环境筹备。第1步,开启华为剖析服务:抉择动静标签治理。如果没有显示“开启剖析服务”按钮,阐明曾经开启剖析服务。点击“开启剖析服务”跳转到华为剖析页面;点击“启动剖析服务”,抉择数据处理地位、抉择时区;点击“实现”按钮,期待剖析服务开明实现。 第2步:配置我的项目的bulid.gradle文件。关上Android Studio我的项目级的“build.gradle”文件,增加华为agc插件,增加HMS Core SDK的Maven仓地址。 第3步:配置利用的bulid.gradle文件。关上利用级的“build.gradle”文件,增加agc插件,增加Analytics和DTM SDK的编译依赖。 第4步:配置混同脚本。关上利用级的混同配置文件,退出混同配置。

March 16, 2022 · 1 min · jiezi

关于unity3d:Unity3D打砖块游戏入门教程

明天来实现一个3D打砖块游戏,十分的简略,是正经的入门教程,然而学到的都是Unity游戏开发中重点的内容,上面一起来理解下吧。 新建3D游戏我的项目关上Unity Hub软件,咱们新建一个3D我的项目,新建好之后双击关上就好了。 初始化我的项目目录在Assets目录下新建以下文件夹: Scenes:寄存游戏场景,默认新建我的项目就有,没有则新建Materals:寄存材质,比方一辆车有不同的色彩和样式Prefab:寄存预制件,打砖块中砖块和子弹会呈现很多,咱们能够为其设定预制件Scripts:寄存游戏脚本文件,脚本里有游戏的运行逻辑。创立高空新建一个叫 Plane 的3D对象,并在Assets/Materals新建一个同名的材质,为咱们的高空增加款式,高空太小能够在右侧属性面板中找到Transform组,批改缩放值,X为20,Z为20。 创立砖块墙新建一个 Cube 的3D对象,而后将其设置为一个Prefab,并且增加个物理引擎“刚体”的组件(让其有物理成果,自由落体等)。 复制多个 Cube 的Prefab,使其变为一堵墙,编一个组为 Cubes 。 创立子弹同样,在 prefab 下新建个 Bullet的预置件,并为其设置组件》物理》刚体,让其也有物理成果。 咱们需要是这样的,在按下鼠标左键时会创立一颗子弹,并执行其动画(挪动和砖块撞击),并且是在摄像机的侧面方向射出。 为了实现下面需要,新建一个脚本文件 Shoot.cs ,代码如下: using System.Collections;using System.Collections.Generic;using UnityEngine;public class Shoot : MonoBehaviour{ public GameObject bullet; public float speed = 10; void Update() { //按下鼠标左键 if (Input.GetMouseButtonDown(0)) { GameObject b = GameObject.Instantiate(bullet, transform.position, transform.rotation); Rigidbody rgd = b.GetComponent<Rigidbody>(); rgd.velocity = transform.forward * speed; } }}代码解析: 创立了两个公共属性, bullet是子弹,speed是子弹发射的速度update是帧更新的生命周期,它在游戏运行后每秒后执行60次左右在 update 办法中,咱们监听了鼠标左键,而后获取了子弹的本体,获取它的刚体, 设置它的刚体速度,它的方向是正前方 transform.forward。当初就能够实现子弹的发射了,不过当初子弹只能在一个方向上发射,上面咱们就来解决这个问题。 ...

September 17, 2021 · 1 min · jiezi

关于unity3d:Unity游戏引擎中的脚本

明天看了些Unity在虚构仿真上的利用,以及Unity3D游戏开发的教程,最初重点看了下Unity中文文档“脚本”这块的内容,发现与我之前用的cocos creator简直一样,除了应用的编程语言不一样,内置UI,事件,游戏对象的属性面板都差不多,这也为我省下了不少工夫。 Cocos 合成大西瓜游戏在4个月前,我已经也折腾过一两个礼拜的游戏开发,做的是“合成大西瓜”的游戏: 应用的脚本语言是Typescript,我发现Cocos的脚本构造和Unity的差不多一样,就比如说游戏对象的生命周期: 在Cocos脚本中 export default class Game extends cc.Component { start() {} update() {}}在Unity脚本中 using System.Collections;using System.Collections.Generic;using UnityEngine;public class Game : MonoBehaviour{ void Start(){} void Update(){}}当然还有很多雷同的局部,游戏引擎应该都这样设计的吧。 什么是游戏脚本?脚本是什么?对于游戏引擎来说脚本到底干了些什么? 首先要明确一点,脚本对于任何一个游戏引擎来说都是必不可少的局部。 它的主要用途是响应玩家的输出,安顿游戏过程中就产生的事件,实例化图形成果,管制游戏对象的物理行为,还能够为角色自定义AI零碎等等。 Unity中的脚本概念Unity创立脚本Project 面板左上方的 Create 菜单新建脚本抉择 Assets > Create > C# Script 来新建脚本Unity脚本文件分析using System.Collections;using System.Collections.Generic;using UnityEngine;public class Wall : MonoBehaviour{ // Start is called before the first frame update void Start() { } // Update is called once per frame void Update() { }}MonoBehaviour内置类派生类,用于创立可附加到游戏对象的新组件类型。Update(),解决游戏对象的帧更新。Start(),脚本初始化的地位。Unity中的PrefabsPrefabs中文翻译过去是预制件,它个别用于想在运行时实例化简单的游戏对象或游戏对象的汇合时应用,它十分不便,与应用代码从头开始创立游戏对象相比,有以下长处: ...

September 16, 2021 · 1 min · jiezi

关于unity3d:unity2021游戏引擎安装激活并汉化

明天从新搭建了下unity的开发环境,也踩了不少坑,还有就是看了一些unity3d的教程,越看越不堪设想,unity竟然能做这么多好玩的货色,像枪战类,模仿类,角色扮演,动作冒险都很震撼。 然而震撼归震撼,如果本人独立开发的话,只能做小型的2d游戏,像3d的,除去编码不说,还要会建模,美术,国内有款 cocos 和 unity很像,也反对2d和3d,而且反对javascript开发,不过我学习这个首要任务还是做虚构仿真,所以必然要学unity了。 让咱们开始搭建unity的环境吧! 下载Unity程序你须要注册一个 unity 官方网站的账号,反对微信登录,然而有一系列的绑定流程,包含邮箱和手机号,最好都弄一下。 关上官网下载页面 https://unity3d.com/cn/get-un... ,unity 和 unityHub 这两个都要下载下来。 抉择集体版本,下载程序Unity不占用C盘默认unity是会占用c盘空间的,我第一次下载,一下就少了30多个g(下载了几个版本加vs),那么怎么解决这个占用问题呢? unity在C盘默认的地位是 C:\Program Files\Unity,咱们在W盘新建个Hub目录,而后创立一个快捷打开方式,拖动快捷方式到unity默认装置地位里,像上面这样: 这样就不会占用C盘空间了。 UnityHub是什么unity游戏开发的主程序,那么UnityHub是什么呢? UnityHub 是一个管理工具,用于治理你的所有 Unity 我的项目,治理所有Unity的版本,unity有很多版本,假如你用2017.x版本开发了游戏,我用2021.x版本是关上不了的,版本相差太大,而有了UnityHub,咱们能够很不便的下载某个版本,关上对应的我的项目。 Unity激活关上 UnityHub, 登录账号,点击右上角设置》许可证治理》手动激活 在弹出窗口中“保留许可证申请”,而后到手动激活页面,会取得一个许可证文件,上传这个文件就能够激活了。 Unity汉化汉化对于英文不好的人来说是必须的,因为不汉化的界面有大量英文,会影响开发效率,就像上面这样,看起来都很费劲: 两种汉化形式: 手动下载中文汉化包,将汉化包放进unity装置目录下Editor\Data\Localization目录下,没有则新建。应用unity-hub下载不同版本时,勾选版本反对的语言。汉化后: 结尾付上unity做的电影和一个3d科幻游戏。 完! 您的点赞、评论、关注是对小编最大的激励 O(∩_∩)O 我是极客猿小兵,公众号【极客猿】,记录独立开发者学习成长,一起走向财产自在。

September 15, 2021 · 1 min · jiezi

关于unity3d:Unity-Timeline研究之基础篇一

一、Timeline简介1.1 入口Window->Sequencing->Timeline 1.2 自带Track简介1) Track GroupTrack组,能够放多个track,能够用来按组分类划分2) Activation Track激活Track,用来管制GameObject是否激活3) Animation Track用来管制Animation的播放4) Audio Track用来管制Audio的播放5) Control Track用来管制prefab、特效、gameobject等的工夫线管制,且在clip外会主动销毁6) Signal Track用来发射信号,登程事件7) Playable Track用户自定义的轨道 二、Signal介绍信号,能够播送,是timeline触发事件的媒介,因为其具备播送的性质,所以比event的名字更适宜 2.1对于信号的应用2.1 如何增加信号1)右击任何一个Track,在弹出的菜单栏中点击Add Signal Emitter即可增加信号2)信号增加好后,会呈现下图中的游标,带正告的游标阐明没有抉择要触发的信号类型(Emit Signal为none)3)选中Signal游标,在检视版中抉择触发的信号类型4)Signal选好后,须要在下方增加一个Signal Receiver用来抉择接管信号的办法,同按钮点击事件,不在赘述5)至此当timeline播放到signal游标处就会触发对应的事件了,(留神,signal触发的事件,只有signal所在track上的对象上的signal receiver失效) 2.1.2 如何增加带参信号1)继承SignalEmitter,实现一个新的信号触发器,并在其中退出新的参数2)增加自定义的信号。当创立了新的SignalEmitter时,timeline会在原增加信号菜单处退出增加新信号的菜单3)抉择信号类型同一般信号。4)signal receiver须要本人实现,在挂在track的对象上,这个时候就能够通过 notification获取带参信号的参数了~ 三、对于自定义Tracktimeline很弱小,除了自带的轨道,还能够本人定义轨道,从而可能依据本身须要增加timeline clip 3.1 如何自定义Track3.1.1 创立新轨道1)很简略,继承TrackAsset就能够了2)这个时候右击timeline的菜单中就呈现自定义的轨道了3)track罕用的3条个性 1>[TrackColor(0,0,0)]管制轨道flag的色彩2>[TrackClipType(typeof(TestDemoAsset1))] 能够增加哪些clip类型3>[TrackBindingType(typeof(TestTimeline))] 指定能够应用此track的对象类型3.1.2 创立clip类型1)创立playableasset和playablebehaviour2)自定义asset的参数,且参数须要通过对应的behaviour传递3)实现behaiour4)至此自定义的clip就创立实现了 3.1.3 对于混合behaviour1)混合behaviour次要用于解决两个clip重叠局部的体现。2)创立混合baviour。须要在track类里创立。3)实现混合behaviour。和clip的behaviour一样,只是要依据多个clip的权重,来调整behaiour成果

July 26, 2021 · 1 min · jiezi

关于unity3d:Unity3D开源棋牌游戏

棋牌金币游戏性能介绍金币类棋牌游戏大厅!!!<br/>能够自由组合,开发出不同的大厅,打造本人的大厅!游戏大厅反对斗地主,3D麻将 (红中麻将,血战麻将,广东麻将等),多款捕鱼(金蟾捕鱼,悟空脑海,摇钱树,美人鱼),跑得快等各种益智棋牌游戏(请看最初一张图片),反对多人娱乐,反对茶馆俱乐部。当然当你理解我的项目后,你也能够本人开发本人的游戏,打造本人残缺的产品。 软件技术开发工具:Unity3D (Unity 5.4.0f3 )开发语言:Java + C服务端框架:SmarkfoxServer2x + MySQL客户端语言:C容许成果间接运行可执行游戏 ,局部效果图如下: 代码地址:https://gitee.com/DaLianZhiYiKeJi/chessgame

July 22, 2021 · 1 min · jiezi

关于unity3d:unity-中三种更新方式

unity中存在三种更新形式Update、FixedUpdate、LateUpdate。这三种更新形式别离利用于不同的情景。Update更新update是每次渲染新的一帧时才会调用,和机器性能有着严密的分割。如果机器的性能较差或者场景较简单,Update的更新频率会呈现较大的稳定,因而和机型性能以及须要精准计算的操作不宜呈现在Update中。 FixedUpdate固定更新FixedUpdate是固定工夫更新,也就是说这个函数和帧率无关,他的更新频率是固定的。在unity中默认的更新频率是0.02秒,当然你也能够通过Edit->ProjectSetting->Time->FixedTimeStep来设置更新频率。FixedUpdate利用于物理碰撞和倒计时等须要精准数据的操作。如果把物理操作放在Update中,因为碰撞检测的工夫是固定的,当物体产生碰撞时,如果人物未进行挪动,则下一帧物体会继续移动,这样就会产生抖动。艰深来讲就是Update的更新频率太快大于了碰撞检测的频率,物体曾经向前挪动了,但还未进行碰撞检测,因而人物会穿梭过来,待碰撞检测结束后人物又会被弹出去。 LateUpdate晚于更新LateUpdate是提早更新函数。处于激活状态下的脚本每一帧都会在Update执行结束后再执行LateUpdate,通常用来调整代码的执行程序。LateUpdate配合Update经常会产生意想不到的成果。例如物体的追随(相机视角追随人物挪动)如果相机放在Update有可能会呈现抖动,这是因为相机可能先于人物执行了追随挪动指令,人物之后再执行挪动指令,此时相机的视距就会发生变化,因而就会产生抖动。如果经相机操作写在Update中能够确保人物地位确定结束后再确定相机的地位和旋转。

July 20, 2021 · 1 min · jiezi

关于unity3d:黑魂复刻游戏的手柄输入支持Unity随手记

明天实现的内容:Input Manager要配置好手柄,咱们将应用Unity自带的Input Manager,这个零碎可能很好的打消输出设施的差别,对立各项输出,还能自定义新输出,并提供了输出相干的参数可供批改。仔细观察能够发现,默认的Input Manager里每种输出模式都设置了两个。以Horizontal为例,其中一个是键盘输入,另一个是手柄输出,当咱们应用键盘时,Horizontal失去的是应用键盘输入,换成手柄当前Horizontal会主动变成手柄,十分智能。当然如果你无意要区别手柄,你也能够将第二个Horizontal改个名字。上面的图展现了我设置的XBOX手柄输出设置。JoystickInput类JoystickInput类对标原PlayerInput类,原PlayerInput类被咱们写成了键鼠专用,所以当初被我改名为MouseKeyboardInput。!JoystickInput代码如下,相似MouseKeyboardInput: using System.Collections;using System.Collections.Generic;using UnityEngine;public class JoystickInput : MonoBehaviour{ [Header("==== 手柄按键 ====")] // 角色挪动管制轴 public string movementAxis_X = "X axis"; public string movementAxis_Y = "Y axis"; // 摄像机管制轴 public string cameraAxis_X = "4th axis"; public string cameraAxis_Y = "5th axis"; // 游戏功能键 public string buttonRun_jab_roll = "A"; //冲刺/后跃/翻滚 public string buttonJump = "LS"; //跳跃键 public string buttonAttackRHand = "RB"; //攻打键 public string keyD; [Header("==== 输入信号 ====")] // 角色管制信号 damp之后的 向上/向右 方向值 public float dirUp; public float dirRight; // 玩家的输出模长量 用于当成向前量大小作为动画管制 public float dirMag; // 玩家的方向 用于旋转模型 public Vector3 dirVec; // 摄像机管制信号 public float cameraUp; public float cameraRight; // 按压信号 public bool run; //奔跑信号 是否正在奔跑 // 一次性信号 public bool jab_roll; //后跃/翻滚信号 public bool jump; //跳跃信号 public bool attack; //攻打信号 [Header("==== 其它参数 ====")] // 模块软开关 public bool inputEnabled = true; // 输出的damp工夫 protected float dampTime = 0.1f; // 向上/向右 的最终方向值 用于将四键输出转换为双轴输出 protected float m_targetDirUp; protected float m_targetDirRight; // 向上/向右 damp的currentVelocity参数 protected float m_velocityDirUp; protected float m_velocityDirRight; // 映射后的输出双轴 protected Vector2 m_dirAxis; // 按键按压计时器 protected float pressTimer; // 单击的间隔时间 小于等于这个工夫是单击 大于这个工夫是长按(Long Press) protected float clickIntervalTime = 0.2f; // Update is called once per frame void Update() { // 摄像机信号 cameraUp = Input.GetAxis(cameraAxis_Y); cameraRight = Input.GetAxis(cameraAxis_X); // 角色信号 // 将高低键的输出整合 计算向上方向的输出大小 m_targetDirUp = Input.GetAxis(movementAxis_Y); // 将左右键的输出整合 计算向右方向的输出大小 m_targetDirRight = Input.GetAxis(movementAxis_X); // 输出模块是否敞开 这段代码肯定要放在这个地位 if (!inputEnabled) { m_targetDirUp = 0; m_targetDirRight = 0; } // 使用SmoothDamp来取得突变的输出变动 dirUp = Mathf.SmoothDamp(dirUp, m_targetDirUp, ref m_velocityDirUp, dampTime); dirRight = Mathf.SmoothDamp(dirRight, m_targetDirRight, ref m_velocityDirRight, dampTime); // 计算输出模长 dirMag = Mathf.Sqrt(dirUp * dirUp + dirRight * dirRight); // 计算玩家的方向 dirVec = dirRight * transform.right + dirUp * transform.forward; // 冲刺/后跃/翻滚信号 Jab_RollOrRun(buttonRun_jab_roll); // 攻打信号 attack = Input.GetButtonDown(buttonAttackRHand); // 跳跃信号 if (run && Input.GetButtonDown(buttonJump)) jump = true; else jump = false; } // 长按还是单击 决定是冲刺还是翻滚/后跃 private void Jab_RollOrRun(string _key) { if (Input.GetButtonDown(_key)) { pressTimer = 0; } if (Input.GetButtonUp(_key) && pressTimer <= clickIntervalTime) { jab_roll = true; } else { jab_roll = false; } if (Input.GetButton(_key)) { pressTimer += Time.deltaTime; if (pressTimer > clickIntervalTime) run = true; } else { run = false; } }}用抽象类对立不同的输出设施到目前为止,咱们的游戏键鼠输出和手柄输出是离开的,其中有很多一样的货色,咱们能够应用一个抽象类来将这些不同的输出设施对立起来。咱们这个新的抽象类就取以前的老名字,叫IPlayerInput,I示意它做为接口。 ...

June 15, 2021 · 3 min · jiezi

关于unity3d:Unity3D动作游戏开发实战笔记及扩展21

2.1.1. 应用协程合成简单逻辑协程解决异步工作:当遇到一些须要异步解决的程序需要时,能够应用协程来实现应用协程的长处:简略,易于实现实例:应用协程代替无限状态机 (基于原书的代码做了些许批改以及减少了正文) //一个示意村民的类public class Villager : MonoBehaviour{ public float maxSatiation = 10f; //最大饱食度 public float maxFatigue = 10f; //最大困倦值 const float minSatiation = 0.2f; //最小饱食度 const float minFatigue = 0.2f; //最小困倦值 private float satiation; //以后饱食度 private float fatigue; //以后困倦值 Coroutine currentCoroutine; //以后的状态(协程) //OnEnable在脚本被激活时立刻执行 void OnEnable() { satiation = maxSatiation; //初始化饱食度,设为最大值 fatigue = maxFatigue; //初始化困倦值,设为最大值 StartCoroutine(Tick()); //开始“游戏循环”的协程 } //模仿“游戏循环”,相似MonoBehaviour的Update办法 IEnumerator Tick() { //每帧进行一次循环 while(true) { DecrePerFrame(satiation); //缩小饱食度 DecrePerFrame(fatigue); //缩小困倦值 //如果饿死了且以后的状态为空,开始“吃”协程,并定“吃”为以后状态 if(satiation < minSatiation && currentCoroutine == null) { currentCoroutine = StartCoroutine(Eat()); } //如果困死了,不论当初在干啥,间接开始“睡”协程,并定“睡”为以后状态 if(fatigue < minFatigue) { currentCoroutine = StartCoroutine(Sleep()); } //进展一帧 yield return null; } } IEnumerator Eat() { //每帧吃一点,吃到饱为止 while(satiation < maxSatiation) { IncrePerFrame(satiation); yield return null; } //吃饱了,以后状态改回空 currentCoroutine = null; } IEnumerator Sleep() { //立刻进行以后正在干的事(例如"吃") StopCoroutine(currentCoroutine); //如果没睡够,持续睡 while(fatigue < maxFatigue) { IncrePerFrame(fatigue); yield return null; } //睡够了,以后状态改为空 currentCoroutine = null; }}2.1.2. 自定义的插值公式什么是插值(interpolation):在两个值/地位之间定义一个新的值/地位插值通用公式:P01 = (1 - u) P0 + u P1;u是什么:在线性内插中,u为一个0-1之间的浮点数,用于决定咱们取得的插值更凑近P0还是P1. (线性外插的u是<0或者>1的,在游戏中并不罕用)罕用的插值公式线性插值:u = u缓进:u = u * u缓出:u = 1 - (1 - u) * (1 - u)缓进出:u = ((u - 1) (u - 1) (u - 1) + 1) ((u - 1) (u - 1) * (u - 1) + 1)Sin波长:u = u + range(0, 1) sin(u 2 * PI)2.1.3. 音讯模块的设计音讯/事件治理:游戏中往往有大量相互连贯的元素,而他们非常须要音讯零碎的反对。音讯/事件的作用:在一个事件产生时,与之相干的后果被一并触发(例如,击杀一个敌人,咱们的成就零碎要记录咱们多击杀了一个敌人,这就是音讯/事件的用武之地)音讯模块的缓存:通常状况下,一个事件被触发后,会立刻告诉所有订阅的监听者,但这并不适用于所有的状况(例如玩家取得新武器,背包内的新武器会高光显示,但此时玩家还没关上背包,而等到关上时事件却早就告诉过监听者了)实例:音讯模块的繁难实现 (基于原书的代码简化成伪代码) ...

June 2, 2021 · 2 min · jiezi

关于unity3d:Unity-关于ComputeShader中ThreadGroup和numthreads的理解

明天遇到一个神奇的景象,我设置了一个100 * 100的 texture,而后应用 ComputeShader 让它填充一些色彩,后果却有一个黑边。 代码如下所示: _renderTexture = new RenderTexture(100, 100, 24); _renderTexture.enableRandomWrite = true;_renderTexture.Create(); shader.Dispatch(0, _renderTexture.width / 8, _renderTexture.height / 8, 1);[numthreads(8,8,1)]void CSMain (uint3 id : SV_DispatchThreadID){ Result[id.xy] = float4(float3(id) / 100, 1);}最终咱们失去的图像是这样的,能够看到有个黑边。 我尝试了一下,如果我将 shader.Dispatch(0, _renderTexture.width / 8, _renderTexture.height / 8, 1); 中的 8 改为 9。 shader.Dispatch(0, _renderTexture.width / 9, _renderTexture.height / 9, 1);就会发现,这条黑边,变得更加宽了。 通过我查阅相干文档后,我了解了一下 Dispatch 办法的三个参数是说在XYZ三个方向上划分多少个线程组。回到之前的 8 。也就是划分了 100 / 8 = 12.5 -> 12 个线程组。 ...

May 6, 2021 · 1 min · jiezi

关于unity3d:Unity3D-Vector3Lerpx-y-TimedeltaTime-是什么意思

最近看到一些代码,发现外面会这样写 Vector3.Lerp(x, y, Time.deltaTime),deltaTime 是此时间隔上一次调用的工夫,它并不是[0, 1],所以这个插值是什么意思呢? 其实,这是一个加速的线性插值,我举一个非常简单的例子。比方要让以后物体的地位从0,挪动到100。 float currPosition = 0;void Update() { float currPosition = ...; float targetPosition = Vector3.Lerp(currPosition, 100, Time.deltaTime); // use target position to update}假如 Time.deltaTime 是 0.2,那么第一次调用后 0 -> 100 进度:0.2,差值为20,targetPosition = 20下一次调用时,则是 20 -> 100,进度 0.2,差值是 $(100 - 20) * 0.2 = 16$,所以 targetPosition = 20 + 16 = 36 以此类推,能够看出,因为 deltaTime 是一个能够了解为恒定的数值,而起始数据和指标数值会随着迭代,起始数值一直凑近指标数值,这样每次步进的差值就会越来越小。 迭代 起始->指标 deltaTime 步进差值 以后迭代的后果0: 0 -> 100, 0.2, 20, 201: 20 -> 100, 0.2, 16, 362: 36 -> 100, 0.2, 12.8, 48.83: 48.8 -> 100, 0.2, 10.2, 594: 59 -> 100, 0.2, 8.2, 67.25: ....心愿以上内容对你有帮忙。 ...

March 9, 2021 · 1 min · jiezi

关于unity3d:Unity3D移动的-Static-Collider-无法产生碰撞的问题

最近遇到一个问题,有一个 Rigidbody Collider 无奈与挪动的Static Collider 产生碰撞。 找到上面这篇文档:https://docs.unity3d.com/Manu... 外面解释了 Static Collider 就是只有 Collider 然而没有 Rigidbody 的物体,Static Collider 个别用于静止不动的物体,比方地板。而须要挪动的物体则须要加上 Rigidbody 能力有碰撞产生。

February 19, 2021 · 1 min · jiezi

关于unity3d:游戏分类

游戏分类思维导图 具体介绍下面是对游戏简略的分类,上面会对游戏的分类进行具体的介绍 游戏平台游戏平台顾名思义就是运行游戏的中央 主机游戏:Xbox、PS、Wli 电脑游戏:PC、Mac 街机游戏:游戏机 便携游戏:NDS、PSP、手机 游戏载体电子游戏 电子游戏(Video Games)又称电玩游戏,是指所有依靠于电子设备平台而运行的交互游戏 游戏特色 互动性:即人与电子设备之间产生的一种分割,一种反馈模仿性:对事实世界或思维世界的模仿长处 促孩童养成良好习惯,助老人大脑灵便运行电子游戏可进步视觉搜寻能力电子游戏有助于进步动静视力毛病 沉浸电子游戏,不务正业助长青少年叛逆暴力、色情等因素非电子游戏 不在电子设备平台上进行的游戏,如弹子,棋牌类游戏,变形金刚,纸飞机等等 游戏内容角色扮演类游戏 角色扮演游戏通常有残缺的故事情节,游戏中玩家能够抛开本人的身份,表演游戏中的某些角色,取得某种代入感的满足,如《仙剑奇侠传》《最终幻想》《上古卷轴》,在RPG游戏中玩家好像取得了游戏角色的经验和体验,如同演员般“入戏”。这须要构建一个逻辑精妙、完满自洽的游戏世界,也须要一个充斥自由度的游戏环境,更须要小说巨著般的游戏剧情和人物塑造,玩家在游戏的过程中取得的是比小说、电影更加真切的代入体验。 模仿类游戏 模拟游戏,现今多为电子游戏,是一种宽泛的游戏类型。模拟游戏试图去复制各种“事实”生存的各种模式,达到“训练”玩家的目标:如进步熟练度、剖析状况或预测。仿真水平不同的模拟游戏有不同的性能,较高的仿真度能够用于专业知识的训练;较低的能够作为娱乐伎俩。 “仿真”是模拟游戏的外围。“真”代表真实世界,仿真水平越高的模拟游戏越对现实生活有帮忙意义;反之,较低的仿真水平会让游戏减少娱乐性。仿真水平的高下并不代表模拟游戏的优良与否,而是游戏面对的市场。 模拟游戏能够提供三种用处:策略、打算和训练,他们三个别离对应“娱乐”、“模仿”和“案例钻研”。尤其是第三者常在模拟游戏中体现,因为模拟游戏能够模拟一些事实中无奈常常遇到的情况。已有不少机构采纳模拟游戏来进行教学领导。越高仿真度太高的模拟游戏会被称为“虚构训练软件”,但实际上两者是一回事。模拟游戏带来的种种长处曾经在东方教学界引起器重,许多钻研人员试图反对模拟游戏的倒退,以让他们进入生存中的方方面面。 模拟游戏也带来了对“游戏”这个词语定义的扭转。模拟游戏证实,如果把“游戏”二字作为等同于“娱乐”的阐释,是全面的。游戏代表一种综合性、交互性的多媒体体验,模拟游戏正是能够将这种交互性体验为社会带来奉献的游戏类型。在“游戏”二字定义扩充之前,很多人将这种带有利用性质的游戏命名为“庄重游戏”(Serious Game),尽管这是谬误的。 策动类游戏 策略游戏,这类游戏提供给玩家一个能够多动脑筋思考问题,解决较简单事件的环境,容许玩家自在管制、治理和应用游戏中的人、或事物,通过这种自在的伎俩以及玩家们开动脑筋想出的反抗敌人的方法来达到游戏所要求的指标。 分类:策略游戏可分为回合制和即时制两种,回合制策略游戏如大家喜爱的《三国志》系列(三国志7、8、10为RPG类型游戏)、《樱花大战》系列,又如星战回合策略类网游《星际文化》;即时制策略游戏如《命令与驯服》系列、《帝国时代》系列、《沙丘》等。起初在策略类游戏的倒退中造成了一种游戏办法比拟固定的模仿类游戏。这类游戏次要是通过模仿咱们生存的世界,让你在虚构的环境里经营或建设一些像医院、商店类的场景。要充分利用本人的智慧去努力实现游戏中建设和经营这些场景的要求,即SIM(simulation)类游戏,如《模仿人生》、《模拟城市》、《过山车大亨》和养成类游戏(TCG,如《足球经理世界》,还有以造就和教育游戏对象为目标的养成类游戏和即时策略类游戏,也都是策略类游戏的倒退和分支,如《零波丽育成打算》等)也归到了SLG下。 冒险类游戏 冒险游戏集中于摸索未知、解决谜题等情节化和探索性的互动,冒险游戏还强调故事线索的挖掘,次要考验玩家的观察力和剖析能力。 冒险游戏(Adventure Game)是电子游戏中的一种。冒险游戏游戏集中于摸索未知、解决谜题等情节化和探索性的互动,强调故事线索的挖掘,次要考验玩家的观察力和剖析能力。冒险游戏有时候很象角色扮演游戏(Role-Playing Game),但与角色扮演游戏不同的是,冒险游戏的特色是故事情节往往是以实现一个工作或解开某些迷题的模式呈现的,而且在游戏过程中刻意强调谜题的重要性。 冒险游戏个别分为文字类型的冒险游戏和动作类型的冒险游戏,文字类冒险游戏侧重于利用文字或图像的谜题来考验玩家,动作类则依附带有提醒或机关的2D、3D场景来实现。相同点是两种游戏都具备“摸索”这一特色,现在如日中天的动作冒险游戏和恋爱文字冒险游戏都具备“摸索”这一因素。能够说,“摸索”是冒险游戏的外围。 除了文字和动作两种辨别形式,冒险游戏也有解密和动作两种辨别形式。尽管两种分类形式都含有“动作”,但并非是同一意思。和解谜绝对的动作是指摸索时谜题和战斗两局部占得比重;而文字和动作的绝对,仅仅指摸索时是用肢体摸索较多还是文字摸索较多。 分类 文字冒险文字冒险游戏(Text adventure)又可称为交互式小说(Interactive fiction),是传统的冒险游戏类型。个别为解谜因素。因为动作冒险游戏的衰亡,老一代文字冒险游戏曾经败落。新兴的文字冒险游戏个别含有恋爱成分,这使得文字冒险游戏能够始终延续下去。视觉小说视觉小说(Visual novel),是新兴的冒险游戏类型。视觉小说相似于简化的文字冒险游戏,视觉小说很少有选项,然而却有丰盛的对话和图像。玩家只须要循序渐进的观看视觉小说即可,顾名思义,就是带有大量图像的小说。不过这种将游戏倒退回漫画的办法受到推动游戏倒退人士的拥护。动作冒险动作冒险游戏(Action Adventure Game,简称AAG)是过关式动作游戏3D化后的产物——他们也含有过关、解谜的因素。但因为画面的提高,从单纯的下指令后退,变为须要在关卡里利用机关或口头技巧进行后退的形式。动作类游戏 动作游戏(Action Game)是一种狭义上以“动作”作为游戏次要表现形式的游戏即可算作动作游戏的游戏类型。它强调玩家的反馈能力和手眼的配合。以游戏机为主、电脑为辅。动作游戏的剧情个别比较简单,次要是通过相熟操作技巧就能够进行游戏。这类游戏个别比拟有刺激性,情节缓和,声光效果丰盛,操作简略。动作游戏也蕴含“射击游戏”和“格斗游戏”。 分类 射击游戏射击游戏(Shooting Game,简称为STG)。带有很显著的动作游戏特点,因为要管制的角色和物体根本处于静止状态。而且“射击”自身也是动作的一种。概括下来,没有纯然的射击游戏,因为射击必须要通过一种动作形式来出现它的“射击”。格斗游戏格斗游戏(Fighting Game,简称为FTG)。这类的游戏具备显著的动作游戏特色,并且很好分辨。画面通常是玩家两边面对站立并互相作战,应用搏斗技巧使击败对手来获取胜利。游戏反抗形式 PVEPVE,指玩家对战环境(Player VS Environment),即在游戏中玩家挑战游戏程序所管制的NPC怪物和BOSS。PVE有时候又被称作PVC(Player Vs Computer)。 PVPPVP,指玩家对战玩家(Player versus player),即玩家相互利用游戏资源攻打而造成的互动竞技。 游戏市场的热点为了可能正确找到当今游戏市场的热点,我在手机上找到了游戏市场当日下载量的排名,和近日热搜量的排名,如下所示: 首先看当日下载量的排行,能够看到网游也就是PVP模式下的游戏更受玩家们的青睐。其中阴阳师是策略类的游戏,射雕群侠转和火影忍者等都是动作类的游戏,能够看出现在热点在于策略和动作的游戏。 再看热搜榜单上的游戏,能够发现下面的游戏很多都是休闲益智的单机游戏。大多数的游戏能够归结为超休闲类游戏,也就是操作极为简略,能够利用碎片化的工夫就能够进行的游戏。我认为次要的起因就是在手机上玩游戏时,并没有太富余的工夫,可能是你在工作学习中途的放松工夫,这样的碎片化的工夫更适宜玩一些休闲类的游戏,如果有工夫的话,就会抉择在PC端打游戏了那样的体验会更好。 总的来说,当今手机游戏市场的热点还是超休闲类的单机游戏,和一些策略,动作类的网游。

October 3, 2020 · 1 min · jiezi

关于unity3d:离散仿真引擎基础井字棋

离散仿真引擎根底--井字棋简答题解释 游戏对象(GameObjects) 和 资源(Assets)的区别与分割。 解答: 游戏对象(GameObjects),游戏程序空间中的事物,可能是 Empty(空,最有用的事物)、2D、3D、光线、摄像机等游戏资源(Assets),结构游戏对象、装璜游戏对象、配置游戏的物体和数据。即序列化的或存储格局的游戏对象或数据游戏对象指的是创立进去的对象,以及初始化时的灯光和相机。而游戏资源能够是创立的游戏对象,也能够是从内部导入的图像。 二者也是有分割的,咱们将游戏对象拖入进游戏资源中,便成为了一个游戏资源;当咱们将游戏资源实例化之后便成为了游戏对象 下载几个游戏案例,别离总结资源、对象组织的构造(指资源的目录组织构造与游戏对象树的层次结构) 解答: 在 unity hub 中的学习目录中有很多游戏样例进行学习和下载,我抉择了其中的两款进行剖析。 通过 unity 关上后能够查看到它的 Assets 目录如下所示: 由图中能够看到Assets目录的构造,是采纳的属性构造,父文件夹蕴含多个子文件夹,且雷同或者相似的文件保留在同一个文件夹中,每个子文件夹,也有若干个子文件。能够依据这样的层次结构失去论断,资源文件夹将属性类似的资源放在同一个文件夹中。 找到该项目标场景BlankScene关上后,能够看到对象的层次结构,不难看出有多个对象有本人的子对象,这些子对象又具备本人的子对象。父对象由他们的子对象组成起来。所有对象以树形模式组织起来。 又下载了几个游戏案例,发现其对象的层次结构与Assets的层次结构与下面的案例相似,这里就不开展阐明了,间接将他们的构造截图放在上面: 游戏介绍:![在这里插入图片形容](https://img-blog.csdnimg.cn/20200921205417641.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQzMjY3Nzcz,size_16,color_FFFFFF,t_70#pic_center)- Assets的构造如下所示:![](https://img-blog.csdnimg.cn/2020092120515657.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQzMjY3Nzcz,size_16,color_FFFFFF,t_70#pic_center)- 对象的层次结构如下所示:![](https://img-blog.csdnimg.cn/2020092120523657.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQzMjY3Nzcz,size_16,color_FFFFFF,t_70#pic_center)编写一个代码,应用 debug 语句来验证 MonoBehaviour 根本行为或事件触发的条件 根本行为包含 Awake() Start() Update() FixedUpdate() LateUpdate()罕用事件包含 OnGUI() OnDisable() OnEnable()解答: 首先增加一个C#代码的资源,验证的代码内容如下所示: using System.Collections;using System.Collections.Generic;using UnityEngine;public class Test : MonoBehaviour{ // Start is called before the first frame update void Start() { Debug.Log("Start"); } // Update is called once per frame void Update() { Debug.Log("Update"); } void FixedUpdate() { Debug.Log("FixedUpdate"); } void LateUpdate() { Debug.Log("LateUpdate"); } void Awake() { Debug.Log("Awake"); } void OnGUI() { Debug.Log("OnGUI"); } void OnDisable() { Debug.Log("OnDisable"); } void OnEnable() { Debug.Log("OnEnable"); }}而后关上保留,在unity中点击play进行运行,失去的后果如下图所示: ...

October 3, 2020 · 2 min · jiezi

关于unity3d:游戏对象与图像基础动作管理器

游戏对象与图像根底--动作管理器自学资源构造类型构造类型(“structure type”或“struct type”)是一种可封装数据和相干性能的值类型。 应用 struct关键字定义构造类型: public struct Coords{ public Coords(double x, double y) { X = x; Y = y; } public double X { get; } public double Y { get; } public override string ToString() => $"({X}, {Y})";}能够应用 readonly 修饰符来申明构造类型不可变: public readonly struct Coords能够在构造类型的申明中应用 ref 修饰符。 ref 构造类型的实例在堆栈上调配,并且不能本义到托管堆. public ref struct CustomRef枚举类型枚举类型 是由根底整型数值类型的一组命名常量定义的值类型。 若要定义枚举类型,请应用 enum关键字并指定枚举成员 的名称: enum Season{ Spring, Summer, Autumn, Winter}const 关键字const 在c#中的用法和别的语言一样,该关键字用来申明某个常量字段或是常量局部变量,该值是不能批改的 ...

October 3, 2020 · 4 min · jiezi

关于unity3d:空间与运动-MVC架构学习

空间与静止 -- MVC架构学习简答并用程序验证【倡议做】游戏对象静止的实质是什么?请用三种办法以上办法,实现物体的抛物线静止。(如,批改Transform属性,应用向量Vector3的办法…)写一个程序,实现一个残缺的太阳系, 其余星球围绕太阳的转速必须不一样,且不在一个法平面上。解答: 静止的实质就是扭转 transform 三个属性的(Position, Rotation, Scale)值,使物体进行静止抛物线静止实现的三种办法: 扭转物体 position 的办法,因为要实现抛物线静止,咱们晓得在unity的界面中,垂直方向的扭转也就是对y轴进行扭转,依据抛物线的公式 $y=v_0t+\frac{1}{2}at^2$,抛物线是向下静止就能够在公式中增加负号,即可实现物体的想下静止 using System.Collections;using System.Collections.Generic;using UnityEngine;public class NewBehaviourScript : MonoBehaviour { public float vx = 0.5f; // x轴方向上的速度 public float v0 = 0; // y轴方向上的初始速度 const float a = 9.8f; //加速度a // Start is called before the first frame update void Start() { } // Update is called once per frame void Update() { this.transform.position += new Vector3(vx * Time.deltaTime, (float)(-v0 * Time.deltaTime - 0.5 * a * (Time.deltaTime) * (Time.deltaTime)), 0); v0 += a * Time.deltaTime; // 每一帧扭转的时候v0的速度是不一样的 }}应用transform的translate函数,此函数使得物体的position挪动相应的地位,具体的公式还是抛物线的公式:$y=v_0t+\frac{1}{2}at^2$ using System.Collections; using System.Collections.Generic; using UnityEngine; public class NewBehaviourScript : MonoBehaviour { public float vx = 0.5f; // x轴方向上的速度 public float v0 = 0; // y轴方向上的初始速度 const float a = 9.8f; //加速度a // Start is called before the first frame update void Start() { } // Update is called once per frame void Update() { this.transform.Translate(new Vector3(vx * Time.deltaTime, (float)(-v0 * Time.deltaTime - 0.5 * a * (Time.deltaTime) * (Time.deltaTime)), 0)); v0 += a * Time.deltaTime; } }transform中能够调用一个函数 SetPositionAndRotation,此函数能够设置物体的position和rotation,rotation能够不须要设置,position设置的数值和下面基本一致,然而此时须要额定设置工夫的变动,以及,初始物体的高度也就是y值 using System.Collections;using System.Collections.Generic;using UnityEngine;public class NewBehaviourScript : MonoBehaviour{ public float vx = 0.5f; // x轴方向上的速度 const float a = 9.8f; //加速度a public float t = 0; public float y = 10.0f; // 初始y的地位 // Start is called before the first frame update void Start() { } // Update is called once per frame void Update() { this.transform.SetPositionAndRotation(new Vector3(vx * t, y - (float)(0.5 * a * t * t), 10), this.transform.rotation); t += Time.deltaTime; }}做太阳系,首先从老师给的网址太阳系贴图,将所有行星的图片都拖到桌面,而后再拖入unity中,即可在assets中应用,而后将这些图片拖到大小不一的球星就够,就能够造成各大行星 ...

October 3, 2020 · 11 min · jiezi

Lets-Hackathon-索尼黑客松召集令做这条gai最酷的极客

致程序员:从触屏时代进入感应时代,Future-Close at hand。ToF技术目前在VR游戏,AR音乐等场景中实现了应用,期待更多极客加入我们,共同走进感应时代。追求极致体验和更多乐趣,不论在游戏,短视频领域,还是在教育,电商,医疗等行业,让我们一起创造更多可能性。我们邀请您加入本次ToF黑客松,一起感应未来。 **1. 什么是ToF?**这是一场基于索尼最新ToF技术,搭载索尼 SDK的手机应用编程大赛。ToF是飞行时间(Time of Flight)技术的缩写,传感器发出红外光,通过计算光线发射和反射时间差来换算被拍摄景物的距离,以产生深度信息,将物体的三维轮廓以不同颜色代表不同距离的地形图方式呈现出来。 **2. ToF的应用领域**人类正在从触屏时代进入感应时代。随着5G时代的到来,传感器的技术革新,未来的各种操作体验将变得更加酷炫。索尼的ToF技术已经被应用到VR游戏、AR音乐、VR教育等一系列的场景中。提供给个人更多乐趣和便利,也提供给社会更多便利和安全。同时ToF技术也有被运用到在健身、短视频、电商、医疗、导航等领域。ToF应用场景演示视频 **3. 王者荣耀重磅加入**自活动发起以来,大赛收到了行业多方关注,王者荣耀正式加入本次黑客松,作为赛事合作方,特别授权本次黑客松大赛对王者热门英雄模型素材的使用,其中包括12个热门英雄的模型动画音效素材,及王者荣耀主要场景、建筑、野怪、兵线和背景音乐。比赛中,参赛者可以利用这些极具人气的王者英雄素材进行创意创作,相信很多王者荣耀的游戏迷已经跃跃欲试了!本次大赛的应用领域包括:王者荣耀素材主题、游戏、电商、医疗健康、社交、教育、导航和其他(请各位选手在报名时选择对应的应用领域)。选择王者荣耀素材主题的参赛团队,在开发期间,可使用比赛专用开发机调用相关王者荣耀的十二种热门英雄模型素材,结合索尼ToF技术,VR/AR方向的制作,实现创新,可尝试1V1、多人对战、音乐类和与英雄有强烈情感交互等方向,成果不仅仅局限于游戏。 各位Unity3D,游戏,AR/VR大佬们,48小时极限编程邀请你加入!在这里你可以:接触到索尼最新未公开的ToF科技,可以利用极具人气的王者英雄素材进行创意创作,赢取10万现金大奖,更有获得索尼或王者荣耀工作/合作的机会! 点击报名链接进行报名或者扫描下图二维码进行报名

June 28, 2019 · 1 min · jiezi

如何通过ShareSDK的-Unity3D快速接入AndroidiOS分享与授权

Unity3D是由Unity Technologies开发的一个让玩家轻松创建诸如三维视频游戏、建筑可视化、实时三维动画等类型互动内容的多平台的综合型游戏开发工具,是一个全面整合的专业游戏引擎;在游戏中使用分享功能能够有效的帮助游戏运营推广,通过分享回流来提高APP安装量。ShareSDK的Unity3D插件可以帮助开发者快速实现分享与授权功能。 一、应用注册 获取appkey,操作步骤可参考:《Mob开发者后台使用指南》 二、快速集成 下载ShareSDK的Unity3D工具类,双击或导入ShareSDK.unitypackage导入相关文件。注意该操作可能会覆盖您原来已经存在的文件。 挂接ShareSDK脚本并配置平台信息 选择好需要挂接的GameObject(例如Main Camera),在右侧栏中点击Add Component,选择Share SDK 进行挂接。挂接后会发现提供了当前支持的平台和及其配置信息。可以直接在此处修改你所需要的平台的配置信息。需要注意的是当前的编译环境是Android还是iOS,其字段名称是不同的哦! Android编译配置关键文件:mainTemplate.gradle和proguard-user.txt Unity2017及以上版本,在Build Settings > Player Settings下面,有两个开关,新建项目的话打开这两个开关就可以在Plugins>Android生成对应的两个文件;由于这两个文件ShareSDK都有直接提供,只需导入.unitypackage就好,Unity检测到已经存在这两个文件,自动会更新为勾选状态; Build的时候有一个Build System选项,此选项默认选择的Internal,切记要改成选择里面的gradle选项(重要)图中所示的mainTemplate.gradle文件,即为集成的核心文件,使用编辑器打开此文件,要点内容如下: 此处为区分Unity5.6和Unity2017 gradle插件版本的地方,开发时用到哪个版本就使用哪个,若使用到其他Unity版本,请随意选择一个,然后build,编译的时候会报错的,Console控制台信息报错时会提示插件版本是多少,根据提示修改成需要的版本就好(只修改后面的数字,比如:2.3.0或者2.1.0) buildscript{ repositories { jcenter() } dependencies { classpath 'com.android.tools.build:gradle:2.3.0'//Unity2017 //classpath'com.android.tools.build:gradle:2.1.0'//Unity5.6 // 注册MobSDK classpath 'com.mob.sdk:MobSDK:+' } }此处为配置签名文件和签名文件的别名和密码(正式发布apk需要的签名文件),可以写绝对路径,也可以写相对路径,相对路径使用”..”跳出一层目录,跳出多层则连续拼接 signingConfigs { release { keyAlias 'demokey.keystore' keyPassword '123456' storeFile file('F:\\Unitydemo(CJY)\\MobPushForUnity\\Assets\\Plugins\\Android\\demokey.keystore') storePassword '123456' } }此处为混淆文件的配置,也就是MobPush提供的proguard-user.txt文件,此文件内容不需要更改,按照提供的即可,如自己代码需要额外增加混淆逻辑,可自行增加混淆规则,如果是Unity2017以下版本,请把注释的代码调换一下即可;(minifyEnabled属性为是否开启代码混淆:true为开启混淆,false为关闭) buildTypes { release { minifyEnabled true// 是否混淆 //shrinkResources false//是否去除无效的资源文件 proguardFilesgetDefaultProguardFile('proguard-android.txt'), 'proguard-user.txt'//Unity2017及以上 //proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-unity.txt' //Unity2017以下 signingConfig signingConfigs.release } ...

June 17, 2019 · 3 min · jiezi

Unity-模型命名规范和导入设置

模型命名规范1.模型文件命名:模型名@动画名这样命名 Unity导入后会自动把模型中的Animation命名为动画名 2.网格和动画分离:一个带网格不带动画的模型文件和其余带动画不带网格的模型文件因为可以共用同一个网格和骨骼,分离网格和模型以后 减小了体积和内存 优化了性能同时也方便单独修改动画 模型挂载点设置1.骨骼上标明特殊点:需要做动画的美工标记特殊点 程序好使用例如:武器、装备、饰品的挂载点 技能特效的释放点 特殊点的属性上设置一个特殊图标 这样更直观 方便查找和修改 空点是隐藏的 不好找 如果相同功能的点有多个 建议加下标01、02、03 以示区分 模型设置优化1.主模型Model选项:(1)Scale Factor: 模型比例同一角色的模型 一定要设置一样的比例不同美工或不同时间做的同一角色模型 做之前统一规范和单位 非常重要如果产生大小比例不一致的情况 程序这面难以使用和修改 增加极大工作量 隐患很多 容易出BUG 别入这个坑 (2)Mesh Compressin: 网格压缩启用压缩后 体积会变小 加载会变慢 同时模型上的贴图位置会有一些细微的移动官方说明:压缩网格在构建的游戏中节省了空间,但更多的压缩会在顶点数据中引入更多的工件。 (3)Read/Write Enabled:当你不需要获取网格数据或动态修改网格形状时,请设为false 会减小内存 官方说明:网格顶点和索引可以从脚本访问吗?使网格可读将在内存中保存它的两个副本,一个用于呈现,一个用于系统内存中的脚本访问。将可读设置为false可以节省内存。在三个轴上缩放不同数量的网格(即不均匀缩放)需要网格具有可读性,以便正确照明。在Unity编辑器中,当不处于播放模式时,总是允许访问。 (4)Import Cameras:设为false (5)Import Lights:设为false (5)Import Hierarchy:设为true 不启用该选项时 很可能导致动画根节点不对 产生以下问题: ➀动画控制了角色的位置、角度和比例 导致角色有动画时 无法移动 ➁主模型和动画模型根节点名称不一致 动画模型无法使用主模型的骨骼 2.主模型Rig选项:(1)Avatar Defination:Create From This Model 3.主模型Animation选项:(1)Import Animation:false 主模型不导入动画 3.主模型Materials选项:(1)Import Materials:建议false 主模型和动画模型均不导入材质 请单独创建材质 单独使用 (趟过坑 不建议true) ...

May 28, 2019 · 1 min · jiezi

Unity-3D-的-Shader-运行时状态及渲染模式问题

Unity 中的 Shader 有四种渲染模式,分别是: ——Opaque(不透明)——Cutout(镂空)——Fade(隐现)——Transparent(透明)之前我遇到一个需求,需要给特定的游戏物体添加一个冰冻的效果,但是给我的 Shader 是一个完全冰冻的 Shader,而且无法通过参数调整它的颜色值。之后我的同事告诉我可以通过修改渲染模式更改物体本身的Alpha值实现,所以第一步我寻找了网上关于修改运行时 Shader 渲染模式的代码,如下。http://www.voidcn.com/article... 然后就是简单的代码操作,如下。 //获取目标身上的渲染组件 var renderer = GetComponentsInChildren<Renderer>(); // 建立一个冰冻数组 第二个数组元素是事先找好的冰冻特效 Material[] frostMatetials = new Material[2] { renderer.material, frostEffect }; //添加冰冻特效到人物身上的数组中 renderer.materials = frostMatetials; //实例化一个渲染模式变量 var fadeMode = SetMaterialRenderingMode.RenderingMode.Fade; //根据网上的方法更改你的 Shader 渲染模式为 Fade SetMaterialRenderingMode.SetMaterialRenderingModeMethod( renderer.materials[0],fadeMode);由于 Color 的 Alpha 值是只读的不能修改,但是 Color 是可以修改的,所以要获取目标物体 Color 的 RGB 值,然后实例一个 Color 用构造函数更改为你想要的 Alpha 值。如下: Color currentcolor03 = new Color { a = 0.8f, r = renderer.materials[0].color.r, g = renderer.materials[0].color.g, b = renderer.materials[0].color.b }; //替换目标 Color 属性就可以实现了其实这个方法不是很好,主要是因为所给的 Shader 不能修改属性值,后来我拿到了可以更改属性值的Shader,事情就变得简单了许多。 ...

April 29, 2019 · 1 min · jiezi

在 Unity 多人游戏中实现语音对话

我们曾经不止一次为大家分享过游戏中的实时音视频,例如怎么实现游戏中的听声辨位、狼人杀游戏中的语音聊天挑战等。基本上,都是从技术原理和 Agora SDK 出发来分享的。这次我们换一个角度。我们将从 Unity 开发者的角度分享一下,在 Unity 中如何给自己的多人在线游戏增加实时语音通话功能。我们在这里利用了 Unity 上流行的 “Tanks!!! asset reference” 坦克游戏作为多人在线游戏作为基础,相信很多人都不会陌生。大家可以在 Unity Asset Store 中搜到它。然后,我们会利用 Unity Asset Store 中的 Agora Voice SDK 为它增加多人语音聊天功能。在开始前,你需要做以下准备:安装 Unity 并注册 Unity 账号了解如果在 Unity 中创建 iOS、Android 项目一款跨移动平台多玩家的 Unity 游戏(本文中我们选择的是 Tanks)了解 C# 和 Unity 脚本注册一个 Agora 开发者账户至少两个移动设备(如果有一个 iOS 设备,一个 Android 设备就再理想不过了)安装 Xcode新建 Unity 项目我们默认大家都是用过 Unity 的开发者,但是为了照顾更多的人。我们还是要从头讲起。当然,开始的操作步骤很简单,所以我们会尽量以图片来说明。首先,打开 Unity 后,让我们先创建一个新的项目。如果你之前已经下载过 Tanks!!! ,那么我们点击页面旁边的“Add Asset Package”按钮,选择添加它即可。如果你还未下载过 Tanks!!! 那么可以在 Unity Store 中下载它。在将 Tanks!!! 参考项目部署到手机之前,还有几步需要做。首先,我们需要在 Unity Dashboard 中,为这个项目开启 Unity Live Mode。该设置的路径是:project → Multiplayer → Unet Config。尽管 Tanks!!! 只支持最多四个玩家4,但我们在将“Max Player per room”设置为6。图:这个界面说明 Unity Live Mode 已经开启Building for iOS现在我们已经准备好来创建 iOS 版本了。打开 Build Setting,将系统平台切换到 iOS,然后 Build。在切换系统平台后,请记得更新 Bundle Identifier(如下图所示)。图:创建了一个“Build”文件夹用于储存 iOS 项目图:Build 完成让我们打开 Unity-iPhone.xcodeproj,sign 并让它在测试设备上运行。现在我们已经完成了 iOS 项目的创建。接下来我们要创建 Android 项目了。Building for AndroidAndroid 项目相比 iOS 来讲要更简单一些。因为 Unity 可以直接创建、sign 和部署运行,无需借助 Android Studio。我默认大家已经将 Unity 与 Android SDK 文件夹关联起来了。现在我们要打开 Build Setting,然后将系统平台切换到 Android。在我们创建并运行之前,我们还需要对代码做出一些简单的调整。我们只需要注释掉几行代码,加一个简单的返回声明,再替换一个文件。背景信息:Tanks!!! Android 包含了 Everyplay 插件,用以实现游戏屏幕录制和分享。问题是,Everyplay 在2018年十月停止了服务,而插件仍然存在一些未解决的问题,如果我们不对其进行处理会导致编译失败。首先,我们要纠正一下 Everyplay 插件 build.gradle 文件中的语法错误。该文件的路径是:Plugins → Android → everyplay → build.gradle。现在,我们打开了 gradle 文件,全选所有代码,然后将下方的代码替换上去。Tanks!!! 团队在 Github 上更新了代码,但是不知道为什么并没能更新到插件中。// UNITY EXPORT COMPATIBLEapply plugin: ‘com.android.library’repositories { mavenCentral()}buildscript { repositories { mavenCentral() } dependencies { classpath ‘com.android.tools.build:gradle:1.0.0’ }}dependencies { compile fileTree(dir: ’libs’, include: [’*.jar’])}android { compileSdkVersion 23 buildToolsVersion “25.0.3” defaultPublishConfig “release” defaultConfig { versionCode 1600 versionName “1.6.0” minSdkVersion 16 } buildTypes { debug { debuggable true minifyEnabled false } release { debuggable false minifyEnabled true proguardFile getDefaultProguardFile(‘proguard-android.txt’) proguardFile ‘proguard-project.txt’ } } sourceSets { main { manifest.srcFile ‘AndroidManifest.xml’ java.srcDirs = [‘src’] aidl.srcDirs = [‘src’] renderscript.srcDirs = [‘src’] res.srcDirs = [‘res’] jniLibs.srcDirs = [’libs’] } } lintOptions { abortOnError false }}最后我们要做的修改就是关闭 Everyplay。你可能想问:为什么我们要关闭 Everyplay 呢?因为当插件初始化时会导致 Android 应用崩溃。我发现最快速的方法就是在 EveryPlaySettings.cs 文件中更新几行代码(该文件的路径:Assets → Plugins → EveryPlay → Scripts),如此一来,每当 Everyplay 视图检测自身是否处于开启状态时,我们都会给它返回“false”。public class EveryplaySettings : ScriptableObject{ public string clientId; public string clientSecret; public string redirectURI = “https://m.everyplay.com/auth"; public bool iosSupportEnabled; public bool tvosSupportEnabled; public bool androidSupportEnabled; public bool standaloneSupportEnabled; public bool testButtonsEnabled; public bool earlyInitializerEnabled = true; public bool IsEnabled { get { return false; } }#if UNITY_EDITOR public bool IsBuildTargetEnabled { get { return false; } }#endif public bool IsValid { get { return false; } }}现在我们已经准备好 Build 了。在 Unity 中打开 Build Settings,选择 Android 平台,然后按下“Switch Platform”按钮。随后,在 Player Settings 中为 Android App 修改 bundle id。在这里,我使用的是 com.agora.tanks.voicedemo。集成语音聊天功能接下来,我们要利用 Unity 中的 Agora voice SDK for Unity 来给跨平台项目增加语音聊天功能了。我们打开 Unity Asset Store ,搜索 Agora Voice SDK for Unity。当插件页面完成加载后,点击“Download”开始下载。下载完成后,选择“Import”,将它集成到你的项目中。我们需要创建一个脚本来让游戏与 Agora Voice SDK 进行交互。我们在项目中新建一个 C# 文件(AgoraInterface.cs),然后在 Visual Studio 中打开它。在这个脚本中有两个很重要的变量:static IRtcEngine mRtcEngine;public static string appId = “Your Agora AppId Here”;先要将“Your Agora AppId Here” 替换成 App ID,我们可在登录 Agora.io ,进入 Agora Dashboard 获取。mRtcEngine是静态的,这样在OnUpdate 调用的时候,才不会丢失。由于游戏中的其它脚本可能会引用 App ID,所以它是public static。考虑到节省时间,我已经将AgoraInterface.cs的代码写好了(如下所示)。大家可以直接使用,避免重复造车轮。在这里简单解释一下代码。首先,我们在开头有一些逻辑,用于 check/requset Android Permission。然后我们用 App ID 初始化 Agora RTC Engine,然后我们附加了一些事件回调,这部分很简单易懂。mRtcEngine.OnJoinChannelSuccess表示用户已经成功加入指定频道。最后一个重要功能就是update,当启用了 Agora RTC Engine 时,我们想要调用引擎的.Pull()方法,它对于插件是否能运行起来很关键。using System;using System.Collections;using System.Collections.Generic;using UnityEngine;using UnityEngine.UI;using UnityEngine.SceneManagement;using agora_gaming_rtc;#if(UNITY_2018_3_OR_NEWER)using UnityEngine.Android;#endifpublic class AgoraInterface : MonoBehaviour{ static IRtcEngine mRtcEngine; // PLEASE KEEP THIS App ID IN SAFE PLACE // Get your own App ID at https://dashboard.agora.io/ // After you entered the App ID, remove ## outside of Your App ID public static string appId = “Your Agora AppId Here”; void Awake() { QualitySettings.vSyncCount = 0; Application.targetFrameRate = 30; } // Start is called before the first frame update void Start() {#if (UNITY_2018_3_OR_NEWER) if (Permission.HasUserAuthorizedPermission(Permission.Microphone)) { } else { Permission.RequestUserPermission(Permission.Microphone); }#endif mRtcEngine = IRtcEngine.GetEngine(appId); Debug.Log(“Version : " + IRtcEngine.GetSdkVersion()); mRtcEngine.OnJoinChannelSuccess += (string channelName, uint uid, int elapsed) => { string joinSuccessMessage = string.Format(“joinChannel callback uid: {0}, channel: {1}, version: {2}”, uid, channelName, IRtcEngine.GetSdkVersion()); Debug.Log(joinSuccessMessage); }; mRtcEngine.OnLeaveChannel += (RtcStats stats) => { string leaveChannelMessage = string.Format(“onLeaveChannel callback duration {0}, tx: {1}, rx: {2}, tx kbps: {3}, rx kbps: {4}”, stats.duration, stats.txBytes, stats.rxBytes, stats.txKBitRate, stats.rxKBitRate); Debug.Log(leaveChannelMessage); }; mRtcEngine.OnUserJoined += (uint uid, int elapsed) => { string userJoinedMessage = string.Format(“onUserJoined callback uid {0} {1}”, uid, elapsed); Debug.Log(userJoinedMessage); }; mRtcEngine.OnUserOffline += (uint uid, USER_OFFLINE_REASON reason) => { string userOfflineMessage = string.Format(“onUserOffline callback uid {0} {1}”, uid, reason); Debug.Log(userOfflineMessage); }; mRtcEngine.OnVolumeIndication += (AudioVolumeInfo[] speakers, int speakerNumber, int totalVolume) => { if (speakerNumber == 0 || speakers == null) { Debug.Log(string.Format(“onVolumeIndication only local {0}”, totalVolume)); } for (int idx = 0; idx < speakerNumber; idx++) { string volumeIndicationMessage = string.Format("{0} onVolumeIndication {1} {2}”, speakerNumber, speakers[idx].uid, speakers[idx].volume); Debug.Log(volumeIndicationMessage); } }; mRtcEngine.OnUserMuted += (uint uid, bool muted) => { string userMutedMessage = string.Format(“onUserMuted callback uid {0} {1}”, uid, muted); Debug.Log(userMutedMessage); }; mRtcEngine.OnWarning += (int warn, string msg) => { string description = IRtcEngine.GetErrorDescription(warn); string warningMessage = string.Format(“onWarning callback {0} {1} {2}”, warn, msg, description); Debug.Log(warningMessage); }; mRtcEngine.OnError += (int error, string msg) => { string description = IRtcEngine.GetErrorDescription(error); string errorMessage = string.Format(“onError callback {0} {1} {2}”, error, msg, description); Debug.Log(errorMessage); }; mRtcEngine.OnRtcStats += (RtcStats stats) => { string rtcStatsMessage = string.Format(“onRtcStats callback duration {0}, tx: {1}, rx: {2}, tx kbps: {3}, rx kbps: {4}, tx(a) kbps: {5}, rx(a) kbps: {6} users {7}”, stats.duration, stats.txBytes, stats.rxBytes, stats.txKBitRate, stats.rxKBitRate, stats.txAudioKBitRate, stats.rxAudioKBitRate, stats.users); Debug.Log(rtcStatsMessage); int lengthOfMixingFile = mRtcEngine.GetAudioMixingDuration(); int currentTs = mRtcEngine.GetAudioMixingCurrentPosition(); string mixingMessage = string.Format(“Mixing File Meta {0}, {1}”, lengthOfMixingFile, currentTs); Debug.Log(mixingMessage); }; mRtcEngine.OnAudioRouteChanged += (AUDIO_ROUTE route) => { string routeMessage = string.Format(“onAudioRouteChanged {0}”, route); Debug.Log(routeMessage); }; mRtcEngine.OnRequestToken += () => { string requestKeyMessage = string.Format(“OnRequestToken”); Debug.Log(requestKeyMessage); }; mRtcEngine.OnConnectionInterrupted += () => { string interruptedMessage = string.Format(“OnConnectionInterrupted”); Debug.Log(interruptedMessage); }; mRtcEngine.OnConnectionLost += () => { string lostMessage = string.Format(“OnConnectionLost”); Debug.Log(lostMessage); }; mRtcEngine.SetLogFilter(LOG_FILTER.INFO); // mRtcEngine.setLogFile(“path_to_file_unity.log”); mRtcEngine.SetChannelProfile(CHANNEL_PROFILE.GAME_FREE_MODE); // mRtcEngine.SetChannelProfile (CHANNEL_PROFILE.GAME_COMMAND_MODE); // mRtcEngine.SetClientRole (CLIENT_ROLE.BROADCASTER); } // Update is called once per frame void Update () { if (mRtcEngine != null) { mRtcEngine.Poll (); } }}注意,以上代码可复用于所有 Unity 项目。离开频道如果你曾经使用过 Agora SDK,你可能注意到了,这里没有加入频道和离开频道。让我们先从“离开频道”开始动手,创建一个新的 C# 脚本LeaveHandler.cs,我们需要在用户返回到主菜单的时候调用 theleaveHandler。最简单的方法就是在 LobbyScene 打开后,为特定游戏对象开启该方法。using System.Collections;using System.Collections.Generic;using UnityEngine;using agora_gaming_rtc;public class LeaveHandler : MonoBehaviour{ // Start is called before the first frame update void OnEnable() { // Agora.io Implimentation IRtcEngine mRtcEngine = IRtcEngine.GetEngine(AgoraInterfaceScript.appId); // Get a reference to the Engine if (mRtcEngine != null) { Debug.Log(“Leaving Channel”); mRtcEngine.LeaveChannel();// leave the channel } }}在这里,我们要找的游戏对象是 LeftSubPanel (如下图,MainPanel → MenuUI → LeftSubPanel )。Tanks!!! 中有两种方法加入多人游戏,一种是创建新游戏,另一种是加入游戏。所以有两个地方,我们需要增加“加入频道”的命令。让我们先找到 UI Script Asset 文件夹(该文件夹路径:Assets → Scripts → UI),然后打开CreateGame.cs文件。在第61行,你会找到游戏用于匹配玩家的方法,在这里我们可以加入一些逻辑用于加入频道。首先我们要做的就是应用 Agora SDK 库。using agora_gaming_rtc;在StartMatchmakingGame()的第78行,我们需要加入一些逻辑来获取正在运行中的Agora RTC Engine,然后将“用户输入的内容”作为频道名称(m_MatchNameInput.text)。private void StartMatchmakingGame(){ GameSettings settings = GameSettings.s_Instance; settings.SetMapIndex(m_MapSelect.currentIndex); settings.SetModeIndex(m_ModeSelect.currentIndex); m_MenuUi.ShowConnectingModal(false); Debug.Log(GetGameName()); m_NetManager.StartMatchmakingGame(GetGameName(), (success, matchInfo) => { if (!success) { m_MenuUi.ShowInfoPopup(“Failed to create game.”, null); } else { m_MenuUi.HideInfoPopup(); m_MenuUi.ShowLobbyPanel(); // Agora.io Implimentation var channelName = m_MatchNameInput.text; // testing –> prod use: m_MatchNameInput.text IRtcEngine mRtcEngine = IRtcEngine.GetEngine(AgoraInterfaceScript.appId); // Get a reference to the Engine mRtcEngine.JoinChannel(channelName, “extra”, 0); // join the channel with given match name Debug.Log(“joining channel:” + channelName); } });}StartMatchmakingGame()包含了加入频道现在我们需要打开LobbyServerEntry.cs(Assets → Scripts → UI),然后加入一些逻辑,以实现让用户可以通过“Find a Game”来加入其他人的房间。在 Visual Studio 打开 LobbyServerEntry.cs,然后找到第63行,这里有一个 JoinMatch()。我们在第80行增加几行代码。private void JoinMatch(NetworkID networkId, String matchName){ MainMenuUI menuUi = MainMenuUI.s_Instance; menuUi.ShowConnectingModal(true); m_NetManager.JoinMatchmakingGame(networkId, (success, matchInfo) => { //Failure flow if (!success) { menuUi.ShowInfoPopup(“Failed to join game.”, null); } //Success flow else { menuUi.HideInfoPopup(); menuUi.ShowInfoPopup(“Entering lobby…”); m_NetManager.gameModeUpdated += menuUi.ShowLobbyPanelForConnection; // Agora.io Implimentation var channelName = matchName; // testing –> prod use: matchName IRtcEngine mRtcEngine = IRtcEngine.GetEngine(AgoraInterfaceScript.appId); // Get a reference to the Engine mRtcEngine.JoinChannel(channelName, “extra”, 0); // join the channel with given match name // testing string joinChannelMessage = string.Format(“joining channel: {0}”, channelName); Debug.Log(joinChannelMessage); } } );}完成了!现在我们已经完成了Agora SDK 的集成,并且已经准备好进行 iOS 端和 Android 端的 Build 与测试。我们可以参照上述内容中的方法来进行 Building 与部署。为了便于大家参考,我已经将这份 Tutorial 中的脚本上传了一份到 Github:https://github.com/digitallys…如果你遇到 Agora SDK API 调用问题,可以参考我们的官方文档(docs.agora.io),也欢迎在 RTC 开发者社区 的 Agora 版块与我们的工程师和更多同行交流、分享。 ...

April 4, 2019 · 6 min · jiezi

WebAssembly + Forge实战 - 整合Forge AR/VR ToolKit + Unity场景至前端框架

在浏览器环境下,解释运行JavaScript脚本实现高阶功能早已是家常便饭,然而,Web前端日新月异的需求已逐渐无法完全依赖JavaScript实现。幸运的是,打破瓶颈的新技术已逐渐成熟,它就是WebAssembly。什么是WebAssemblyWebAssembly是一项神奇的技术,简而言之就是一种底层的类汇编语言,其编译后的二进制模块wasm可在浏览器中运行以接近原生的性能运行CC++、C#、Java、GO、PHP、Rust等等语言的代码!自2015年颁布、2017年初正式发布最小功能版本以来,WebAssembly迅速开始盛行,并已得到主流浏览器的广泛支持,详细支持情况可以参见下图或MDN:图片描述图片描述(数据采于2019-01-25)需要强调的是:WebAssembly并不旨在取代JavaScript或任何现有的H5/ES6技术,而是与他们共存 - 我们耳熟能详的WebGL、Web Audio等组件都是WebAssembly模块在浏览器端的运行时,在浏览器端实现所需功能图片描述优势与异同那么问题来了 - WebAssembly究竟和asm.js、Dart等类似技术有何不同?我们早已可以通过Emscripten编译asm.js在浏览器中跑c/c++了,为什么还需要WebAssembly呢?相比之下,WebAssembly主要具备以下优势:WebAssembly模块不论在加载速度和性能上都有明显优势 - 它以二进制码的形式在浏览器中原生运行,无需像asm.js那样将原始语言编译成JavaScript,远超JavaScript引擎解释脚本的运行速度,即便首屈一指的Chrome V8有JIT加持也无济于事。WebAssembly并不是基于现有组建的扩展,而是一个Web开发新特性/标准,它有独立的路线图,不断有新特性加入进来。不受asm.js等技术在AOT等层面的限制,特性拓展潜力极大,应用场景广泛,详见底部延伸阅读部分的介绍。编译与运行那么如此神奇的技术究竟如何编译运行?当下最主流编译器可谓就是Emscripten了,广泛应用于原始语言->LLVM中间码->JavaScipt(asm.js)的编译。当然在WebAssembly全面企稳的今天,直接将原始语言编译成WebAssembly(wasm)也不在话下。较新版本的Emscripten支持跳过LLVM中间码->asm.js->wasm的过度,直接编译wasm,以c语言为例可通过如下命令直接编译:# WASM=1:仅生成wasm模块(默认为LLVM中间码),SIDE_MODULE=1:仅编译用户代码,而不包含printf、memalloc等函数./emcc hello-world.c -O3 -s WASM=1 -s SIDE_MODULE=1 -o hello-world.html编译生成的结果包括:hello-world.wasm: wasm模块二进制码hello-world.html: 展示页面hello-world.js: 读取wasm模块的JavaScript其中编译生成的hello-world.js是帮助我们在页面中调用加载wasm模块的脚本,我们也可结合Fetch API在自己的代码进行加载: fetch(‘path/to/wasm’) .then(response => response.arrayBuffer()) \将wasm文件响应转为二进制数组 .then(bits => WebAssembly.compile(bits)) \编译模块 .then(module => { return new WebAssembly.Instance(module) }); \生成模块实例可通过自带的emrun工具在指定浏览器中运行编译结果,或直接托管在Web服务器上:emrun –browser /path/to/browser/executable hello-world.html实战Unity+WebAssembly接下来我们就进入今天的实战:将经由Autodesk Forge Model Derivative服务轻量化的模型,通过Forge AR/VR Toolkit导入Unity场景,结合C#/JSLIB脚本与Unity插件,编译为WebAssembly,并集成至我们的前端框架中!图片描述参考该教程,为Unity3D项目配置好Forge AR/VR Toolkit将轻量化后的模型导入至Unity场景,如图所示填入模型的URN和从Forge服务端获取的Access Token图片描述需注意将.NET运行时版本调整为4.5以便支持TLS 1.2图片描述完成场景的建模与开发,本例结合Cinemachine的Freelook Camera插件与简单的c#脚本实现由键鼠操控的场景漫游。Cinemachine是一套强大的Unity相机管理工具,可利用其路径(Path)路点(Waypoint)等特性(并结合Timeline)轻松制作强大的预制路线漫游等效果。通过较新Unity3D(2017/5.6+)直接将场景编译为WebAssembly,设定发布目标平台为WebGL,并在发布设定中将连接器目标设为WebAssembly,开始Build编译:图片描述图片描述编译结果包括:html:展示页面Build目录:<项目名>.json(包括运行所需的参数与设置)、UnityLoad.js(浏览器加载wasm所需的脚本)、<项目名>..unityweb(发布设定中指定格式的压缩包,包含wasm模块与场景资源等)Template:展示页面依赖与前端框架整合浏览展示页面确认实际效果无误后,将Build目录导入前端项目的静态资源路径(如./src/assets)接下来将分别介绍针对Vue、React、Angular框架与无框架的整合React推荐使用react-unity-webgl加载Unity WebAssembly:npm install vue-unity-webgl在React组建中调用import Unity, { UnityContent } from “react-unity-webgl”;class App extends Component { unityContent:UnityContent = new UnityContent( “Build/forge_sample.json”, \引用编译结果,将所有编译结果置于相同路径下 “Build/UnityLoader.js” \并确保浏览器会话可以http协议访问 ); \… render() { \… <Unity unityContent={this.unityContent} /> }}与Unity中的对象通讯 this.unityContent.send( “Unity对象名称”, “C#或JSLIB脚本函数名称”, 1 \参数值 );在Unity脚本中与JavaScript通讯: [DllImport("__Internal")] private static extern void EventName (int arg); public void CallAnEvent (int arg) { EventName(arg); }在Unity中创建JSLIB脚本(如Assets/Plugins/WebGL/forge-sample.jslib)注入事件:mergeInto(LibraryManager.library, { EventName: function(arg) { ReactUnityWebGL.EventName(arg); }});在前端监听该事件 this.unityContent.on(“EventName”, arg => { \…- 同理我们可以在前端监听Unity的生命周期事件:public class NewBehaviourScript : MonoBehaviour {... [DllImport("__Internal")] private static extern void EventName (); void OnSceneLoaded (Scene scene, LoadSceneMode mode) { EventName();}... }##Vue- 推荐使用vue-unity-webgl组件加载Unity WebAssembly:npm install vue-unity-webgl- 在Vue组件中调用<template> <div>/…/<unity src=“Build/forge_sample.json” unityLoader=“Build/UnityLoader.js”></unity> \引用编译结果,将所有编译结果置于相同路径下,并确保浏览器会话可以http协议访问/…*/</div></template><script>import Unity from ‘vue-unity-webgl’...export default { components: { Unity } ...}<script>##Angular与无框架- 对于适用于Angular的Unity组件库,我们只找到了ng-unity,但在实测中出现报错,似乎是由于其内置的UnityLoader.js与我们的模块并不兼容(该库不能引用外置Loader),因此我们结合了无框架的引用方式来做示范- 在页面中引用编译生成的UnityLoad.js <script language=“JavaScript” src=“assets/Build/UnityLoader.js”></script>- 组件页面中加入容器元素 / app.component.html/ <div id=‘unityContainer’></div>- 在组件中载入模块\app.component.tsdeclare var UnityLoader: any; \声明UnityLoader为任意类export class AppComponent implements AfterViewInit{ private unityInstance: any; ... ngAfterViewInit(){(<any>window).UnityLoader = UnityLoader; \将UnityLoader对象暴露为窗体具柄this.unityInstance = UnityLoader.instantiate(‘unityContainer’, ‘./assets/Build/forge_sample.json’); \引用编译结果,将所有编译结果置于相同路径下,并确保浏览器会话可以http协议访问}sendMessage(objectName: string, functionName: any, argumentValue: any) {this.unityInstance.SendMessage(objectName, functionName, argumentValue); \与Unity对象通讯} ...}- 运行结果如下![图片描述][9]#调试与优化编译后的wasm是二进制的,可以通过编译工具(如WABT、Binaryen等)生成或转换为WebAssembly Text (wat) Format - 人类可读的类汇编代码:(module (func $i (import “imports” “imported_func”) (param i32)) (func (export “exported_func”)i32.const 42call $i))在浏览器中也可以查看wat,并断点调试![图片描述][10]##优化考量- 将wasm等依赖在服务器端压缩,加速网络传输,以Node后台为例: https://blog.csdn.net/github_38140984/article/details/83011150- 编译时的优化(如使用WebGL2.0,.NET4.5等),参考: https://docs.unity3d.com/Manual/class-PlayerSettingsWebGL.html#Optimization- 使用WebAssembly JIT:https://webassembly.org/docs/jit-library/#延伸阅读- Forge AR/VR介绍:https://segmentfault.com/a/1190000013672044- Unity Cinemachine插件学习笔记: https://blog.csdn.net/l773575310/article/details/78070808- Emscripten-WebAssembly专栏:https://segmentfault.com/blog/yunhuangbeiqing- WebAssembly入门: https://www.jianshu.com/p/bff8aa23fe4d- WebAssembly入门到入门:https://blog.csdn.net/m549393829/article/details/81839822- WebAssembly应用案例: https://blog.csdn.net/frf0lw4/article/details/79267457 [1]: /img/bVbnQqb [2]: /img/bVbnQqh [3]: /img/bVbnQqi [4]: /img/bVbnQqp [5]: /img/bVbnQqw [6]: /img/bVbnQqA [7]: /img/bVbnQqs [8]: /img/bVbnQqt [9]: /img/bVbnQqu ...

January 27, 2019 · 2 min · jiezi

对话 CTO | 喜茶也有 CTO?听陈霈霖讲讲茶饮中的技术甜度

· 本文内容为图文形式· 栏目:对话CTO· 阅读时间:18分钟· 阅读建议:深度长文,请配合文末福利慢慢食用· 掌握难度:★★★★☆专栏导语这个时代的价值,就是技术领袖们的价值。人人都说,一个时代结束了。但是却并没有人能说清,在这之后的新时代是个什么样子。脱缰狂奔了大约十年的光景,移动互联网的「黄金岁月」终于不再。「下半场」、「后移动互联网」、「未来十年最好的一年」等耸人听闻又模棱两可的话语接踵而至,告别了流量就是一切的时代,我们对于技术之于产业的思考从未像今天这样懵懂又尖锐。互联网商业世界走到了历史钉下的交界之地,而技术从业者所在的技术环境和所持的技术思维都必须直面巨大的升级和变化。旧时代里,技术是通往每一个问题解决的利器工具,问题的答案会带来滚滚而至的流量,而流量就成为了价值或泡沫的源泉。而今天,新时代的起跑线上,写满了「数据」的字样。单纯流量的价值开始褪色,化作更加不言自明的基础设施,而如何发掘数据价值、增强数据应用,则成为了时代的主色调——这也成为了技术从业者需要思考的另一个新问题。技术焦点的交接和转移,同样带来了技术开发环境的变化。在技术之外的一切,几乎都将决定技术本身价值的释放速度和力度,产品观、设计观、管理观、运营观,都将成为这个时代技术人员必备的利刃和铠甲——而 CTO,作为这个商业世界中当仁不让的技术领袖群体,则将最先肩负并践行起这一切的考验与责任。时代赋予了这些技术领袖们又一个新机遇,随之而来的新要求也落在了 CTO 们的肩头:他们要更加深谙产品逻辑并关注技术落地,他们也必须前所未有地去拓展自己对于商业本质的认知并作出决绝的选择,他们需要创造出那些在先前的历史当中无法摘取复制的基础方法论,以去披肩植入、开疆扩土。于是,在这个时候,极客公园相信我们需要一起对于 CTO 这个群体作出新的理解和认知,因为他们的价值将决定未来商业世界的价值,也将决定这个新时代的价值。这就是极客公园开设最新专栏「对话 CTO」的原因,我们会以新时代技术从业者的视角,来聊一聊这群人的成长和领悟。本专栏由ONES 的创始人&CEO 王颖奇作为特邀访谈者。王颖奇曾参与金山软件 WPS、金山毒霸等大型软件的核心开发工作;2011 年创立了正点科技,旗下产品正点闹钟、正点日历在全球用户过亿;2014 年,王颖奇在知名美元基金晨兴资本任 EIR,并以个人身份参与十余家公司的管理咨询工作;2015 年,王颖奇创立 ONES,致力于提供企业级研发管理解决方案。摘要喜茶还需要 CTO 么?这恐怕是大多数人认识陈霈霖后的第一反应。几乎每一次,他的技术布道都是从这个问题的肯定回答中开始。这是一位从商学院毕业的 CTO,自学编程的历史可以追溯到他八岁的时候。后来机缘巧合加入金山软件,担任游戏架构师,是著名 Unity3D 游戏开发框架 KSFramework 的创始人,拥有相关的专利。2017 年,陈霈霖走上喜茶 CTO 的位置。从那一刻起,他的技术理解和技术能力,帮助这家全中国炙手可热的新茶饮零售商解决了门店前漫长的排队和恼人的黄牛,也给每一杯的茶饮中调配进了技术的甜度。本期对话 CTO,我们请到了喜茶 CTO 陈霈霖来谈一谈他对于新零售领域的技术理解和技术人员投身产业互联网的能力基准线。数字管理+数字营销颖奇:霈霖好,感谢您接受《对话 CTO》访谈。喜茶是非常棒的一个新式茶饮品牌,很年轻和科技化。但是大家仍然很好奇喜茶为什么会有 CTO,能否先介绍一下您是怎么加入喜茶的呢?陈霈霖:好的,先定义一下我在喜茶的 CTO 职位,我负责了数字化产品策划、技术研发、网络运营、IT 管理四个方面的工作,不是大家一般了解的首席「技术」官。我之前做过社交应用,当时在思考的问题是如何把这个产品在传统行业落地。那时我遇到了喜茶的创始人兼 CEO 聂云宸,一起聊了聊后发现双方观念很契合,就来了喜茶。当时我只知道有个概念叫「新零售」,还搞不懂是干嘛的。宏观来说,我坚信技术和数字化在未来是会抹平整个世界的。每一个公司其实到最后终局都是技术和数据驱动的公司,它们都是数字化公司。既然方向是对的,先出发就对了。颖奇:喜茶也在使用 ONES 的产品。但我每次在跟其他人介绍喜茶是我们的客户时,大家都会问,喜茶为什么要有研发?您是否能跟大家介绍一下,在喜茶的产品研发和经营过程中,技术本身是什么样的位置,起到了怎样的作用呢?陈霈霖:首先,我把企业数字化总结成一个重要的法则叫「数字化三支柱」,包括「数字营销」、「数字管理」、「数字力量」,利用数字技术做营销,利用数字技术做管理,利用数字技术积累数据形成公司资产。零售企业发展的过程中有大量的管理和日常重复性事务工作,随着门店的数量增加,工作量和边际成本是指数级递增的,这就需要技术研发 IT 系统去提效。国外比较大的品牌,如沃尔玛、麦当劳、肯德基、星巴克在我们看来都是餐饮品牌或者零售品牌,但本质他们是强技术驱动型公司。举个例子,亚马逊的第一任 CTO 是原来沃尔玛的 CTO,而沃尔玛在 80 年代就发射过卫星。发射卫星做什么呢?用来管理和监控全球的供应链。颖奇:所以这些零售型公司某种程度上来说也是 IT 公司。陈霈霖:对,我们去麦当劳里面仔细看一下,会发现麦当劳其实本质也是一个 IT 驱动的公司。所有门店的店员做什么呢?店员看屏幕干活,门店营运的核心大脑,就是他们的 IT 系统。通过 IT 系统把整个门店给串起来,精细化管理是通过 IT 进行支撑的。颖奇:那您觉得在中国,有哪些新零售企业在 IT 方面是标杆呢?陈霈霖:首先像我前面所说的,IT 数字化要做好,同时要在「数字营销」、「数字管理」、「数字力量」三个点上同时有所作为。放大来说,我们可以看看哪些产业的数字化已经是做得比较好的。例如,银行业通过很多年完成了从银票到完全的数字系统管理过程,是一个必须以技术驱动的产业,数字管理和数字力量都做得非常好,但是它在数字营销上没有做好,就给予了「互联网银行」一些发展空间。零售业的数字营销是非常先进的,比如说电商的本质就是在于把零售业的数字营销那条线做到极致,但更多零售业的数字管理程度还不够高,所以我是挺认同新零售的常见定义,「以消费者体验为中心的数据驱动的泛零售形态」,本质就是把数字营销、数字管理、数字力量有机结合,从而形成了新零售业态。这个角度看来,盒马鲜生我觉得确实能在 IT 里面起到标杆效应。颖奇:我的理解是「数字营销」更多是获客以及服务客户,「数字管理」实际上是个内化的管理行为,让企业内部的流程更加高效更加节省人力从而做出好的产品,是这样理解么?陈霈霖:对,为什么以往的数字管理在互联网时代没有凸显出来,因为互联网时代都是数字化的世界,管理没有那么复杂,或者说没有那么多人需要被管理。但是零售行业线下各个环节都是由人组成的,地域性比较强,这时候需要很大量的数字管理的技术来支撑。跨界理解+「弄脏双手」颖奇:您在做喜茶 CTO 的这么长时间里,有什么是通过「数字管理」或者「数字营销」的手段,使得喜茶得到了非常好的优化?陈霈霖:「喜茶 GO」是个比较有代表性的产品,外界来看是一个小程序。其实背后我们整个体系都打通了,从用户的营销到门店的管理营运等等,这些都有相关性。小程序只是它的用户端载体。通过一个小程序,让一家公司转变成一家数据公司,「喜茶 GO」在几个月之内就有几百万的用户了。老实说这出乎我意料,我一开始也没有想到原来线下流量来的那么多、那么快。颖奇:有了小程序,就可以像电商一样跟踪到用户的购买行为来优化产品和服务?陈霈霖:是的,在以往整个餐饮零售行业里面有个很大的缺点是你不知道用户是谁,也不知道复购率等等。现在我们复购率很清晰的留在那里了,而且这几个月翻了几倍。因为小程序的存在把经营数据给量化呈现出来了。颖奇:喜茶中的技术人员是如何组织分工的呢?陈霈霖:如前所说我认为数字化三支柱,分成数字营销、数字管理、数字力量,因此我们内部也分别对应 3 个部门,数字营销部、IT 管理部、产品研发部,产品研发部就是大家理解的技术研发中心。颖奇:感觉上这是一个非常大的工程,复杂的地方就是整个的体系搭建。在喜茶的研发团队里,您觉得什么样的人才会比较适合做新零售行业的研发?陈霈霖:是的,非常大,数字化对一家数字化公司而言是一个无处不在的全量大工程。人才方面,我觉得产业互联网核心在于产业认知,需要有对于产业的充分理解,知道整个业务如何去理解以及和不同的环节配合。从人的特质上,我最喜欢的是具有领导力、思辨力的人才,既能驱动事情前进,又能探索事物的本质。在这个行业里面,我认为技术的深度不是最重要的,能够跨界学习的软性能力则是非常重要的,思辨胜于经验。颖奇:您之前的哪些经历会让您对跨界的业务能力这么重视,并且您是怎么一步步跨界过来的呢?陈霈霖:最初我在大学读商学院金融系,当年我的梦想就是要做一个职业经理人,那时候看了很多管理、品牌营销的书籍。久而久之会发现好的营销、创意、产品都需要技术实现,然后自学编程。当时就帮企业做网站,帮学院做一些管理系统,后面因为机缘巧合去了金山软件,在金山里做游戏的技术架构。本质上我认为产业互联网更适合我的职业规划和过往经历的有机整合,就进入到这个行业。颖奇:之前的那些项目经验或者工作经验中,有哪些你所坚持的管理方法、管理理念吗?陈霈霖:我 2009 年的时候看过一本书,叫做《重来》(《Rework》),对我影响非常大。那本书的作者是几个年轻小伙,做一个项目管理软件(Basecamp),员工分布在世界各大洲,远程办公,然后一年可以几千万美元收入。我当时一想,啊这就是未来的世界。未来世界是什么?肯定是「工具驱动管理」。所以我是工具偏执狂,我这边有非常多的工具,文档的、项目管理的、沟通的、各种各样的一些效率工具,所以也选择了 ONES。高效的团队一定是通过工具去实施管理的,我看到很多西方企业其实已经跑完了,但中国还在萌芽阶段。颖奇:除了工具的使用以外,您还有哪些技巧或方法,能够使得产业和互联网的两类团队在一块融合起来往前冲?陈霈霖:我曾经思考过,为什么像国外咨询公司、顾问公司很专业很成熟,但是国内的公司经常会迷惑为什么要请一个外部的人来评估自己的业务呢,自己雇人不就好了。这就引出了一个观点叫做「外部视角」。有一本书叫做《突破现实的困境:趋势、禀赋与企业家的大战略》,作者是麦肯锡的几个合伙人,书中提到了这样的「外部视角」观点,我觉得很深刻。在公司的内部作出的决策和工作方法,其实都属于内部视角。有时候内部思想很难说明白,大家「屁股决定脑袋」嘛,其实很多事情在内部是很难推动的。然而,作为一个传统企业在转型中,面临的一个最大的困境就是认知不对称,这时候就有必要引入外部视角,因为外部视角是中立的。书中提到了「战略的人性面」,比如业务上报了一个数字,那个「数字」就是大家会站在自己的立场会发挥的,无可避免,就算是再厉害的人也会迫于无奈做出这种战略的人性面的一个考量。所以「外部视角」的引用,让跟你公司没有任何关系的人去从全局的客观角度看待业务,从而给出一个非常客观的数字,我觉得这也是外部咨询公司的一个核心价值。回到你刚刚那个问题,不同领域的人如何融合相处,或者如何让认知平衡?我认为光靠内部的力量是无法实现的,这里有人性的考量。想要做好融合,无非就是两个方法,第一,引入外部视角。第二,你在外部输出反哺局内。颖奇:有没有什么对传统行业的一些误解和想法,但进入到行业中之后发现「噢,他们当年本质上是对的,其实这就是这种行业应该坚持去做的东西,而不是说咱们互联网的人觉得可能改了就好了」的经历么?陈霈霖:你这个问题问得好。总结几个互联网人「下海」的一个通常经历吧。第一个阶段「带着优越感」,觉得线下的东西特别容易;第二个阶段是「对工作规划过于乐观」,觉得一个东西特别容易搞定;第三个阶段就是「信心被摧毁」,把最初的星辰大海重新收窄回一个点。一句话总结,就是「不知道自己不知道」。很多互联网人到最后发现,我们原以为很简单的事情,有的时候放在传统行业里是无法行得通的,越到后面就越不敢说话了。我总结了大家的经历,就是产业互联网是一个必须得「弄脏双手」的过程。互联网行业讲究的一个叫做单点突破,这个思维其实已经贯穿了我们的行为习惯。那实际上的情况是什么呢?在产业互联网,在一个庞大复杂的存量产业链条中,你不可能单点突破。我们可以理解,产业互联网本身就是「每一个职能部门的数字化」,这个产业里面有非常多的职能部门,都需要把它给数字化,你要单点突破是不可能的,不仅一个点都不能落下,更要很全面很细致的把它们全给做了,这就是产业互联网本质。我们也经历过各种各样的情况。比如说我们针对这一个自己开发出来的产品觉得很不错,我们做个工具在产业互联网里给全行业都覆盖了,但是这不太现实。因为产业互联网的过程必须得是一个又脏又累的过程,繁琐且复杂,每个人只会满足到这个行业里面的某一个点而已。颖奇:最后聊聊喜茶的大目标吧。CEO可能会有一个商业目标,那您作为CTO,在技术领域中怎么样帮助喜茶达到目标?您的大目标是什么?陈霈霖:我们喜茶互联网事业部的目标主要有三个:第一个是布道数字化,可以全面覆盖企业的经营管理,成为商业目标的一部分;第二个是要组建完整的数字化力量,可以形成企业的核心资产;第三,我希望我们能够成为产业互联网一个国际化的顶级标杆案例。颖奇:喜茶算是产业互联网里的一个拓荒者。陈霈霖:广义上对于行业来说,对的,是个拓荒者,所以看到不少人在模仿也挺感慨,因为这背后我完整地经历了看不见、看不起、看不懂的过程。但狭义上来看,我觉得并不算是拓荒者,因为很多东西都是在借鉴国内外不同行业的不同经验,我只是站在巨人的肩膀上。颖奇:喜茶现在已经是一家很棒的企业了。非常感谢您今天的分享。本文作者:王颖奇联系方式:wangyingqi@gmail.com ...

January 7, 2019 · 1 min · jiezi

几维安全:千锤百炼,锻造移动游戏安全防护黄金铠甲

在近期发布的《2018年上半年中国移动互联网行业发展分析报告》中提出,在上半年中国移动互联网关键字TOP1是“安全”,安全已成为中国移动互联网企业存亡生命线。作为平台,首先要保证输出内容的安全,其次要保证用户的人身财产安全及数据安全。安全,为立“身”之本。在过去二十多年中,伴随着移动互联网的发展,游戏行业经历很大的变化——不仅仅是从技术上的革新,游戏的实现能力更是有了飞跃的发展,但是在移动游戏逐渐成为大众休闲娱乐的主流方式的背后,其安全正受到网络黑产的巨大威胁。移动游戏发展迅猛,安全问题如影随形 据相关数据显示,截止到2018年3季度,全球移动互联网用户已超过30亿,欧美、东亚等区域渗透率近80%。从3季度基于移动互联网应用月新增占比分布数据看,游戏行业占比位居第二,且主流手机游戏应用MAU同比增长趋势明显。但是,随着硬件与开发技术的成熟相继发展成型,游戏行业安全问题也随之出现,外挂工具、系统功能漏洞、服务器宕机漏洞等问题频发,也将大幅影响游戏内平衡,使用户体验下降。可以说,无论是移动应用还是游戏,发生安全问题就如同打开“潘多拉魔盒”,不但可能危害用户切身利益,也同样会造成企业的损失。与此同时还会发生企业信誉危机,品牌口碑大幅下滑等一系列问题。在腾讯安全云鼎实验室于近日发布《2018年游戏行业安全监测报告及五大攻击趋势》的数据显示,目前游戏行业安全威胁主要包括账号类攻击、DDoS攻击、外挂和其他四大类。1. 帐号类攻击针对游戏行业的帐号类攻击,月均在数亿次/月,且持续平稳,具有长期持续性攻击的特征。(1)攻击类型分布在针对帐号的攻击中,大部分的帐号扫描其实也是为了撞库攻击做准备,少部分是基于历史密码的登录尝试。因此,在帐号安全侧,撞库相关攻击实际占据了80%以上的份额。2. DDoS 攻击 从2018年情况统计中,游戏行业仍为DDoS 攻击主要目标,其中移动 Web 游戏被攻击数量明显增加。从被攻击游戏分类看,端游与手游依然占比最大。3. 外挂2018年主要外挂集中在手游的吃鸡类游戏上,其中外挂热度排名前四的吃鸡类手游占据了超过60%的关注度,加上 PC 端的射击类游戏,射击类外挂已然占据了70%以上。4. 其他 其他攻击还包括主要集中在 App Store 平台的代充值类问题,比如:外币汇率差、黑卡和盗刷信用卡等。移动游戏行业发展,需与游戏安全比翼齐飞 移动游戏安全问题逐渐泛滥已经引起了政府监管部门的关注,政府监管部门已明显放慢了版号审批速度,实施网络游戏总量调控,同时也采取了一系列相应措施:2017年12月,中共中央宣传部、中央网信办、工业和信息化部、教育部、公安部、文化部、国家工商总局、国家新闻出版广电总局联合印发《关于严格规范网络游戏市场管理的意见》(以下简称《意见》),部署对网络游戏违法违规行为和不良内容进行集中整治。《意见》中明确提出:“网络游戏系统安全、用户信息安全问题较为突出,个人信息泄露、账号非法交易现象较为普遍。同时,管理体制机制与市场发展还不完全匹配,相关法律法规还不够健全,方式手段还不够完善,纠错惩戒不足以形成震慑。”2018年2月5日下午,浦东网安支队召开浦东地区游戏行业网络安全工作会,会议就目前网游行业发展所导致的文化内容缺失等突出问题为背景,向浦东地区的114家网络游戏企业下发《网络游戏企业基础排摸调研表》,并开展法律法规教育,要求各单位核实并上报本单位的信息安全问题。与此同时,全国很多监管部门也在加紧行动,全面排查,加紧规范整治。在2018年12月21日举行的中国游戏产业年会上,中宣部出版局有关人士表示:“首批送审游戏已经完成审核,正在抓紧核发版号”,说明暂停已久的移动游戏审批重新启动,移动游戏行业又将迎来新的春天。而未来,移动游戏的健康发展更需要安全系统的有力加持。移动游戏主要安全攻击分析移动游戏可分为单机游戏和网络游戏两大类,基于不同类别游戏特点进行分析:1.单机游戏这类游戏所有的数据基本都在本地,面临的分析主要有内购破解,二次打包,游戏修改器等威胁。因为数据基本都在本地,攻击者可以修改本地数据达到一些非法的目的,比如:修改生命值,增加金钱,修改伤害值等。还有一些抄袭者将游戏彻底分析,或者重新二次代码,只修改游戏里面的原有包名,和游戏人物角色ui和名称,可以快速开发一款同类产品,减少开发周期。还有就是直接盗用,修改支付链接,转换为自己的,并将付费额度修改为比正版更低的价格。2.网络游戏这类游戏主要的数据是和服务器进行交互,有些战斗数据计算可能在本地或者是服务器,应对本地计算的,建议放到服务器计算,这样安全性更高。主要的威胁有:外挂,私服,第三方抄袭等。外挂:可以通过分析游戏的核心数据,分析游戏的内部代码达到一些非法操作,比如脱机挂可以自动注册游戏,进行游戏通关操作、刷金币、刷等级等;还有通过外挂可以加速游戏运行,缩短游戏打斗。私服:这种情况是通过破解游戏和服务器的通信协议自建服务器,将游戏网络地址给为自建服务器地址。第三方抄袭:破解游戏后,分析游戏的数值数据、关卡配置等一系列的数据信息。若为网络数据则通过抓包等手段进行分析,开发者只需要修改ui等手段即可以快速出一款同类游戏,减少了策划等工作。造成安全问题的技术实现分析:1.内购破解:通过暴力破解方式,绕过/破解支付校验代码,支付框架、sdk破解,造成收入严重受损。2.修改内存通过内存注入、动态调试、内存dump等操作恶意篡改游戏内容,造成游戏平衡性下降。3.二次打包篡改游戏代码、更换游戏logo、皮肤、包名,篡改后的游戏,造成扣费、流量损耗、弹广告等等,造成公司名义受损。4.游戏修改器游戏修改器对几乎所有的游戏都会造成严重破坏,修改游戏属性值,严重破坏游戏平衡,付费环节变得没有任何作用,收入变低,用户兴趣低,用户量损失。5.核心技术、数据信息丢失通过破解方式,获取游戏核心代码,对公司自主产权造成严重损害,游戏数据信息丢失、玩家个人信息数据泄露。移动游戏安全解决方案解析 1.Java代码vmp加密对dex文件进行native指令化转化,并且以native方式还原到安卓内存中,即使使用dump手段dump出当前部分代码,也是经过native处理过的代码,不会还原成APP源代码。2.动态调试保护(1)防动态注入防注入保护,能防止APP运行时通过注入的方式获取APP隐私数据、使用hook等方式劫持APP的正常运行流程等。当加固后的APP检测到注入时,APP会自动退出运行。(2)防动态调试反调试机制能够拒绝调试工具的附加操作,阻止调试器对移动应用调试分析其业务逻辑代码,一旦被加固的程序检测到有如gdb等调试操作将自动退出运行。(3)防内存dump防内存dump保护,能有效阻止gdb dump等操作,同时因为代码采用函数体分离方式和native化保护,代码都是以单个函数还原到内存中,而内存中的代码也是经过native处理,及时dump出当前代码片段,也是经过native方式处理后的代码,不会还原成源代码。3.防二次打包对签名做完整性校验保护,一旦更改签名文件,程序将不会再次运行。4.So源码混淆对SO文件做加密和自定义加载处理,除此之外还会对SO文件中字符串加密和代码混淆处理,层层防止攻击者提取SO文件和对其二进制代码做反编译和反汇编处理。对Objective-C、C、C++编译后的Native代码进行代码混淆处理,被混淆过后的代码中存在多余代码、怪癖语法、冗余逻辑判断,冗余函数调用等难以阅读和理解的代码,结合字符串加密和反调试机制等功能,让攻击者无法反编译,从而有效的保护源代码安全。5.代码虚拟化保护采用基于LLVM编译器中间层实现的虚拟化编译器,可通过虚拟CPU解释器以及虚拟IR指令,将原始CPU指令进行加密转换处理为只能由虚拟解释器解释执行的虚拟指令,能够完全隐藏函数代码逻辑,以及函数及变量之间的依赖关系。6.其他安全建议iOS安全建议,为了防止在Android端无法分析出协议,但是可以通过iOS端分析的情况发生,建议iOS端也做安全加密操作,iOS端源码混淆功能与so文件源码混淆功能相同,字符串加密、代码结构逻辑混淆、指令替换、控制流平坦化,虚假控制流等。实例解构 几维安全通过长期研究开发,形成了专有技术KiwiVM虚拟化保护方案,实现CPU指令虚拟化,对手游的核心代码进行安全编译、生成受保护的安全模块,从而避免因破解造成的安全风险。以几维安全为某移动游戏企业提供的安全加固案例为例进行解构:1、基于公司现状进行安全风险分析,梳理出该公司的安全加固需求:(1)手游基于Unity3d引擎开发,核心DLL文件存在被逆向破解的风险;(2)不具备正版校验机制,伪冒、盗版手游影响正版手游的正常运营;(3)游戏修改器、脱机挂破坏游戏的公平性,付费用户逐渐流失。2、结合该公司的特点,拟定端到端的整体安全防护方案:3.以整体安全体系架构为基础,根据需求进行单产品或产品组合部署如:在该案例中提供《KiwiVM虚拟机》和《Unity3D手游加密》方案,保护企业核心代码,保障手游正常的运营与推广。(1)提供KiwiVM虚拟化服务KiwiVM是基于Clang编译器扩展实现的VM虚拟机编译器, 在编译时直接对指定的函数[代码]实施虚拟化处理。其加密过程不可逆,攻击者无法还原代码,分析核心业务逻辑。可帮助中大型企业在通信、支付、算法、核心技术等模块进行深度加密,避免因逆向破解问题造成的经济损失。(2)Unity3D手游加密服务Unity3D手游加固服务是在APP安全加固的基础之上,针对Unity3D手游,扩展了函数级[或整体级]的DLL文件加密功能,避免DLL文件被 .NET Reflector 等破解工具提取C#源代码。与DEX加密、防二次打包、内存保护、反调试、防系统加速挂等功能配合形成一套完整的Unity3D手游加密方案。登录移动安全管理平台即可使用。DLL函数级加密为企业版,其算法有几十种可供选择,同时对这些加密算法都有高强度的加密保护,攻击者无法通过Dump内存数据来窃取C#源代码。结语 移动游戏安全系统价值在于维护公平的游戏环境、保护玩家财产、提高用户体验感。千锤百炼,锻造移动游戏安全防护黄金铠甲,为企业树立可信品牌,使用户安心驰骋在手游疆场,助力游戏行业在移动互联网大发展浪潮中更蓬勃的发展。

December 28, 2018 · 1 min · jiezi