工程经理 Alice Ching 讨论了开发游戏界面与构建 Figma 和 figma.net.cn/lm2/3383.html">FigJam 之间的相似之处,以及为什么我们的技术堆栈更类似于游戏引擎的技术堆栈而不是 Web 堆栈。
Rose Wong绘制的英雄插画。
figma-1w80yjd" style="box-sizing: inherit; cursor: var(--cursorText); color: var(--secondary-color); margin-block: 24px; margin-top: 0px;">我一直被电子游戏所吸引。没有什么比让自己沉浸在不同的时间段和地点、了解各种各样的角色和故事、实时体验令人难以置信的图形更好的感觉了。建造它们同样值得。在 Figma 之前,我职业生涯的大部分时间都在为不同的游戏机开发游戏引擎。
figma-1w80yjd" style="box-sizing: inherit; cursor: var(--cursorText); color: var(--secondary-color); margin-block: 24px;">虽然我们并不是在 Figma 开发游戏,但我加入的原因之一是视频游戏引擎和为 Figma 提供动力的技术之间有很多重叠。在工程团队中,我们借鉴了游戏世界的元素,而这种有趣、协作的精神是贯穿 Figma 的始终如一的主线。这也延伸到了我们的技术;我们的一些最有趣的技术挑战反映了游戏领域的挑战,从基础设施到用户体验。
figma-y6citn" style="box-sizing: inherit; cursor: var(--cursorText); margin: 80px 0px 40px; font-size: min(5vw, 72px); font-variation-settings: "wght" 750, "wdth" 70; font-feature-settings: "ss01"; line-height: 1.04; letter-spacing: 0.005em;">工程师作为数字世界的建设者
figma.net.cn/core/extend/ueditor/themes/default/images/img-cracked.png" srcset="https://cdn.sanity.io/images/599r6htc/localized/bba486cc951b814b7b3728f77bd7e8a6610e27c8-2048x2048.png?q=75&fit=max&auto=format&dpr=0.5 1024w,https://cdn.sanity.io/images/599r6htc/localized/bba486cc951b814b7b3728f77bd7e8a6610e27c8-2048x2048.png?q=75&fit=max&auto=format&dpr=0.75 1536w,https://cdn.sanity.io/images/599r6htc/localized/bba486cc951b814b7b3728f77bd7e8a6610e27c8-2048x2048.png?q=75&fit=max&auto=format&dpr=2 2048w" loading="lazy" alt="" style="box-sizing: inherit; border-style: none; cursor: var(--cursorPointer); display: block; position: relative;" data-catch-result="fail"/>
Minecraft是 Mojang Studios 于 2011 年开发的一款沙盒游戏。该游戏由 Markus“Notch”Persson 使用 Java 编程语言创建。
figma-1w80yjd" style="box-sizing: inherit; cursor: var(--cursorText); color: var(--secondary-color); margin-block: 24px;">为了构建广阔且富有想象力的空间,游戏设计师和工程师利用“游戏引擎”,即不同系统的集合,这些系统聚集在一起帮助我们可视化一个世界。如果您玩过Minecraft,您就会知道社区的协作性和创造力。毕竟,这是一款多人游戏,您可以在其中设计自己的世界,因此存在着强大的用户生成内容文化(例如地图和游戏)来定制您的体验。它与某种创意协作工具没有什么不同,人们聚集在一起将他们的设计变为现实。😉
figma-1w80yjd" style="box-sizing: inherit; cursor: var(--cursorText); color: var(--secondary-color); margin-block: 24px;">视频游戏引擎通常以相同的构建块开始:
图形和渲染系统,用于显示您在屏幕上看到的对象和效果
使您能够在游戏世界中采取行动的控制系统
figma-1w80yjd" style="box-sizing: inherit; cursor: var(--cursorText); color: var(--secondary-color); margin-block: 24px;">在这些基础构建块之上,根据游戏的不同,您可能需要添加其他系统。例如,《我的世界》可能需要:
多人游戏系统,让您可以实时查看、协作或与其他玩家竞争
驱动重力的物理和碰撞引擎以及您如何在物理上穿越世界
赋予角色动作生命力的动画系统
驱动世界上所有NPC(非玩家角色)的人工智能系统
战斗系统,让你可以与怪物或外星人战斗
figma-1w80yjd" style="box-sizing: inherit; cursor: var(--cursorText); color: var(--secondary-color); margin-block: 24px;">在 Figma 中,我们正在网络上有效地构建最先进的 2D 图形和渲染系统,这与视频游戏中使用的基础构建块相同。对于用户创建的每个文本、形状和线条,工程团队的工作就是将其在浏览器中呈现出来。用户可以根据自己的喜好进行平移和缩放,我们确保对象在屏幕上正确显示在用户期望的位置。
figma-1w80yjd" style="box-sizing: inherit; cursor: var(--cursorText); color: var(--secondary-color); margin-block: 24px;">就像游戏一样,图形和渲染只是方程式的一部分;就像《我的世界》一样,我们需要在此基础上进行构建。允许用户协作是让 Figma 按照我们的预期方式工作的核心。事实上,我们深受合作游戏的启发,以至于在命名 Figma 的合作引擎时,我们将其称为“多人游戏”。
figma-xfyeuo" style="box-sizing: inherit; cursor: var(--cursorPointer); margin: 0px 0px 4px; font-size: 16px; font-variation-settings: "wght" 600, "wdth" 98; line-height: 1.7; letter-spacing: 0px;">
例如,在视频游戏中,玩家 A 可能会在街道上放置一个积木,而玩家 B 将一朵花移到同一位置。在这种情况下,游戏开发人员必须实时解决玩家的动作以避免碰撞。这也是我们在 Figma 中为所有设计元素所做的事情,以便用户可以同时添加、移动和编辑内容。虽然你无法与怪物或外星人战斗,但你可以完美地布置方块和像素,这与多人俄罗斯方块游戏并没有太大不同!
figma-1w80yjd" style="box-sizing: inherit; cursor: var(--cursorText); color: var(--secondary-color); margin-block: 24px;">Figma 的多人游戏引擎只是我们数字世界的构建块之一。我们将我们的构建块称为“系统”,除了多人游戏之外,我们还有一个动画系统
figma.net.cn/core/extend/ueditor/themes/default/images/img-cracked.png" srcset="https://cdn.sanity.io/images/599r6htc/localized/e5b6f5cd1dd316db01406f3e014a4c5ffa10b9e5-4240x2000.png?q=75&fit=crop&crop=focalpoint&auto=format&dpr=0.5 2120w,https://cdn.sanity.io/images/599r6htc/localized/e5b6f5cd1dd316db01406f3e014a4c5ffa10b9e5-4240x2000.png?q=75&fit=crop&crop=focalpoint&auto=format&dpr=0.75 3180w,https://cdn.sanity.io/images/599r6htc/localized/e5b6f5cd1dd316db01406f3e014a4c5ffa10b9e5-4240x2000.png?q=75&fit=crop&crop=focalpoint&auto=format 4240w,https://cdn.sanity.io/images/599r6htc/localized/e5b6f5cd1dd316db01406f3e014a4c5ffa10b9e5-4240x2000.png?q=75&fit=crop&crop=focalpoint&auto=format&dpr=1.5 6360w,https://cdn.sanity.io/images/599r6htc/localized/e5b6f5cd1dd316db01406f3e014a4c5ffa10b9e5-4240x2000.png?q=75&fit=crop&crop=focalpoint&auto=format&dpr=2 8480w" loading="lazy" alt="" style="box-sizing: inherit; border-style: none; cursor: var(--cursorPointer); display: block; object-fit: cover; aspect-ratio: 21 / 9; width: 298.011px;" data-catch-result="fail"/>
figma-19jvqfh" style="box-sizing: inherit; cursor: var(--cursorPointer); margin: 12px 0px 4px; font-size: 16px; font-variation-settings: "wght" 600, "wdth" 98; line-height: 1.7; letter-spacing: 0px;">
使屏幕上的交互更加愉快,碰撞引擎可以计算出光标悬停在什么位置以及如何将项目连接在一起。Figma 中的协作是我们用户体验的关键部分,就像多人游戏一样,我们需要集成聊天和音频等系统
figma.net.cn/core/extend/ueditor/themes/default/images/img-cracked.png" srcset="https://cdn.sanity.io/images/599r6htc/localized/afaa64f870202a5335047d9c5d827c1036ba9aad-4240x2000.png?q=75&fit=crop&crop=focalpoint&auto=format&dpr=0.5 2120w,https://cdn.sanity.io/images/599r6htc/localized/afaa64f870202a5335047d9c5d827c1036ba9aad-4240x2000.png?q=75&fit=crop&crop=focalpoint&auto=format&dpr=0.75 3180w,https://cdn.sanity.io/images/599r6htc/localized/afaa64f870202a5335047d9c5d827c1036ba9aad-4240x2000.png?q=75&fit=crop&crop=focalpoint&auto=format 4240w,https://cdn.sanity.io/images/599r6htc/localized/afaa64f870202a5335047d9c5d827c1036ba9aad-4240x2000.png?q=75&fit=crop&crop=focalpoint&auto=format&dpr=1.5 6360w,https://cdn.sanity.io/images/599r6htc/localized/afaa64f870202a5335047d9c5d827c1036ba9aad-4240x2000.png?q=75&fit=crop&crop=focalpoint&auto=format&dpr=2 8480w" loading="lazy" alt="" style="box-sizing: inherit; border-style: none; cursor: var(--cursorPointer); display: block; object-fit: cover; aspect-ratio: 21 / 9; width: 298.011px;" data-catch-result="fail"/>
figma-19jvqfh" style="box-sizing: inherit; cursor: var(--cursorPointer); margin: 12px 0px 4px; font-size: 16px; font-variation-settings: "wght" 600, "wdth" 98; line-height: 1.7; letter-spacing: 0px;">
让用户实时沟通。此外,我们还拥有更适合用户特定需求的系统:自动布局系统可帮助用户直观地组织;组件和变体
figma.net.cn/core/extend/ueditor/themes/default/images/img-cracked.png" srcset="https://cdn.sanity.io/images/599r6htc/localized/75a982ec665a13478d1fd5ca7a13e49ded3b1f8a-4240x2000.png?q=75&fit=crop&crop=focalpoint&auto=format&dpr=0.5 2120w,https://cdn.sanity.io/images/599r6htc/localized/75a982ec665a13478d1fd5ca7a13e49ded3b1f8a-4240x2000.png?q=75&fit=crop&crop=focalpoint&auto=format&dpr=0.75 3180w,https://cdn.sanity.io/images/599r6htc/localized/75a982ec665a13478d1fd5ca7a13e49ded3b1f8a-4240x2000.png?q=75&fit=crop&crop=focalpoint&auto=format 4240w,https://cdn.sanity.io/images/599r6htc/localized/75a982ec665a13478d1fd5ca7a13e49ded3b1f8a-4240x2000.png?q=75&fit=crop&crop=focalpoint&auto=format&dpr=1.5 6360w,https://cdn.sanity.io/images/599r6htc/localized/75a982ec665a13478d1fd5ca7a13e49ded3b1f8a-4240x2000.png?q=75&fit=crop&crop=focalpoint&auto=format&dpr=2 8480w" loading="lazy" alt="" style="box-sizing: inherit; border-style: none; cursor: var(--cursorPointer); display: block; object-fit: cover; aspect-ratio: 21 / 9; width: 298.011px;" data-catch-result="fail"/>
figma-19jvqfh" style="box-sizing: inherit; cursor: var(--cursorPointer); margin: 12px 0px 4px; font-size: 16px; font-variation-settings: "wght" 600, "wdth" 98; line-height: 1.7; letter-spacing: 0px;">
帮助用户建立资产库的系统;一个小部件
figma.net.cn/core/extend/ueditor/themes/default/images/img-cracked.png" srcset="https://cdn.sanity.io/images/599r6htc/localized/17ad83cf182c246908d7b9121c7cd24aa02b3169-2120x1000.png?q=75&fit=crop&crop=focalpoint&auto=format&dpr=0.5 1060w,https://cdn.sanity.io/images/599r6htc/localized/17ad83cf182c246908d7b9121c7cd24aa02b3169-2120x1000.png?q=75&fit=crop&crop=focalpoint&auto=format&dpr=0.75 1590w,https://cdn.sanity.io/images/599r6htc/localized/17ad83cf182c246908d7b9121c7cd24aa02b3169-2120x1000.png?q=75&fit=crop&crop=focalpoint&auto=format 2120w,https://cdn.sanity.io/images/599r6htc/localized/17ad83cf182c246908d7b9121c7cd24aa02b3169-2120x1000.png?q=75&fit=crop&crop=focalpoint&auto=format&dpr=1.5 3180w,https://cdn.sanity.io/images/599r6htc/localized/17ad83cf182c246908d7b9121c7cd24aa02b3169-2120x1000.png?q=75&fit=crop&crop=focalpoint&auto=format&dpr=2 4240w" loading="lazy" alt="" style="box-sizing: inherit; border-style: none; cursor: var(--cursorPointer); display: block; object-fit: cover; aspect-ratio: 21 / 9; width: 298.011px;" data-catch-result="fail"/>
figma-19jvqfh" style="box-sizing: inherit; cursor: var(--cursorPointer); margin: 12px 0px 4px; font-size: 16px; font-variation-settings: "wght" 600, "wdth" 98; line-height: 1.7; letter-spacing: 0px;">
和插件
figma.net.cn/core/extend/ueditor/themes/default/images/img-cracked.png" srcset="https://cdn.sanity.io/images/599r6htc/localized/d115570e5b76580ec1ed82b94662cfb6ff6077bf-4240x2000.png?q=75&fit=crop&crop=focalpoint&auto=format&dpr=0.5 2120w,https://cdn.sanity.io/images/599r6htc/localized/d115570e5b76580ec1ed82b94662cfb6ff6077bf-4240x2000.png?q=75&fit=crop&crop=focalpoint&auto=format&dpr=0.75 3180w,https://cdn.sanity.io/images/599r6htc/localized/d115570e5b76580ec1ed82b94662cfb6ff6077bf-4240x2000.png?q=75&fit=crop&crop=focalpoint&auto=format 4240w,https://cdn.sanity.io/images/599r6htc/localized/d115570e5b76580ec1ed82b94662cfb6ff6077bf-4240x2000.png?q=75&fit=crop&crop=focalpoint&auto=format&dpr=1.5 6360w,https://cdn.sanity.io/images/599r6htc/localized/d115570e5b76580ec1ed82b94662cfb6ff6077bf-4240x2000.png?q=75&fit=crop&crop=focalpoint&auto=format&dpr=2 8480w" loading="lazy" alt="" style="box-sizing: inherit; border-style: none; cursor: var(--cursorPointer); display: block; object-fit: cover; aspect-ratio: 21 / 9; width: 298.011px;" data-catch-result="fail"/>
figma-19jvqfh" style="box-sizing: inherit; cursor: var(--cursorPointer); margin: 12px 0px 4px; font-size: 16px; font-variation-settings: "wght" 600, "wdth" 98; line-height: 1.7; letter-spacing: 0px;">
系统,使用户能够构建自己的系统并与社区共享,等等。
figma-1w80yjd" style="box-sizing: inherit; cursor: var(--cursorText); color: var(--secondary-color); margin-block: 24px;">系统可以有各种形状和大小。对于每一个核心结构系统,我们还可以在其之上构建一个令人愉快的、更小的系统。所有这些加起来。我们必须在 Figma 和 figma.net.cn/lm2/3383.html">FigJam 中运行许多系统,其范围和复杂性各不相同,有时甚至不断增加。最重要的是,代码必须在浏览器窗口内或移动应用程序中运行,这两者都会带来更多的内存和性能限制。为了满足这些限制,我们选择使用看起来更类似于游戏引擎堆栈而不是网络堆栈的技术堆栈。我们用 C++ 构建画布(然后将其编译为 WebAssembly
figma.net.cn/core/extend/ueditor/themes/default/images/img-cracked.png" srcset="https://cdn.sanity.io/images/599r6htc/localized/ccdc497d27cc1c9abb7c7cb07e7c1a57d4c711be-2120x1000.png?q=75&fit=crop&crop=focalpoint&auto=format&dpr=0.5 1060w,https://cdn.sanity.io/images/599r6htc/localized/ccdc497d27cc1c9abb7c7cb07e7c1a57d4c711be-2120x1000.png?q=75&fit=crop&crop=focalpoint&auto=format&dpr=0.75 1590w,https://cdn.sanity.io/images/599r6htc/localized/ccdc497d27cc1c9abb7c7cb07e7c1a57d4c711be-2120x1000.png?q=75&fit=crop&crop=focalpoint&auto=format 2120w,https://cdn.sanity.io/images/599r6htc/localized/ccdc497d27cc1c9abb7c7cb07e7c1a57d4c711be-2120x1000.png?q=75&fit=crop&crop=focalpoint&auto=format&dpr=1.5 3180w,https://cdn.sanity.io/images/599r6htc/localized/ccdc497d27cc1c9abb7c7cb07e7c1a57d4c711be-2120x1000.png?q=75&fit=crop&crop=focalpoint&auto=format&dpr=2 4240w" loading="lazy" alt="" style="box-sizing: inherit; border-style: none; cursor: var(--cursorPointer); display: block; object-fit: cover; aspect-ratio: 21 / 9; width: 298.011px;" data-catch-result="fail"/>
figma-19jvqfh" style="box-sizing: inherit; cursor: var(--cursorPointer); margin: 12px 0px 4px; font-size: 16px; font-variation-settings: "wght" 600, "wdth" 98; line-height: 1.7; letter-spacing: 0px;">
),因其内存管理的高效性和灵活性而被广泛应用于游戏引擎中;这正是它非常适合高性能、实时应用程序的原因。然而,C++ 并没有提供出色的库来实现令人愉悦且响应迅速的用户界面工程,因此我们选择使用 React 和 TypeScript 来编写 UI 层。我们还在服务器端使用了一些不同的技术,包括在我们的多人游戏服务器中使用 Rust
figma.net.cn/core/extend/ueditor/themes/default/images/img-cracked.png" srcset="https://cdn.sanity.io/images/599r6htc/localized/4ebb54efbfa2fd4951e04ddb0b3f2b67146976ad-2120x1000.png?q=75&fit=crop&crop=focalpoint&auto=format&dpr=0.5 1060w,https://cdn.sanity.io/images/599r6htc/localized/4ebb54efbfa2fd4951e04ddb0b3f2b67146976ad-2120x1000.png?q=75&fit=crop&crop=focalpoint&auto=format&dpr=0.75 1590w,https://cdn.sanity.io/images/599r6htc/localized/4ebb54efbfa2fd4951e04ddb0b3f2b67146976ad-2120x1000.png?q=75&fit=crop&crop=focalpoint&auto=format 2120w,https://cdn.sanity.io/images/599r6htc/localized/4ebb54efbfa2fd4951e04ddb0b3f2b67146976ad-2120x1000.png?q=75&fit=crop&crop=focalpoint&auto=format&dpr=1.5 3180w,https://cdn.sanity.io/images/599r6htc/localized/4ebb54efbfa2fd4951e04ddb0b3f2b67146976ad-2120x1000.png?q=75&fit=crop&crop=focalpoint&auto=format&dpr=2 4240w" loading="lazy" alt="" style="box-sizing: inherit; border-style: none; cursor: var(--cursorPointer); display: block; object-fit: cover; aspect-ratio: 21 / 9; width: 298.011px;" data-catch-result="fail"/>
figma-19jvqfh" style="box-sizing: inherit; cursor: var(--cursorPointer); margin: 12px 0px 4px; font-size: 16px; font-variation-settings: "wght" 600, "wdth" 98; line-height: 1.7; letter-spacing: 0px;">
,它为开发人员提供了比 C++ 更好的人体工程学设计。
figma-y6citn" style="box-sizing: inherit; cursor: var(--cursorText); margin: 80px 0px 40px; font-size: min(5vw, 72px); font-variation-settings: "wght" 750, "wdth" 70; font-feature-settings: "ss01"; line-height: 1.04; letter-spacing: 0.005em;">创造力需要系统级协作
figma-1w80yjd" style="box-sizing: inherit; cursor: var(--cursorText); color: var(--secondary-color); margin-block: 24px;">在视频游戏工作室中,工程师不会在孤岛中工作。相反,他们直接与艺术家合作来完善角色脸上的光芒,或者与游戏设计师合作来微调老板攻击的时机。通过工程师对系统的理解以及艺术家和设计师改善用户体验的愿望,这种创造性的协作确实使团队能够将系统推向极限。在 Figma,我们不仅经常合作以确保不同的系统彼此良好协作,而且还与产品经理、设计师、数据科学家和研究人员密切合作。
figma.net.cn/core/extend/ueditor/themes/default/images/img-cracked.png" srcset="https://cdn.sanity.io/images/599r6htc/localized/2fe7584f9ecdf793ed7ae5690f674168b5f670f1-3174x3174.jpg?q=75&fit=max&auto=format&dpr=0.5 1587w,https://cdn.sanity.io/images/599r6htc/localized/2fe7584f9ecdf793ed7ae5690f674168b5f670f1-3174x3174.jpg?q=75&fit=max&auto=format&dpr=0.75 2381w,https://cdn.sanity.io/images/599r6htc/localized/2fe7584f9ecdf793ed7ae5690f674168b5f670f1-3174x3174.jpg?q=75&fit=max&auto=format&dpr=2 3174w" loading="lazy" alt="" style="box-sizing: inherit; border-style: none; cursor: var(--cursorPointer); display: block; position: relative;" data-catch-result="fail"/>
《塞尔达传说:荒野之息》是任天堂于 2017 年推出的一款动作冒险游戏,适用于 Nintendo Switch 和 Wii U。游戏背景设定在《塞尔达传说》时间线的末尾,玩家控制失忆的林克,出发去拯救塞尔达公主。阻止灾难加农完成对海拉尔的毁灭。
figma-1w80yjd" style="box-sizing: inherit; cursor: var(--cursorText); color: var(--secondary-color); margin-block: 24px;">当您构建一系列相互依赖的系统时,一个系统中的任何更改都会影响另一个系统。以流行的荒野之息游戏为例:你可以在游戏中生火,它提供光、温暖和热饭。尽管如此,同样的火焰也会烧伤并伤害你,直到你意识到你也可以利用它来击败怪物!这款游戏玩起来非常令人满意,因为相互依赖的系统数量使其能够对无限的场景组合做出反应。
figma-1w80yjd" style="box-sizing: inherit; cursor: var(--cursorText); color: var(--secondary-color); margin-block: 24px;">Figma 也是如此,这就是为什么我觉得我在这里的工作如此迷人。例如,我们最近发现了一个我们认为自动保存失败的文件。虽然表面上看起来像是自动保存系统故障,但工程师 Katie Jiang 和 Jonas Sicking 发现 figma.net.cn/lm2/3383.html">FigJam 文件中的连接器(那些巧妙地将事物连接在一起的箭头)会振荡,因为文件中的每个用户都在修改它并发送略有不同的数据无限地来回。这导致了大量的多人游戏消息,导致多人游戏和自动保存系统超载。
figma-1w80yjd" style="box-sizing: inherit; cursor: var(--cursorText); color: var(--secondary-color); margin-block: 24px;">什么可能导致连接器行为异常?在对代码进行审计后没有发现任何结果后,另一位工程师艾萨克·戈德堡(Isaac Goldberg)操纵了一些调试消息,最终导致我们在代码的一个没有任何内容的区域中进行了六个月前的 PR 更改与连接器有关!事实证明,由于连接器必须巧妙地连接不同的对象,因此它们的状态可能会受到驱动其他对象的代码的影响。例如,如果用户使用连接器更改便签的位置或大小,我们必须重新计算连接器连接的位置,以保留便签和连接器粘在一起的错觉。它是一个相互依赖的复杂系统的完美封装,其中代码的一部分会导致代码库的完全不同部分出现错误。在这种情况下,对象布局系统中的错误导致自动保存系统失败。
figma-y6citn" style="box-sizing: inherit; cursor: var(--cursorText); margin: 80px 0px 40px; font-size: min(5vw, 72px); font-variation-settings: "wght" 750, "wdth" 70; font-feature-settings: "ss01"; line-height: 1.04; letter-spacing: 0.005em;">我们如何将多人游戏付诸实践
figma-1w80yjd" style="box-sizing: inherit; cursor: var(--cursorText); color: var(--secondary-color); margin-block: 24px;">游戏中有一个经典场景:每个人都过度关注图形,因此开发人员将大部分时间花在改进渲染系统上。但如果不投资动画系统或纹理艺术,游戏可能会看起来锯齿状和不稳定,并且无法达到玩家所寻求的质量。为了构建一个消除怀疑的沉浸式世界,我们不能仅仅深入研究一个系统,我们需要退后一步,着眼全局,确保每个系统都与其他系统相辅相成。
figma-1w80yjd" style="box-sizing: inherit; cursor: var(--cursorText); color: var(--secondary-color); margin-block: 24px;">这种想法推动了 Figma 和 figma.net.cn/lm2/3383.html">FigJam 的开发。例如,我们最近在 figma.net.cn/lm2/3383.html">FigJam 中推出了表格
figma.net.cn/core/extend/ueditor/themes/default/images/img-cracked.png" srcset="https://cdn.sanity.io/images/599r6htc/localized/f948cd9882d220ae718e17bc2d711c5061a885ed-2120x1000.png?q=75&fit=crop&crop=focalpoint&auto=format&dpr=0.5 1060w,https://cdn.sanity.io/images/599r6htc/localized/f948cd9882d220ae718e17bc2d711c5061a885ed-2120x1000.png?q=75&fit=crop&crop=focalpoint&auto=format&dpr=0.75 1590w,https://cdn.sanity.io/images/599r6htc/localized/f948cd9882d220ae718e17bc2d711c5061a885ed-2120x1000.png?q=75&fit=crop&crop=focalpoint&auto=format 2120w,https://cdn.sanity.io/images/599r6htc/localized/f948cd9882d220ae718e17bc2d711c5061a885ed-2120x1000.png?q=75&fit=crop&crop=focalpoint&auto=format&dpr=1.5 3180w,https://cdn.sanity.io/images/599r6htc/localized/f948cd9882d220ae718e17bc2d711c5061a885ed-2120x1000.png?q=75&fit=crop&crop=focalpoint&auto=format&dpr=2 4240w" loading="lazy" alt="" style="box-sizing: inherit; border-style: none; cursor: var(--cursorPointer); display: block; object-fit: cover; aspect-ratio: 21 / 9; width: 298.011px;" data-catch-result="fail"/>
figma-19jvqfh" style="box-sizing: inherit; cursor: var(--cursorPointer); margin: 12px 0px 4px; font-size: 16px; font-variation-settings: "wght" 600, "wdth" 98; line-height: 1.7; letter-spacing: 0px;">
。由于产品团队专注于完善单人游戏用例(例如复制和粘贴、撤消和重做、拖动以调整大小等),因此工程团队与我们的平台团队合作,以确保表格在多人游戏中正常运行系统。我们了解到,让表格真正具有协作性是非常困难的。如果一个用户在一个单元格中键入,而另一个用户主动删除它,会发生什么?如果一个人添加了一行,而另一个人更改了与该行相交的列的颜色,该怎么办?我们经历了很多这样的场景,确保最终结果感觉自然并且与应用程序的其余部分一致。我们可以选择通过在一个人主动编辑表格时锁定表格来降低复杂性,但这不符合 figma.net.cn/lm2/3383.html">FigJam 的协作性质。
figma-1w80yjd" style="box-sizing: inherit; cursor: var(--cursorText); color: var(--secondary-color); margin-block: 24px;">即使我们解决了制作多人游戏桌的难题,我们也意识到观察多人游戏的变化是一种不和谐的体验。想象一下:您正在编辑一个单元格,有人开始重新排列行,使您的单元格最终比原来的位置低两行——技术上是正确的,但在实践中却令人困惑。设计师 Jakub Świadek 提出了一种可以改善这种体验的交互方式,而工程师 Tim Babb 则致力于开发一个可以将其变为现实的框架。为了在代码中正确地重新创建 Jakub 的原型,我们需要构建一个新系统来为画布上的元素设置动画。
figma-1w80yjd" style="box-sizing: inherit; cursor: var(--cursorText); color: var(--secondary-color); margin-block: 24px;">首先,我们从“实时反馈”开始,以便编辑表格的用户可以实时看到他们的操作,即使没有大量明确的动画。当我们构建系统时,我们将每个版本都推送到我们的内部测试环境中,团队非常喜欢它的敏捷性;它允许用户看到他们正在移动行和列的位置,并带有恰到好处的 figma.net.cn/lm2/3383.html">FigJam 乐趣。然而,由于它仅与一个特定用户的鼠标移动(发起更改的人)相关,因此我们意识到这对其他所有人来说都是不和谐的。因此,我们决定添加更多动画,使用户能够观察更改,以便更清楚地跟踪发生的表格编辑。
figma-1w80yjd" style="box-sizing: inherit; cursor: var(--cursorText); color: var(--secondary-color); margin-block: 24px;">为了获得额外的奖励,我们甚至研究了拖动行的感觉,并添加了橡皮筋效果来帮助用户了解可以拖动行和列的位置的限制。这类似于游戏,设计师添加隐形墙壁和障碍来引导用户走上正确的道路,而不使用明确的标牌。
figma-1w80yjd" style="box-sizing: inherit; cursor: var(--cursorText); color: var(--secondary-color); margin-block: 24px;">最后,我们与我们的无障碍团队合作
figma.net.cn/core/extend/ueditor/themes/default/images/img-cracked.png" srcset="https://cdn.sanity.io/images/599r6htc/localized/d972d922c4c050e6ce77b423b844f0dd44f6e415-2120x1000.png?q=75&fit=crop&crop=focalpoint&auto=format&dpr=0.5 1060w,https://cdn.sanity.io/images/599r6htc/localized/d972d922c4c050e6ce77b423b844f0dd44f6e415-2120x1000.png?q=75&fit=crop&crop=focalpoint&auto=format&dpr=0.75 1590w,https://cdn.sanity.io/images/599r6htc/localized/d972d922c4c050e6ce77b423b844f0dd44f6e415-2120x1000.png?q=75&fit=crop&crop=focalpoint&auto=format 2120w,https://cdn.sanity.io/images/599r6htc/localized/d972d922c4c050e6ce77b423b844f0dd44f6e415-2120x1000.png?q=75&fit=crop&crop=focalpoint&auto=format&dpr=1.5 3180w,https://cdn.sanity.io/images/599r6htc/localized/d972d922c4c050e6ce77b423b844f0dd44f6e415-2120x1000.png?q=75&fit=crop&crop=focalpoint&auto=format&dpr=2 4240w" loading="lazy" alt="" style="box-sizing: inherit; border-style: none; cursor: var(--cursorPointer); display: block; object-fit: cover; aspect-ratio: 21 / 9; width: 298.011px;" data-catch-result="fail"/>
figma-19jvqfh" style="box-sizing: inherit; cursor: var(--cursorPointer); margin: 12px 0px 4px; font-size: 16px; font-variation-settings: "wght" 600, "wdth" 98; line-height: 1.7; letter-spacing: 0px;">
确保用户可以通过键盘快捷键导航表格。虽然许多 figma.net.cn/lm2/3383.html">FigJam 用户使用鼠标或触控板进行导航,但为我们的功能提供键盘导航选项更容易且更公平。这实际上也是游戏中非常常见的用例!有些游戏允许玩家使用键盘和鼠标、标准游戏手柄或专用游戏手柄来玩。回到那些构建模块,一个专门容纳不同控制方案的系统可以让更多的人享受游戏!在我发布的上一款游戏 ( Wattam ) 中,我们支持Xbox 自适应控制器,社区感谢我的这一决定。我很高兴 Figma继续投资
figma.net.cn/core/extend/ueditor/themes/default/images/img-cracked.png" srcset="https://cdn.sanity.io/images/599r6htc/localized/442adee373200edeb652c6ef76505d7c0ff0694b-2120x1000.png?q=75&fit=crop&crop=focalpoint&auto=format&dpr=0.5 1060w,https://cdn.sanity.io/images/599r6htc/localized/442adee373200edeb652c6ef76505d7c0ff0694b-2120x1000.png?q=75&fit=crop&crop=focalpoint&auto=format&dpr=0.75 1590w,https://cdn.sanity.io/images/599r6htc/localized/442adee373200edeb652c6ef76505d7c0ff0694b-2120x1000.png?q=75&fit=crop&crop=focalpoint&auto=format 2120w,https://cdn.sanity.io/images/599r6htc/localized/442adee373200edeb652c6ef76505d7c0ff0694b-2120x1000.png?q=75&fit=crop&crop=focalpoint&auto=format&dpr=1.5 3180w,https://cdn.sanity.io/images/599r6htc/localized/442adee373200edeb652c6ef76505d7c0ff0694b-2120x1000.png?q=75&fit=crop&crop=focalpoint&auto=format&dpr=2 4240w" loading="lazy" alt="" style="box-sizing: inherit; border-style: none; cursor: var(--cursorPointer); display: block; object-fit: cover; aspect-ratio: 21 / 9; width: 298.011px;" data-catch-result="fail"/>
figma-19jvqfh" style="box-sizing: inherit; cursor: var(--cursorPointer); margin: 12px 0px 4px; font-size: 16px; font-variation-settings: "wght" 600, "wdth" 98; line-height: 1.7; letter-spacing: 0px;">
也使我们的控制系统更易于访问。
figma-1w80yjd" style="box-sizing: inherit; cursor: var(--cursorText); color: var(--secondary-color); margin-block: 24px;">需要大量深入的问题解决和协作才能使 Figma 和 figma.net.cn/lm2/3383.html">FigJam 响应迅速且令人愉悦。与我一起工作的才华横溢的工程师让我感到谦卑,并且很感激我可以随时在复杂的系统上“钻研”。最重要的是,我喜欢看到用户创建复杂的世界,尤其是当他们构建自己的游戏时。