From 1a12d9717d79214a57183a17b16cece36fbdce35 Mon Sep 17 00:00:00 2001 From: freezy Date: Sat, 11 Jun 2022 22:59:46 +0200 Subject: [PATCH 01/12] gates: Add gate lifter component. --- .../Editor/Icons/small_blue/gate_lifter.png | Bin 0 -> 553 bytes .../Icons/small_blue/gate_lifter.png.meta | 122 ++++++++++++++++++ .../Editor/Icons/small_gray/gate_lifter.png | Bin 0 -> 557 bytes .../Icons/small_gray/gate_lifter.png.meta | 122 ++++++++++++++++++ .../Editor/Icons/small_green/gate_lifter.png | Bin 0 -> 556 bytes .../Icons/small_green/gate_lifter.png.meta | 122 ++++++++++++++++++ .../Editor/Icons/small_orange/gate_lifter.png | Bin 0 -> 558 bytes .../Icons/small_orange/gate_lifter.png.meta | 122 ++++++++++++++++++ .../VisualPinball.Unity.Editor/Utils/Icons.cs | 6 +- .../VisualPinball.Unity/Game/Player.cs | 5 + .../VisualPinball.Unity/VPT/CollidableApi.cs | 7 + .../VisualPinball.Unity/VPT/Gate/GateApi.cs | 10 ++ .../VPT/Gate/GateDisplacementSystem.cs | 12 +- .../VPT/Gate/GateLifterApi.cs | 95 ++++++++++++++ .../VPT/Gate/GateLifterApi.cs.meta | 11 ++ .../VPT/Gate/GateLifterComponent.cs | 56 ++++++++ .../VPT/Gate/GateLifterComponent.cs.meta | 11 ++ .../VPT/Gate/GateMovementData.cs | 4 + 18 files changed, 703 insertions(+), 2 deletions(-) create mode 100644 VisualPinball.Unity/Assets/Editor/Icons/small_blue/gate_lifter.png create mode 100644 VisualPinball.Unity/Assets/Editor/Icons/small_blue/gate_lifter.png.meta create mode 100644 VisualPinball.Unity/Assets/Editor/Icons/small_gray/gate_lifter.png create mode 100644 VisualPinball.Unity/Assets/Editor/Icons/small_gray/gate_lifter.png.meta create mode 100644 VisualPinball.Unity/Assets/Editor/Icons/small_green/gate_lifter.png create mode 100644 VisualPinball.Unity/Assets/Editor/Icons/small_green/gate_lifter.png.meta create mode 100644 VisualPinball.Unity/Assets/Editor/Icons/small_orange/gate_lifter.png create mode 100644 VisualPinball.Unity/Assets/Editor/Icons/small_orange/gate_lifter.png.meta create mode 100644 VisualPinball.Unity/VisualPinball.Unity/VPT/Gate/GateLifterApi.cs create mode 100644 VisualPinball.Unity/VisualPinball.Unity/VPT/Gate/GateLifterApi.cs.meta create mode 100644 VisualPinball.Unity/VisualPinball.Unity/VPT/Gate/GateLifterComponent.cs create mode 100644 VisualPinball.Unity/VisualPinball.Unity/VPT/Gate/GateLifterComponent.cs.meta diff --git a/VisualPinball.Unity/Assets/Editor/Icons/small_blue/gate_lifter.png b/VisualPinball.Unity/Assets/Editor/Icons/small_blue/gate_lifter.png new file mode 100644 index 0000000000000000000000000000000000000000..555595c469ab8d03f71d25c839e75652cb04b1e1 GIT binary patch literal 553 zcmV+^0@nSBP)cLFJ$gCNfd{nO%E7Ql1oPcWuu+%{-6CN^iH@p$ib5VA&<2eUfSn zV9+p+3jo&uz5u)f$SD)KIiU~W0l-aj98Y2ifXsojMq{H${R+U^uv_SLUX%ZO0N((H z0H&^qC+jFlRZDTDO!TzB34j-4Xi1p}(&%SWh9!L1h`z?*;snb_tj)AdorPEtodLLI zu2~1nIlxBrgJI*5GO;dx#WTk_2R5R4ppEU(2}1f?2%=~-l<15yafrTto&~PuWUW%_ ze^V~iKB7e}B&qHg5~xm;GT}?hKIOXeT9`{os$qx(0(|(12H-E{tD~ux0G^o=s7&Ea04*Q5MOSCFj zJKjf>ZH$4aL{oN9QB&V4G!ju=x>&FhHP7%iz*R?~kHIT%gm`x>+d<-lPopVHRH;n) zh^9z?5~3+KR4JQ2jW&g$zUv1QO%c(M(lkA8XnaKTGA)@0r8Md!s=M%sYffEgi$-&O r&l(%=|4QTe&xY7I6OD~-5C!l9j<1TYECG4Z00000NkvXXu0mjfx2)`N literal 0 HcmV?d00001 diff --git a/VisualPinball.Unity/Assets/Editor/Icons/small_blue/gate_lifter.png.meta b/VisualPinball.Unity/Assets/Editor/Icons/small_blue/gate_lifter.png.meta new file mode 100644 index 000000000..7394cb358 --- /dev/null +++ b/VisualPinball.Unity/Assets/Editor/Icons/small_blue/gate_lifter.png.meta @@ -0,0 +1,122 @@ +fileFormatVersion: 2 +guid: f8f0f43b8608e9541a2a0553c07a7d92 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 2 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 64 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/Assets/Editor/Icons/small_gray/gate_lifter.png b/VisualPinball.Unity/Assets/Editor/Icons/small_gray/gate_lifter.png new file mode 100644 index 0000000000000000000000000000000000000000..27bd62aef7e18a1d878f9db5eeb2c3f7a1b7d76d GIT binary patch literal 557 zcmV+|0@D47P)3ACRV zd<puYa z0WbtGH4QwPNArR=l3de-_2haJ053|{GEJD1N57&HdaR)XeG9{46lsl6hiMx-3ZZs1 z18_%tX5%nsFCFM7VUDLXVH@!g-zkezqysG-=hz%q97i11$h4!TlkZYpnZ}T> zXkXB}BAs{}D0wo1f`Z1Zpn`_}q}0le%G5=Y7F4~%PeGy4Nw5Tkf4kXW}{K&00000NkvXXu0mjfbCdAB literal 0 HcmV?d00001 diff --git a/VisualPinball.Unity/Assets/Editor/Icons/small_gray/gate_lifter.png.meta b/VisualPinball.Unity/Assets/Editor/Icons/small_gray/gate_lifter.png.meta new file mode 100644 index 000000000..9bf08c652 --- /dev/null +++ b/VisualPinball.Unity/Assets/Editor/Icons/small_gray/gate_lifter.png.meta @@ -0,0 +1,122 @@ +fileFormatVersion: 2 +guid: 089b7800e18ce404c8608d12ff6c9447 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 2 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 64 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/Assets/Editor/Icons/small_green/gate_lifter.png b/VisualPinball.Unity/Assets/Editor/Icons/small_green/gate_lifter.png new file mode 100644 index 0000000000000000000000000000000000000000..9f8ecf132b90888046600398622e9905139f1ea2 GIT binary patch literal 556 zcmV+{0@MA8P)R7$W*4P|GdOb8mXUDskI&ZC%@0nFY2HyOY}jk7nFSh9p)mN z02p=5aRJ~Oz&C&o07c4pp$`}WcmQzI9ph200j%_nvqwWqhJFKJtIaF@x@c+rdjLNG z5&$#Xz@vFI7g;OGHD!FD)|&!&(Yn?t<6a*9ib_~x4HM{F7#6EYYlJ#XyVy|(wWD(Y zx5Q_*9%J@0fqoL^cuX1J%8&d`S)3vhXyG}>?%)PlsWu-4@u)B8JY{^p`|A7L^I1yN z8il?Jc`mYQM`bR|MRrH9Ky%QPaaUNXkgLjTskO_t#K!_2Yq&u@^cV8Y!O%+p&qNC} z27NcQ>meT>=^x8JWq~Kd9IsT+p{38{p+zn-I0~0#F0zrU(4fe+qqdXpQ(f7{kgw>v zpiMDRpfL_qtvOvD?MjJy*Y^gEv7y3v71K9Csk@~$NtIh^Ye>3*lxGzf-X8i*(K1Z z;^`Q`uw{-*05<@>0ek=`V^);vfC#`NfZO&Mk7@~Ep?35h^(_(l6@XlsSNL^yqV*pD z`~XM*Oicri=Fy6$CrPd`D+Y4C34j-+YZGlv4F!Gc2EcXg?x1|^a{Y5 zXo1F{@0xZsK;ST~D;y~4!)8^5(l*o5|XV4Hk>XMqKhXsudw5(H-SyaoTMo?LWPfTM@ wrE~FUDc`fk%I|-vvH!Edw|Y?D>INu)U$HQaLcYA6oB#j-07*qoM6N<$g1sE|R{#J2 literal 0 HcmV?d00001 diff --git a/VisualPinball.Unity/Assets/Editor/Icons/small_orange/gate_lifter.png.meta b/VisualPinball.Unity/Assets/Editor/Icons/small_orange/gate_lifter.png.meta new file mode 100644 index 000000000..1b0674ff2 --- /dev/null +++ b/VisualPinball.Unity/Assets/Editor/Icons/small_orange/gate_lifter.png.meta @@ -0,0 +1,122 @@ +fileFormatVersion: 2 +guid: 714ba3a4d70e7484eb2a5e702bc528b0 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 2 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 64 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/Utils/Icons.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/Utils/Icons.cs index 041d0f9f3..6fbcf3c0c 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Editor/Utils/Icons.cs +++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/Utils/Icons.cs @@ -73,6 +73,7 @@ public IconVariant(string name, IconSize size, IconColor color) private const string FlasherName = "light_flasher"; private const string FlipperName = "flipper"; private const string GateName = "gate"; + private const string GateLifterName = "gate_lifter"; private const string HitTargetName = "hit_target"; private const string KeyName = "keyboard"; private const string KickerName = "kicker"; @@ -113,7 +114,7 @@ public IconVariant(string name, IconSize size, IconColor color) private static readonly string[] Names = { AssetLibraryName, BallRollerName, BoltName, BumperName, CalendarName, CannonName, CoilName, DropTargetBankName, DropTargetName, FlasherName, - FlipperName, GateName, HitTargetName, KeyName, KickerName, LightGroupName, LightName, MechName, MechPinMameName, PlayfieldName, PlugName, + FlipperName, GateName, GateLifterName, HitTargetName, KeyName, KickerName, LightGroupName, LightName, MechName, MechPinMameName, PlayfieldName, PlugName, PlungerName, PrimitiveName, RampName, RotatorName, RubberName, ScoreReelName, ScoreReelSimpleName, SlingshotName, SpinnerName, SurfaceName, SwitchNcName, SwitchNoName, TableName, TeleporterName, TriggerName, TroughName, CoilEventName, SwitchEventName, LampEventName, LampSeqName, MetalWireGuideName, @@ -172,6 +173,7 @@ private static IIconLookup[] GetLookups() { public static Texture2D Flasher(IconSize size = IconSize.Large, IconColor color = IconColor.Gray) => Instance.GetItem(FlasherName, size, color); public static Texture2D Flipper(IconSize size = IconSize.Large, IconColor color = IconColor.Gray) => Instance.GetItem(FlipperName, size, color); public static Texture2D Gate(IconSize size = IconSize.Large, IconColor color = IconColor.Gray) => Instance.GetItem(GateName, size, color); + public static Texture2D GateLifter(IconSize size = IconSize.Large, IconColor color = IconColor.Gray) => Instance.GetItem(GateLifterName, size, color); public static Texture2D HitTarget(IconSize size = IconSize.Large, IconColor color = IconColor.Gray) => Instance.GetItem(HitTargetName, size, color); public static Texture2D Key(IconSize size = IconSize.Large, IconColor color = IconColor.Gray) => Instance.GetItem(KeyName, size, color); public static Texture2D Kicker(IconSize size = IconSize.Large, IconColor color = IconColor.Gray) => Instance.GetItem(KickerName, size, color); @@ -277,6 +279,7 @@ public Texture2D Lookup(T mb, IconSize size = IconSize.Large, IconColor color case DropTargetBankComponent _: return Icons.DropTargetBank(size, color); case FlipperComponent _: return Icons.Flipper(size, color); case GateComponent _: return Icons.Gate(size, color); + case GateLifterComponent _: return Icons.GateLifter(size, color); case HitTargetComponent _: return Icons.HitTarget(size, color); case KickerComponent _: return Icons.Kicker(size, color); case LightComponent _: return Icons.Light(size, color); @@ -322,6 +325,7 @@ public void DisableGizmoIcons() Icons.DisableGizmo(); Icons.DisableGizmo(); Icons.DisableGizmo(); + Icons.DisableGizmo(); Icons.DisableGizmo(); Icons.DisableGizmo(); Icons.DisableGizmo(); diff --git a/VisualPinball.Unity/VisualPinball.Unity/Game/Player.cs b/VisualPinball.Unity/VisualPinball.Unity/Game/Player.cs index 89c88f3a8..9e5b5545f 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/Game/Player.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/Game/Player.cs @@ -237,6 +237,11 @@ public void RegisterGate(GateComponent component, Entity entity) RegisterTransform(GateWireTransforms, component, entity); } + public void RegisterGateLifter(GateLifterComponent component) + { + Register(new GateLifterApi(component.gameObject, this), component); + } + public void RegisterHitTarget(HitTargetComponent component, Entity entity) { Register(new HitTargetApi(component.gameObject, entity, this), component, entity); diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/CollidableApi.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/CollidableApi.cs index 0e12c851d..ffbc168b3 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/CollidableApi.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/CollidableApi.cs @@ -27,13 +27,20 @@ public abstract class CollidableApi : I where TCollidableComponent : ColliderComponent where TData : ItemData { + public bool IsCollidable { + get => _simulateCycleSystemGroup.ItemsColliding[Entity]; + set => _simulateCycleSystemGroup.ItemsColliding[Entity] = value; + } + protected readonly Entity Entity; protected readonly TCollidableComponent ColliderComponent; private protected EntityManager EntityManager; + private readonly SimulateCycleSystemGroup _simulateCycleSystemGroup; protected CollidableApi(GameObject go, Entity entity, Player player) : base(go, player) { + _simulateCycleSystemGroup = World.DefaultGameObjectInjectionWorld.GetOrCreateSystem(); EntityManager = World.DefaultGameObjectInjectionWorld != null ? World.DefaultGameObjectInjectionWorld.EntityManager : default; Entity = entity; diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Gate/GateApi.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Gate/GateApi.cs index 2ad94e933..664fd21b8 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Gate/GateApi.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Gate/GateApi.cs @@ -17,6 +17,7 @@ using System; using System.Collections.Generic; using Unity.Entities; +using Unity.Mathematics; using UnityEngine; using VisualPinball.Engine.VPT.Gate; @@ -78,6 +79,15 @@ public GateApi(GameObject go, Entity entity, Player player) { } + public void Lift(float speed, float angleDeg) + { + var data = EntityManager.GetComponentData(Entity); + data.IsLifting = true; + data.LiftSpeed = speed; + data.LiftAngle = math.radians(angleDeg); + EntityManager.SetComponentData(Entity, data); + } + #region Wiring public bool IsSwitchEnabled => SwitchHandler.IsEnabled; diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Gate/GateDisplacementSystem.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Gate/GateDisplacementSystem.cs index a307f6bf8..c07c58560 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Gate/GateDisplacementSystem.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Gate/GateDisplacementSystem.cs @@ -52,7 +52,7 @@ protected override void OnUpdate() Entities .WithName("GateDisplacementJob") - .ForEach((Entity entity, ref GateMovementData movementData, in GateStaticData data) => { + .ForEach((Entity entity, ref GateMovementData movementData, in GateStaticData data) => { marker.Begin(); @@ -117,6 +117,16 @@ protected override void OnUpdate() } } movementData.Angle += movementData.AngleSpeed * dTime; + + if (movementData.IsLifting) { + if (math.abs(movementData.Angle - movementData.LiftAngle) > 0.000001f) { + var direction = movementData.Angle < movementData.LiftAngle ? 1f : -1f; + movementData.Angle += direction * (movementData.LiftSpeed * dTime); + + } else { + movementData.IsLifting = false; + } + } marker.End(); diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Gate/GateLifterApi.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Gate/GateLifterApi.cs new file mode 100644 index 000000000..f989dde81 --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Gate/GateLifterApi.cs @@ -0,0 +1,95 @@ +// Visual Pinball Engine +// Copyright (C) 2022 freezy and VPE Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +using System; +using NLog; +using UnityEngine; +using Logger = NLog.Logger; + +namespace VisualPinball.Unity +{ + public class GateLifterApi : IApi, IApiCoilDevice, IApiWireDeviceDest + { + public DeviceCoil LifterCoil; + + public event EventHandler Init; + + private readonly Player _player; + private readonly GateComponent _gateComponent; + private readonly GateLifterComponent _gateLifterComponent; + private readonly GateColliderComponent _gateColliderComponent; + + private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); + private GateApi _gateApi; + + internal GateLifterApi(GameObject go, Player player) + { + _gateComponent = go.GetComponent(); + _gateColliderComponent = go.GetComponent(); + _gateLifterComponent = go.GetComponent(); + _player = player; + } + + void IApi.OnInit(BallManager ballManager) + { + LifterCoil = new DeviceCoil(_player, OnLifterCoilEnabled, OnLifterCoilDisabled); + _gateApi = _player.TableApi.Gate(_gateComponent); + Init?.Invoke(this, EventArgs.Empty); + } + + public IApiCoil Coil(string deviceItem) + { + return deviceItem switch { + GateLifterComponent.LifterCoilItem => LifterCoil, + _ => throw new ArgumentException($"Unknown coil \"{deviceItem}\". Valid name is \"{GateLifterComponent.LifterCoilItem}\".") + }; + } + + public IApiWireDest Wire(string deviceItem) + { + return deviceItem switch { + GateLifterComponent.LifterCoilItem => LifterCoil, + _ => throw new ArgumentException($"Unknown wire \"{deviceItem}\". Valid name is \"{GateLifterComponent.LifterCoilItem}\".") + }; + } + + private void OnLifterCoilEnabled() + { + if (_gateColliderComponent == null) { + Logger.Warn("Lifter coil enabled, but gate collider not found."); + return; + } + + _gateApi.IsCollidable = false; + _gateApi.Lift(_gateLifterComponent.AnimationSpeed, _gateLifterComponent.LiftedAngleDeg); + } + + private void OnLifterCoilDisabled() + { + if (_gateColliderComponent == null) { + Logger.Warn("Lifter coil enabled, but gate collider not found."); + return; + } + + _gateApi.IsCollidable = true; + _gateApi.Lift(_gateLifterComponent.AnimationSpeed, 0f); + } + + void IApi.OnDestroy() + { + } + } +} diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Gate/GateLifterApi.cs.meta b/VisualPinball.Unity/VisualPinball.Unity/VPT/Gate/GateLifterApi.cs.meta new file mode 100644 index 000000000..08852d8d2 --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Gate/GateLifterApi.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: dae30298e10a0894c991d49ceb01e001 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Gate/GateLifterComponent.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Gate/GateLifterComponent.cs new file mode 100644 index 000000000..82ebe6718 --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Gate/GateLifterComponent.cs @@ -0,0 +1,56 @@ +// Visual Pinball Engine +// Copyright (C) 2022 freezy and VPE Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// ReSharper disable InconsistentNaming + +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using VisualPinball.Engine.Game.Engines; + +namespace VisualPinball.Unity +{ + [AddComponentMenu("Visual Pinball/Mechs/Gate Lifter")] + public class GateLifterComponent : MonoBehaviour, ICoilDeviceComponent + { + public const string LifterCoilItem = "lifter_coil"; + + [Tooltip("How much to rotate the wire to the end position, in degrees.")] + public float LiftedAngleDeg; + + [Tooltip("How fast to lift the wire to the end position.")] + public float AnimationSpeed = 0.1f; + + #region ICoilDeviceComponent + + IEnumerable IDeviceComponent.AvailableDeviceItems => AvailableCoils; + IEnumerable IWireableComponent.AvailableWireDestinations => AvailableCoils; + IEnumerable IDeviceComponent.AvailableDeviceItems => AvailableCoils; + public IEnumerable AvailableCoils => new[] { + new GamelogicEngineCoil(LifterCoilItem) { + Description = "Lifter Coil" + } + }; + + #endregion + + private void Awake() + { + GetComponentInParent().RegisterGateLifter(this); + var wireComponent = GetComponentInChildren(); + } + } +} diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Gate/GateLifterComponent.cs.meta b/VisualPinball.Unity/VisualPinball.Unity/VPT/Gate/GateLifterComponent.cs.meta new file mode 100644 index 000000000..819d73ff8 --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Gate/GateLifterComponent.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ab2020dc8f79c7543b66ff6ec8830aed +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 089b7800e18ce404c8608d12ff6c9447, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Gate/GateMovementData.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Gate/GateMovementData.cs index 75e729cf9..685df1b9f 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Gate/GateMovementData.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Gate/GateMovementData.cs @@ -25,5 +25,9 @@ internal struct GateMovementData : IComponentData public bool ForcedMove; public bool IsOpen; public bool HitDirection; + + public bool IsLifting; + public float LiftAngle; + public float LiftSpeed; } } From ce2a01510e1a57f1758682318c136478d6fffbc6 Mon Sep 17 00:00:00 2001 From: Jason Millard Date: Mon, 13 Jun 2022 16:07:54 -0400 Subject: [PATCH 02/12] coilplayer: use IsDynamic when determining hasDynamicWire --- VisualPinball.Unity/VisualPinball.Unity/Game/CoilPlayer.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/VisualPinball.Unity/VisualPinball.Unity/Game/CoilPlayer.cs b/VisualPinball.Unity/VisualPinball.Unity/Game/CoilPlayer.cs index 2d2dd47fa..c1e0692bc 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/Game/CoilPlayer.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/Game/CoilPlayer.cs @@ -114,7 +114,8 @@ private void AssignCoilMapping(CoilMapping coilMapping, bool isLampCoil) } var hasDynamicWire = _tableComponent!.MappingConfig.Wires.FirstOrDefault(w => w.DestinationDevice == coilMapping.Device && - w.DestinationDeviceItem == coilMapping.DeviceItem) != null; + w.DestinationDeviceItem == coilMapping.DeviceItem && + w.IsDynamic) != null; _coilAssignments[coilMapping.Id].Add(new CoilDestConfig(coilMapping.Device, coilMapping.DeviceItem, isLampCoil, hasDynamicWire)); CoilStatuses[coilMapping.Id] = false; From ee9b09840c2772403d06b94176ee0a13b84b9e5b Mon Sep 17 00:00:00 2001 From: Jason Millard Date: Mon, 13 Jun 2022 16:29:32 -0400 Subject: [PATCH 03/12] wireplayer: prevent unmapped eos switches from causing exceptions --- VisualPinball.Unity/VisualPinball.Unity/Game/WirePlayer.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/VisualPinball.Unity/VisualPinball.Unity/Game/WirePlayer.cs b/VisualPinball.Unity/VisualPinball.Unity/Game/WirePlayer.cs index bf59bd680..fd7726c29 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/Game/WirePlayer.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/Game/WirePlayer.cs @@ -360,6 +360,9 @@ public void HandleSwitchChange(WireDestConfig wireConfig, bool isEnabled) /// Whether to enable or disable the coil. public void HandleCoilEvent(string id, bool isEnabled) { + if (!_gleDestAssignments.ContainsKey(id)) { + return; + } foreach (var wireConfig in _gleDestAssignments[id]) { if (!_wireDevices.ContainsKey(wireConfig.Device)) { continue; From f84a7859979c112e4130232d3929c124d2384fd9 Mon Sep 17 00:00:00 2001 From: freezy Date: Tue, 14 Jun 2022 22:42:48 +0200 Subject: [PATCH 04/12] fix: Inspector for score reel display component. --- .../Display/ScoreReelDisplayInspector.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/Display/ScoreReelDisplayInspector.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/Display/ScoreReelDisplayInspector.cs index df354d35d..471792844 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Editor/Display/ScoreReelDisplayInspector.cs +++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/Display/ScoreReelDisplayInspector.cs @@ -37,10 +37,14 @@ private void OnEnable() public override void OnInspectorGUI() { + serializedObject.Update(); + EditorGUILayout.PropertyField(_idProperty, new GUIContent("ID")); EditorGUILayout.PropertyField(_speedProperty); EditorGUILayout.PropertyField(_waitProperty); EditorGUILayout.PropertyField(_reelObjectsProperty); + + serializedObject.ApplyModifiedProperties(); } } } From 30baf037e1b35245159b8e8aa58d7e0b79ab80a9 Mon Sep 17 00:00:00 2001 From: freezy Date: Tue, 14 Jun 2022 23:07:10 +0200 Subject: [PATCH 05/12] display: Add direction to score reel. --- .../Display/ScoreReelComponent.cs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/VisualPinball.Unity/VisualPinball.Unity/Display/ScoreReelComponent.cs b/VisualPinball.Unity/VisualPinball.Unity/Display/ScoreReelComponent.cs index d4ec7352a..91f498d45 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/Display/ScoreReelComponent.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/Display/ScoreReelComponent.cs @@ -23,6 +23,14 @@ namespace VisualPinball.Unity { public class ScoreReelComponent : MonoBehaviour { + public enum ScoreReelDirection + { + up, down + } + + [Tooltip("In which direction the reel rotates, when looking from the front.")] + public ScoreReelDirection Direction = ScoreReelDirection.down; + [HideInInspector] public float Speed = 1; @@ -35,6 +43,8 @@ public class ScoreReelComponent : MonoBehaviour private float _currentRotation; + private bool _isRotatingDown => Direction == ScoreReelDirection.down; + public void AnimateTo(int position) { var numPositions = (position - _nextPosition + 10) % 10; @@ -48,9 +58,10 @@ public void AnimateTo(int position) private IEnumerator Rotate() { + var dir = _isRotatingDown ? 1 : -1; while (_remainingPositions > 0) { var lastPosition = (int)(_currentRotation / 36f); - _currentRotation += Time.deltaTime * Speed * 36f; + _currentRotation += dir * Time.deltaTime * Speed * 36f; var currentPosition = (int)(_currentRotation / 36f); _currentRotation %= 360f; From 9583d389c430d1b4fd0c79def9bbcecbadbac865 Mon Sep 17 00:00:00 2001 From: freezy Date: Fri, 24 Jun 2022 23:06:38 +0200 Subject: [PATCH 06/12] gate: Add documentation for gate lifter. --- .../manual/mechanisms/lifting-gate.jpg | Bin 0 -> 95639 bytes .../manual/mechanisms/lifting-gates.md | 36 ++++++++++++++++++ .../Documentation~/creators-guide/toc.yml | 2 + .../VPT/Gate/GateLifterComponent.cs | 3 +- 4 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 VisualPinball.Unity/Documentation~/creators-guide/manual/mechanisms/lifting-gate.jpg create mode 100644 VisualPinball.Unity/Documentation~/creators-guide/manual/mechanisms/lifting-gates.md diff --git a/VisualPinball.Unity/Documentation~/creators-guide/manual/mechanisms/lifting-gate.jpg b/VisualPinball.Unity/Documentation~/creators-guide/manual/mechanisms/lifting-gate.jpg new file mode 100644 index 0000000000000000000000000000000000000000..2559eba8c6f6eb7d529433e58287ca437b628f96 GIT binary patch literal 95639 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
?S6Th4d!eieEyWuHabnB9`8O(cD#mrpru{21CBA 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 + +
+ Photo © 2022 by bord + + +Some Gottlieb and Bally games use gates that can be activated and deactivated. It does that by connecting a stem to the wire that lifts it up so the ball can pass through in both directions. The stem is attached to a relay. When the relay is turned on, the one-way gate becomes a two-way gate. + +VPE provides a component that you can add to your existing gate. By doing that, it creates a new coil device that you can then map in the [Coil Manager](xref:coil_manager). + +## Setup + +In order to add the lifting gate feature to a gate, select the game object of the gate and click on *Add Component* in the inspector. Select it by searching or navigating to *Visual Pinball -> Mechs -> Gate Lifter*. + +### Lifting Angle + +How many degrees the wire rotates up to the deactivated position. About 15° should work well for most geometry. + +### Animation Speed + +How fast the gate rotates from and into the decativated position. Higher is faster. `0.1` seems a reasonable value. + +## Usage + +Adding the gate lifter component adds a coil input to the gate, i.e. you can map it to any of the gamelogic engine's coil outputs through the [Coil Manager](xref:coil_manager). + +> [!NOTE] +> If you're working on an EM game or an original game with [Visual Scripting](xref:uvs_index), don't forget to add the new coil to the [coil definitions](xref:uvs_setup#coils). \ No newline at end of file diff --git a/VisualPinball.Unity/Documentation~/creators-guide/toc.yml b/VisualPinball.Unity/Documentation~/creators-guide/toc.yml index b1a94e913..d42afcc2e 100644 --- a/VisualPinball.Unity/Documentation~/creators-guide/toc.yml +++ b/VisualPinball.Unity/Documentation~/creators-guide/toc.yml @@ -87,3 +87,5 @@ href: manual/mechanisms/rotators.md - name: Collision Switches href: manual/mechanisms/collision-switches.md + - name: Lifting Gates + href: manual/mechanisms/lifting-gates.md diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Gate/GateLifterComponent.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Gate/GateLifterComponent.cs index 82ebe6718..9c6969bc4 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Gate/GateLifterComponent.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Gate/GateLifterComponent.cs @@ -23,11 +23,13 @@ namespace VisualPinball.Unity { + [RequireComponent(typeof(GateComponent))] [AddComponentMenu("Visual Pinball/Mechs/Gate Lifter")] public class GateLifterComponent : MonoBehaviour, ICoilDeviceComponent { public const string LifterCoilItem = "lifter_coil"; + [Unit("degrees")] [Tooltip("How much to rotate the wire to the end position, in degrees.")] public float LiftedAngleDeg; @@ -50,7 +52,6 @@ public class GateLifterComponent : MonoBehaviour, ICoilDeviceComponent private void Awake() { GetComponentInParent().RegisterGateLifter(this); - var wireComponent = GetComponentInChildren(); } } } From b7c010885639f94a0be8892103123fe425b88e55 Mon Sep 17 00:00:00 2001 From: freezy Date: Sun, 26 Jun 2022 22:21:36 +0200 Subject: [PATCH 07/12] gate: Add lifter inspector --- .../VPT/Gate/GateLifterInspector.cs | 44 +++++++++++++++++++ .../VPT/Gate/GateLifterInspector.cs.meta | 11 +++++ 2 files changed, 55 insertions(+) create mode 100644 VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Gate/GateLifterInspector.cs create mode 100644 VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Gate/GateLifterInspector.cs.meta diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Gate/GateLifterInspector.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Gate/GateLifterInspector.cs new file mode 100644 index 000000000..33d6c0dcf --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Gate/GateLifterInspector.cs @@ -0,0 +1,44 @@ +// Visual Pinball Engine +// Copyright (C) 2022 freezy and VPE Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +using UnityEditor; +using UnityEngine; + +namespace VisualPinball.Unity.Editor +{ + [CustomEditor(typeof(GateLifterComponent)), CanEditMultipleObjects] + public class GateLifterInspector : UnityEditor.Editor + { + private SerializedProperty _angleProperty; + private SerializedProperty _speedProperty; + + private void OnEnable() + { + _angleProperty = serializedObject.FindProperty(nameof(GateLifterComponent.LiftedAngleDeg)); + _speedProperty = serializedObject.FindProperty(nameof(GateLifterComponent.AnimationSpeed)); + } + + public override void OnInspectorGUI() + { + serializedObject.Update(); + + EditorGUILayout.PropertyField(_angleProperty); + EditorGUILayout.PropertyField(_speedProperty); + + serializedObject.ApplyModifiedProperties(); + } + } +} diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Gate/GateLifterInspector.cs.meta b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Gate/GateLifterInspector.cs.meta new file mode 100644 index 000000000..2629fcbbf --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Gate/GateLifterInspector.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9f8d7d8c69166434c867f04d7c8c5c3a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: From 3f46b95da627ae091402a99e8ce1c45ec2ad00a1 Mon Sep 17 00:00:00 2001 From: freezy Date: Sun, 26 Jun 2022 22:32:38 +0200 Subject: [PATCH 08/12] doc: Update changelog. --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 285f1fd1d..6a76a2721 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ Built with Unity 2021.2. ### Added +- Gate Lifter Component ([#418](https://github.com/freezy/VisualPinball.Engine/pull/418), [Documentation](https://docs.visualpinball.org/creators-guide/manual/mechanisms/lifting-gates.html)). - Asset Browser ([#412](https://github.com/freezy/VisualPinball.Engine/pull/412)) - Trigger meshes can now be easily scaled ([#374](https://github.com/freezy/VisualPinball.Engine/pull/374)) - We got a new game item called *Metal Wire Guide* (thanks @Cupiii, [#366](https://github.com/freezy/VisualPinball.Engine/pull/366)) From 04825688d12072aa2ec30479ab08b6b3f9711ac9 Mon Sep 17 00:00:00 2001 From: freezy Date: Sun, 26 Jun 2022 22:32:57 +0200 Subject: [PATCH 09/12] doc: Update link to WIP thread. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6aa5a0944..9c047e2cf 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ This repository is part of a number of packages. It is what we're referring to a VPE is still work in progress. You can check the current features list [here](https://docs.visualpinball.org/creators-guide/introduction/features.html) and the open issues [here](https://github.com/freezy/VisualPinball.Engine/issues). -There are a few videos in the [VPF thread](https://www.vpforums.org/index.php?showtopic=43651), +There are a few videos in the [VPF thread](https://vpuniverse.com/forums/topic/5362-wip-visual-pinball-in-unity-2021-edition/), where you can discuss. Screenshots are [here](https://github.com/freezy/VisualPinball.Engine/wiki/Unity-Screenshots)! :) ## Credits From 68ce90e10ed222bdd920e74ad1f0e235ac2fc9d7 Mon Sep 17 00:00:00 2001 From: freezy Date: Sun, 26 Jun 2022 22:47:43 +0200 Subject: [PATCH 10/12] gate: Add inspector screenshot to lifter component. --- .../manual/mechanisms/lifting-gate-inspector.png | Bin 0 -> 8672 bytes .../manual/mechanisms/lifting-gates.md | 2 ++ .../VPT/Gate/GateLifterInspector.cs | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 VisualPinball.Unity/Documentation~/creators-guide/manual/mechanisms/lifting-gate-inspector.png diff --git a/VisualPinball.Unity/Documentation~/creators-guide/manual/mechanisms/lifting-gate-inspector.png b/VisualPinball.Unity/Documentation~/creators-guide/manual/mechanisms/lifting-gate-inspector.png new file mode 100644 index 0000000000000000000000000000000000000000..97630a439bf152ea9fd882b388c7bf295844533a GIT binary patch literal 8672 zcmcI~cT`i|*Cwb)Q@ZpLf;6e2gCbHzDT36{LkPtHp@a^i5;1g85R{^TbQB1pNL4zK zDiT4Y7m+F;y*LNoGT)l@%{RY)CTk%#mvi^oXP0L`dtalB46mN0;iMrWBRhLdSL-Gj z8Tkyj#!#IA{}Q^+lY?K>Ub=8!GBR4`;~#Rery1;IWE7olrj}Ss1AP@F#zPX}gmFYk z26}jb)nsIs)B?Q_NHhuyaYVVed8$HJYa5{uHz!r7g}i~ZftM!A)lE0p2W1j$Xo?I* zBbA+?YL_9G0#$$j4-^&w3G{IH^i>H|h5nJN0KHC7pv_LcKKW1|5mWCX^L$t;${W=7jwBSuZ~y_dh3fLQ0|B zQ66BKFHj8j?^a%}7%axu74v^N$G?C6_cUHAnm#B57UN@z!MOk9DWiX+KxAYkWg#LK zZk|q<0AJB#jsAWBrG>zvRH4USlaN-BkWny|kx`LTP?41ula^7Dmi}w00SE*q1Qzk1 zEyg&xIS2hGOAQQEu6g=m5uQlYH7!*rP)gFx%}K>cNmBB?%>21%!mM zvYfI6Ldh8=A%m2LDa**p!JK3j|B-gX#|@+o!u`KWJ=V$zNJPTq6;LQ;SqWulMVN#< zLe3dnDIp~gFhvDtWtgLkg0nLe;)GOj#`t(3K%BUFAY4#VUY;&c$p6+x6XTBYF~B$h zo68Wa%V<)4WpnuYs=ubC zZW{P?In&ML+_i=W-)Z%~aUJGQ8~%z}!C&lWM7|w+;^`7xKD@0xOyPuP(QegIPqw|n zpsj6l#YtJ5*nlCd_C=R!+~^I>+)sam)PcK9zMmBDSfxH$LLkU2e(nrjcm_8sxV^1r zb##S_zeSSq@lobZZxn+D-c|$7tkI$VXfu2~>)h{Zdn$e$K?uj-lZaYgT3VW#nwp%P zoSmJ`rC?6ehO(}WKygN-$0=2{wYBY8Kex6b%WQ3Jcg+|zM9?uG_l$Q<48jI@kL2YV ziZOw^zC^RzW;h1o*D1oQ;$k=S>er3N*NZ<6imCXMt6EW+X=!O0p|fABOa~|qi{Hub z5>s4yvrI@hhP#!O8$~7sj*gB@RSqXAA6Gx0U0C2`V`JmvYqUp}udJ-BSxFU2Wb#;lmemLcvRa#Jv&frjFWaMd0j<&Y8#O&Hy>wL(@7Nv}=>~=s1RRvw5vxUW%PoF*k zbMNc~hKK)t|Ni~_yhw7KmiSk;lIss2K79Pzq3PfggS49*r!hoG8m$h0b~$X1Xb9r@!5@YGu~vxhD2rhg+#*r7;6Ztt*aByx3I7X-}@mv@bT`q*67-* z15Z@g@>h8|8}~P9o7>xLo0o4N?0kFYJI}YYy2ap_nP!#7`F!mG4p;3)O+!;$RK)nB zqkLqClYee^6tWEeM^7#Q)_GrU+_g0pOe{_5yQy5q>_?F ztxLBh%v3XYn3>VO@MbJ#tnO}qetv$R#6y>z-QA$`Jv}{7FCRF`!x#N&wd!5R9}n?r zh{sh{`f6*pexl6D&1HPzj6#9v`=HFo$mqjJSiXfL*X{;>`tdxu${{$I^GWvskTrzT1!<>vcCF;RYN&+|qIi zy8Wfho{g22^M~NF2-^K5vA3tE?NEzSA3tOmhZBSBFBs_S+gMs& zkw_a#J<*$?Y?4R8%$h2H#lotr)XdghfQ4;5Nu>?z;ZdI`@62~eyxBeEYJiIc1|-Q^ z^=|IEaGJr5M#Q7`ZV-)=0>9q)cTtCE1nmfEDGCb zmQ!ie1HCZ5h;?&Gf&2|Gw^z zrKQ&mr3S;i#_>4 zg+JvS(1oF_)v7P|Czc`>K4gFS_;K}UEg@Y0#tp?|aL@$5sZX{gu1%Axu@VfLS27zb2E}PB{>;C{Pn91nH%VyWY9@gfCJlb4XC^oRV=IZL| z;jz58S5wX_)N-87DYb!rCg-rsXDX=|B3txnm-Fqss zsEVOS8Mw3CTmO2H5gZ&m_x=0Y7bXE^(mubitTA1LP5o0VGqc=13u}wtTg&Uee!XTt z-PzS;N*6&EDuzZczTr{2=(k{MWR#d~EbMfLp}DCkHbWt)eSF-0b#;p$cInbLqS_A^ z%!npl^g;Ih+t72`nW`cFjahe1y&Y~t{o2WyojSU^wU-WVNW{g(9UC;2`|aEC7AO`TBH z%aV3SmV~EMVYyjYlGD>iMn-Bud8w<5rS5{}=NC}}N>ktQltF_E zWdP`nJU@{IsRq@SdLGhQ}?L)-;0UhQM#y7 zW#_-1KE1n8Qg(TNsdAi|px5W#7bt?(DE;uoK0GdWWusT^_f(A3kyeN2l}g6A2Lz!O zLg+@fB0hEk9sFP^PO9;M$$;u?6u5uypp2FCL0W{XHqhuX&&zx?em8Vo;7hW6b}2Q= z0FL(d@d1v&dU;7FPj)?#6%`dFvN$#PFI%BdsGy*CfaZyoSkfsfD$>)_>m>s|n6o`# zOq$qPo3<>zesHwE%7fhj$We4b1HO6^6i0h2D;gRanPh~60~yDOlP6KvuU(_Q2}qF~ zXZQH;qktC zaB^|I^#epRznBW;aTX4!T|q$stthR|)vM@Rw~~XLot;;{y+a<0JUZAFln4q6O0GKR zbWHui2yfmfsH(mcLyIpgEJXiKTW#2nFNU_Ec(}M~%ge98)5XxXrngAxjy%OBCHs4O z#l^*Y`}?A3v5w%|w;OVEo4dQ0hbvub2)DOaY~9>MTebYf7I8S-_UgC^X^yC(re>ep zkN=Ubi1GLLmz0!@kBdW00rgX*?9KC8&YdeVXRMU6tNXdJ(QL0ZtE#H{)^k+FdkRNj zrKeAzq~|?DN0*Zk9ZeGuuw7GA^X;3BfOY&OFG|M+S~kfE0WB@9LWPm8>wc)^nHi83 zcXEV;gsiNreh$;8m-eS9`^-=YVNr))8jt)!LiXF@xLBBB#-tA)KFo)_tEpKaa)v44 zM(phDbVyBW?5wOpObF=~1|?i?=EVopCPdil`F6hWOS!GX!@GAnt$viw&(C*t>5CAG zil~{{r0iOHZsupGhL~IUIF6yTbJ?iyQ=j*gBJ zEb90G!2feYQJM-7y znd|68+R&~s(+#Dhq|DBuT#13oI;^04WIMg+?dqxv+5mQ%drth?f?%+P=hC3Kqsf4O z%;|0+ZRdG~^`DT#E}Fw67eR0gnas7n%{!CPU1qu|%HWOMEG!gx;scy5$H~XXN92SI z-7QVRBgroMqtWQFFrKOW0{p8|#!F|rjq8qs{iLO%%=O@#oxVc~_Gn)mpvlW`EsHg8Jd3sTaLQ&V#zxXzuUaLZBVF9hKA zaC^F`68}lkrW&#$Dt#V3J!MadDP*D38oB9eM#eje%-a7-531H`S`$={d#RU$IN(DO*BTY<}IPA~_C`tZ` zXL4eyE&8?KpgR#LZngS3%IkC(v1RedtLe_Kiz+JDuU}`7Z;l8?#f>qO%yXp8${tGc_}nE=lnxtkef9)Bm;*O$58lszL08ZPtG=nNFjoe->P z(c)zJ;`8ezaxt@V0>QD4oa;h+;5q3|&v4KAJBM1u1qH&Fe>bq)Ka^Kgq`Yh8yKhj+ za{XQ|eJB0;@}%(11U|L+h(vPvVPjG)#bmioE@SZK*4E1E>QyfX;j2W%uIeJ_))p3S zZE^S>-2(U#pt8Nzr zRnml4-$fq-IP=KIr|rW0*OxR%p!4MAj9v#_(fW_xIM z5(D_HYijsjt2Gbx_1&rGx1*80c+uL*Y5}x1zHqMKyYYighpCMRv#l{~Q-0FV8yoq) z2TsTB1DZ}jK>@HYzm6f3ff!8L0~&=E(9ORc@tdBW9vB!f2(6sqHLBO``ZUNN48op= zmsjV2mx<}#L``)y`;@|A{jX=`rHcy-q%U7UDVUfC?L|i0&*jkV(SS%R|0`GCFMcTl zqnrGKf@Alto&>lR78Yh^W`<8$@|ZE*ewn~32z1?!Tg9JEqT1wk{*x9@8@#6@Kegfs z742uLmUee{K(p_lz%qD4b=OM_>WW9}z4Mx+w-Q7tkjUG_9 zt>1cPDtT)>QP1r!T&FyJT0u_kilm2!2Mh+I!c`IoUYD;>A0uW%0%f+?I;j5+j3?e! zS1Y}nU!VO5paOrZy{%2!7&J)MJYN3(k@^*g!dF#QX7V}p(_1AX5)#_)3!}doQ{=cG zm_7cnuwVs;M|m{2jn@XyU%&ZkYG&sAn_G^KIeB>$&$P|@<2e|nHM=7sA_`9sn!h+% z!^a!L`Cx>F!)Py9Fn^?#La_VQc<$XtcLSD~fQ8}#ePvWQ+L=x;F)>jRO3`Z#X_!oY zK+gx5p+<5?=^4MxhMu~&Z`nMxyX58MPHpouk|N9a<+~iMhNLfFzKuYTPlkGWu5_m> z0>@@M@1EW%FPHv|XTAnnd!ZJ+ZnHsU6_qA7e1ox%j?U?xQzGO8`IyFNF^gCDNr-@e zga~tFQxrK-=S2`84%iLj`*kc)s!@5m;(+wz9g`mB=v2X_v=6PV6txuglnUp}K7an~ z@ZEtFNdSY)m4$_yRih(sF^%EBkA^CcZRtuV1ChlrvIU${%dgz42@Lb1CvV`Xd5zn` z@Zl*H1+Pkz)I>$Ebxm>KfwyE4^sA{w0hxmON3J@x(A?+W30t3uNsm(s`! zRJy>hl6Yq4mQm4JRGd^!aq;y*|NeyGv9UIIG(jl23WW+=_$(?y_Ms{*E-LDScyQTu zSa)}~=>3$(k0USL6ssX*Wn`F|-wiCUtF!3=R2}JeFj%X)yu6IhHAs~=Jc(B^3wR?U z(8u%EUJ5^DEN-r4n4#7uY}BA<(eZU;#QGgg4><^XM^1HbIQ)rEQEDoi`85LrdDzL| z^YeltviN~4pxIY211-K)3)m{IRQ1v&08htV+2?*F|xV`;2;O>qR*o|y$@g`gp0kr>X!^6YH^n*h~B5{q=TU_Mi z0zKB{3hT&cN=ix{GX1}eP&$@zmh3JR6=qajXtmS#Sy)+#-3nRc14^3ncIc|?QUKT$ z%%&dOfKSANCdE(q59hSQKhdjO1r&VbpXr&X{C?}`F z%c(lKZfKrm*l}z_f*_o^AQ}M;c#^Qf~xz@C~ykNwFZ%|<1kU#s( z%4jVpQ^mE#{c7y&>_Zh%U|>&Bpw&H|P}z+?nxINf<(3deGpfza%!pv1TK3k0=)toW ziq}7W{FtP^ix-%(XA#r*tlGgzE|ue)g2#NTzH0_1{mDp@B4#X^qprT*`({#eU&ozF z{8Hw@^Dw%~!a`l;KFp=&fr1-r?~>KX?sSa4AzThxpV`{-2aTFOH9h@Rnymq#b24KgleZ=XouM9m#635<&lxV2}r`Z*CiCkHBc&{nAZfuH8K# zk-Q;h=*c=F%--JKX?}6BS@|RfDDS5!DG@H9e`S_Eb?Vf_rLTj7_m|Zp!5apUsyx%) zdTJjm;qZ4=Rrli!wX|BQ&|koy{-T0He%(e*c{#&g8|fx6>X;&!|4xc~ZxCq0!^49r zKIRZ~v_TFzJ_mS3w-Ui@Mxdjki=;`)e)Y-_v)e&-F-C)xm34vwWmES6wpd+V4XS|h zy@bSfuV0%E|7JizU$xjLQM$wcJBrbQ!G05E(tQW3P1Bip4yb@YDvnWXorQXULB%dKyx`5gt%(ZT=yMHlAC#IiFX_sU*^&T2}H}oewBn!<&A#( z7SE^lD&WWVczCboQzO!WD!TTHqSf#7ldIsp6x@VFsYwboIm6G?AUZdZl$G@=q;aBv za{PlXo~a=sX-E{18Ga^iD)6hqUhAZ`+=n#=pAO_L#_D-heG#;y)LNBm5sur+i)ucu z2*d@Ivh*J&17rgxL;csgF2_{D+zOb=9FJiBOm7}&k+>_tOR(b`9k)B4)<*oreg2Gf n{ye{=O$tAr + In order to add the lifting gate feature to a gate, select the game object of the gate and click on *Add Component* in the inspector. Select it by searching or navigating to *Visual Pinball -> Mechs -> Gate Lifter*. ### Lifting Angle diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Gate/GateLifterInspector.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Gate/GateLifterInspector.cs index 33d6c0dcf..a29c266ec 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Gate/GateLifterInspector.cs +++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Gate/GateLifterInspector.cs @@ -35,7 +35,7 @@ public override void OnInspectorGUI() { serializedObject.Update(); - EditorGUILayout.PropertyField(_angleProperty); + EditorGUILayout.PropertyField(_angleProperty, new GUIContent("Lifting Angle")); EditorGUILayout.PropertyField(_speedProperty); serializedObject.ApplyModifiedProperties(); From 3335fa514bd264103a0f1b36f9a6f14c9e06af09 Mon Sep 17 00:00:00 2001 From: freezy Date: Mon, 27 Jun 2022 00:15:12 +0200 Subject: [PATCH 11/12] fix: Address PR comments. --- .../VPT/Gate/GateLifterInspector.cs | 2 +- .../VisualPinball.Unity/Display/ScoreReelComponent.cs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Gate/GateLifterInspector.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Gate/GateLifterInspector.cs index a29c266ec..8d99f35ff 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Gate/GateLifterInspector.cs +++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Gate/GateLifterInspector.cs @@ -35,7 +35,7 @@ public override void OnInspectorGUI() { serializedObject.Update(); - EditorGUILayout.PropertyField(_angleProperty, new GUIContent("Lifting Angle")); + EditorGUILayout.PropertyField(_angleProperty, new GUIContent("Lifted Angle")); EditorGUILayout.PropertyField(_speedProperty); serializedObject.ApplyModifiedProperties(); diff --git a/VisualPinball.Unity/VisualPinball.Unity/Display/ScoreReelComponent.cs b/VisualPinball.Unity/VisualPinball.Unity/Display/ScoreReelComponent.cs index 91f498d45..d0cfbbcc3 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/Display/ScoreReelComponent.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/Display/ScoreReelComponent.cs @@ -25,11 +25,11 @@ public class ScoreReelComponent : MonoBehaviour { public enum ScoreReelDirection { - up, down + Up, Down } [Tooltip("In which direction the reel rotates, when looking from the front.")] - public ScoreReelDirection Direction = ScoreReelDirection.down; + public ScoreReelDirection Direction = ScoreReelDirection.Down; [HideInInspector] public float Speed = 1; @@ -43,7 +43,7 @@ public enum ScoreReelDirection private float _currentRotation; - private bool _isRotatingDown => Direction == ScoreReelDirection.down; + private bool _isRotatingDown => Direction == ScoreReelDirection.Down; public void AnimateTo(int position) { From 5615023af6a8f72a9a5fd23dce47552aaf09d1f4 Mon Sep 17 00:00:00 2001 From: freezy Date: Mon, 27 Jun 2022 00:24:44 +0200 Subject: [PATCH 12/12] doc: Fix typo in URL. --- .../1-prepare-artwork.md | 0 .../2-create-mesh.md | 124 +++++++-------- .../3-uv-map-mesh.md | 142 +++++++++--------- .../4-import-into-unity.md | 0 .../blender-duplicated-surface.png | Bin .../blender-edges-selected.png | Bin .../blender-extrude.png | Bin .../blender-extruded.png | Bin .../blender-material-geometry.png | Bin .../blender-material-slots.png | Bin .../blender-no-lower-bevel.png | Bin .../blender-normals.png | Bin .../blender-poly-reduction.png | Bin .../blender-select-coplanar.png | Bin .../blender-shapes.png | Bin .../blender-triangle-selected-2.png | Bin .../blender-triangle-selected.png | Bin .../blender-triangulated.png | Bin .../blender-uv-mapped.png | Bin .../blender-uv-mapping.png | Bin .../illustrator-export-svg.png | Bin .../illustrator-export-texture.png | Bin .../illustrator-joined-artwork.png | Bin .../illustrator-joined-surfaces.png | Bin .../illustrator-new-document.png | Bin .../illustrator-separate-artwork.png | Bin .../index.md | 0 .../overview.png | Bin .../t2-example.png | Bin .../unity-decal-material-preview.png | Bin .../unity-imported.png | Bin .../unity-textured.png | Bin .../unity-transparent-textured.png | Bin .../unity-transparent.png | Bin 34 files changed, 133 insertions(+), 133 deletions(-) rename VisualPinball.Unity/Documentation~/creators-guide/tutorials/{relatistic-plastics => realistic-plastics}/1-prepare-artwork.md (100%) rename VisualPinball.Unity/Documentation~/creators-guide/tutorials/{relatistic-plastics => realistic-plastics}/2-create-mesh.md (98%) rename VisualPinball.Unity/Documentation~/creators-guide/tutorials/{relatistic-plastics => realistic-plastics}/3-uv-map-mesh.md (98%) rename VisualPinball.Unity/Documentation~/creators-guide/tutorials/{relatistic-plastics => realistic-plastics}/4-import-into-unity.md (100%) rename VisualPinball.Unity/Documentation~/creators-guide/tutorials/{relatistic-plastics => realistic-plastics}/blender-duplicated-surface.png (100%) rename VisualPinball.Unity/Documentation~/creators-guide/tutorials/{relatistic-plastics => realistic-plastics}/blender-edges-selected.png (100%) rename VisualPinball.Unity/Documentation~/creators-guide/tutorials/{relatistic-plastics => realistic-plastics}/blender-extrude.png (100%) rename VisualPinball.Unity/Documentation~/creators-guide/tutorials/{relatistic-plastics => realistic-plastics}/blender-extruded.png (100%) rename VisualPinball.Unity/Documentation~/creators-guide/tutorials/{relatistic-plastics => realistic-plastics}/blender-material-geometry.png (100%) rename VisualPinball.Unity/Documentation~/creators-guide/tutorials/{relatistic-plastics => realistic-plastics}/blender-material-slots.png (100%) rename VisualPinball.Unity/Documentation~/creators-guide/tutorials/{relatistic-plastics => realistic-plastics}/blender-no-lower-bevel.png (100%) rename VisualPinball.Unity/Documentation~/creators-guide/tutorials/{relatistic-plastics => realistic-plastics}/blender-normals.png (100%) rename VisualPinball.Unity/Documentation~/creators-guide/tutorials/{relatistic-plastics => realistic-plastics}/blender-poly-reduction.png (100%) rename VisualPinball.Unity/Documentation~/creators-guide/tutorials/{relatistic-plastics => realistic-plastics}/blender-select-coplanar.png (100%) rename VisualPinball.Unity/Documentation~/creators-guide/tutorials/{relatistic-plastics => realistic-plastics}/blender-shapes.png (100%) rename VisualPinball.Unity/Documentation~/creators-guide/tutorials/{relatistic-plastics => realistic-plastics}/blender-triangle-selected-2.png (100%) rename VisualPinball.Unity/Documentation~/creators-guide/tutorials/{relatistic-plastics => realistic-plastics}/blender-triangle-selected.png (100%) rename VisualPinball.Unity/Documentation~/creators-guide/tutorials/{relatistic-plastics => realistic-plastics}/blender-triangulated.png (100%) rename VisualPinball.Unity/Documentation~/creators-guide/tutorials/{relatistic-plastics => realistic-plastics}/blender-uv-mapped.png (100%) rename VisualPinball.Unity/Documentation~/creators-guide/tutorials/{relatistic-plastics => realistic-plastics}/blender-uv-mapping.png (100%) rename VisualPinball.Unity/Documentation~/creators-guide/tutorials/{relatistic-plastics => realistic-plastics}/illustrator-export-svg.png (100%) rename VisualPinball.Unity/Documentation~/creators-guide/tutorials/{relatistic-plastics => realistic-plastics}/illustrator-export-texture.png (100%) rename VisualPinball.Unity/Documentation~/creators-guide/tutorials/{relatistic-plastics => realistic-plastics}/illustrator-joined-artwork.png (100%) rename VisualPinball.Unity/Documentation~/creators-guide/tutorials/{relatistic-plastics => realistic-plastics}/illustrator-joined-surfaces.png (100%) rename VisualPinball.Unity/Documentation~/creators-guide/tutorials/{relatistic-plastics => realistic-plastics}/illustrator-new-document.png (100%) rename VisualPinball.Unity/Documentation~/creators-guide/tutorials/{relatistic-plastics => realistic-plastics}/illustrator-separate-artwork.png (100%) rename VisualPinball.Unity/Documentation~/creators-guide/tutorials/{relatistic-plastics => realistic-plastics}/index.md (100%) rename VisualPinball.Unity/Documentation~/creators-guide/tutorials/{relatistic-plastics => realistic-plastics}/overview.png (100%) rename VisualPinball.Unity/Documentation~/creators-guide/tutorials/{relatistic-plastics => realistic-plastics}/t2-example.png (100%) rename VisualPinball.Unity/Documentation~/creators-guide/tutorials/{relatistic-plastics => realistic-plastics}/unity-decal-material-preview.png (100%) rename VisualPinball.Unity/Documentation~/creators-guide/tutorials/{relatistic-plastics => realistic-plastics}/unity-imported.png (100%) rename VisualPinball.Unity/Documentation~/creators-guide/tutorials/{relatistic-plastics => realistic-plastics}/unity-textured.png (100%) rename VisualPinball.Unity/Documentation~/creators-guide/tutorials/{relatistic-plastics => realistic-plastics}/unity-transparent-textured.png (100%) rename VisualPinball.Unity/Documentation~/creators-guide/tutorials/{relatistic-plastics => realistic-plastics}/unity-transparent.png (100%) diff --git a/VisualPinball.Unity/Documentation~/creators-guide/tutorials/relatistic-plastics/1-prepare-artwork.md b/VisualPinball.Unity/Documentation~/creators-guide/tutorials/realistic-plastics/1-prepare-artwork.md similarity index 100% rename from VisualPinball.Unity/Documentation~/creators-guide/tutorials/relatistic-plastics/1-prepare-artwork.md rename to VisualPinball.Unity/Documentation~/creators-guide/tutorials/realistic-plastics/1-prepare-artwork.md diff --git a/VisualPinball.Unity/Documentation~/creators-guide/tutorials/relatistic-plastics/2-create-mesh.md b/VisualPinball.Unity/Documentation~/creators-guide/tutorials/realistic-plastics/2-create-mesh.md similarity index 98% rename from VisualPinball.Unity/Documentation~/creators-guide/tutorials/relatistic-plastics/2-create-mesh.md rename to VisualPinball.Unity/Documentation~/creators-guide/tutorials/realistic-plastics/2-create-mesh.md index 40d1ab3b0..1e074cbcb 100644 --- a/VisualPinball.Unity/Documentation~/creators-guide/tutorials/relatistic-plastics/2-create-mesh.md +++ b/VisualPinball.Unity/Documentation~/creators-guide/tutorials/realistic-plastics/2-create-mesh.md @@ -1,62 +1,62 @@ ---- -uid: tutorial_plastics_2 -title: Realistic Looking Plastics - Create Mesh -description: How to create the meshes in Blender ---- - -# Create Mesh - -We're now going to import the SVG created in the [previous step](xref:tutorial_plastics_1) and create a mesh that is beveled on the top. - -## Step 1: Import - -Open Blender, clear the scene with `A`, `X`, `Enter`. Then, click on *File -> Import -> Scalable Vector Graphics (.svg)*, navigate to where you've saved the SVG in the previous step, select `Plastics.svg`, and hit *Import*. - -You might not see much due to the imported size. If there were no errors, you should see your imported plastics in the Outliner. Select them and press `.` on the numpad (not the main keyboard) while hovering over the 3D viewport to zoom in. - -> [!note] -> You might run into another issue due to the size of the plastics: Camera clipping. To fix that, press `N` with your cursor over the 3D Viewport, select *View* and set something like 0.001m for *Clip Start*. - -Your viewport should look like this now: - -![2D Outlines](blender-shapes.png) - -## Step 2: Setup - -The way we're going for this is to extrude and bevel our SVG on one side only. This however results in the bottom faces missing. To fix that, we'll duplicate our SVG and use one for extrusion and the other for the bottom mesh. - -Before we start, let's make it one single object so we can easily apply everything we do in one step. Select one element, hit `A` for select all, then `Ctrl`+`J` for joining all curves. - -Hit `Shift`+`D`, `Esc` to duplicate at the same position. In the *Outliner*, let's name our objects "bottom" and "extruded": - -![Duplicated Surface](blender-duplicated-surface.png) - -## Step 3: Extrude - -Select "extruded" in the outliner and click on the *Object Properties* tab in the *Properties* view on the right side. Under *Geometry*, there is an *Extrude* field, and a bit below a *Bevel* section. - -Now, the *Extrude* value is difficult to judge. If you have access to the physical plastics, you can calculate the scale between the real world and the object in Blender by physically measuring the size of a plastic and dividing it by the [measured value](https://docs.blender.org/manual/en/latest/editors/3dview/toolbar/measure.html) in Blender. Then, also measure the thickness of the real-world plastic and multiply it by that factor. Personally, I just eyeballed it and ended up with 0.003 m for the *Extrude* value and 0.001 m for the *Bevel Depth*. - -Then there are three more properties to change: - -- We only want to extrude the front, so set *Fill Mode* to *Front*. -- We don't want to make the object larger by beveling, so enter the negative value of the bevel depth under *Offset*. -- Finally, a *Resolution* of `0` will do. - -Here are all the non-default options in red: - -![Extrude Parameters](blender-extrude.png) - -## Step 4: Convert, Join and Clean - -As seen in the previous screenshot, our bottom object now sits in the middle of the extruded mesh. Let's fix that by typing `G` (move), `Z` (on z-axis only), and the extrude value of the previous step, in our case `0.003`, followed by `Enter`. - -Then type `A` to select all objects, choose *Object -> Convert -> Mesh*, and hit `Ctrl`+`J` to join them all. Finally, clean up the duplicated vertices from the extrusion by hitting `Tab` for edit mode, `A` to select all vertices, and choose *Mesh -> Clean Up -> Merge by Distance*. - -Exit edit mode and this is how it should look: - -![Extruded Shapes](blender-extruded.png) - -If that's the case, congrats, you're done with the meshes! Maybe now it's a good moment to save your Blender file. `Ctrl`+`S` and enter `Plastics.blend`. - -In the [next part](xref:tutorial_plastics_3) of this tutorial, we're going to UV-Map them. +--- +uid: tutorial_plastics_2 +title: Realistic Looking Plastics - Create Mesh +description: How to create the meshes in Blender +--- + +# Create Mesh + +We're now going to import the SVG created in the [previous step](xref:tutorial_plastics_1) and create a mesh that is beveled on the top. + +## Step 1: Import + +Open Blender, clear the scene with `A`, `X`, `Enter`. Then, click on *File -> Import -> Scalable Vector Graphics (.svg)*, navigate to where you've saved the SVG in the previous step, select `Plastics.svg`, and hit *Import*. + +You might not see much due to the imported size. If there were no errors, you should see your imported plastics in the Outliner. Select them and press `.` on the numpad (not the main keyboard) while hovering over the 3D viewport to zoom in. + +> [!note] +> You might run into another issue due to the size of the plastics: Camera clipping. To fix that, press `N` with your cursor over the 3D Viewport, select *View* and set something like 0.001m for *Clip Start*. + +Your viewport should look like this now: + +![2D Outlines](blender-shapes.png) + +## Step 2: Setup + +The way we're going for this is to extrude and bevel our SVG on one side only. This however results in the bottom faces missing. To fix that, we'll duplicate our SVG and use one for extrusion and the other for the bottom mesh. + +Before we start, let's make it one single object so we can easily apply everything we do in one step. Select one element, hit `A` for select all, then `Ctrl`+`J` for joining all curves. + +Hit `Shift`+`D`, `Esc` to duplicate at the same position. In the *Outliner*, let's name our objects "bottom" and "extruded": + +![Duplicated Surface](blender-duplicated-surface.png) + +## Step 3: Extrude + +Select "extruded" in the outliner and click on the *Object Properties* tab in the *Properties* view on the right side. Under *Geometry*, there is an *Extrude* field, and a bit below a *Bevel* section. + +Now, the *Extrude* value is difficult to judge. If you have access to the physical plastics, you can calculate the scale between the real world and the object in Blender by physically measuring the size of a plastic and dividing it by the [measured value](https://docs.blender.org/manual/en/latest/editors/3dview/toolbar/measure.html) in Blender. Then, also measure the thickness of the real-world plastic and multiply it by that factor. Personally, I just eyeballed it and ended up with 0.003 m for the *Extrude* value and 0.001 m for the *Bevel Depth*. + +Then there are three more properties to change: + +- We only want to extrude the front, so set *Fill Mode* to *Front*. +- We don't want to make the object larger by beveling, so enter the negative value of the bevel depth under *Offset*. +- Finally, a *Resolution* of `0` will do. + +Here are all the non-default options in red: + +![Extrude Parameters](blender-extrude.png) + +## Step 4: Convert, Join and Clean + +As seen in the previous screenshot, our bottom object now sits in the middle of the extruded mesh. Let's fix that by typing `G` (move), `Z` (on z-axis only), and the extrude value of the previous step, in our case `0.003`, followed by `Enter`. + +Then type `A` to select all objects, choose *Object -> Convert -> Mesh*, and hit `Ctrl`+`J` to join them all. Finally, clean up the duplicated vertices from the extrusion by hitting `Tab` for edit mode, `A` to select all vertices, and choose *Mesh -> Clean Up -> Merge by Distance*. + +Exit edit mode and this is how it should look: + +![Extruded Shapes](blender-extruded.png) + +If that's the case, congrats, you're done with the meshes! Maybe now it's a good moment to save your Blender file. `Ctrl`+`S` and enter `Plastics.blend`. + +In the [next part](xref:tutorial_plastics_3) of this tutorial, we're going to UV-Map them. diff --git a/VisualPinball.Unity/Documentation~/creators-guide/tutorials/relatistic-plastics/3-uv-map-mesh.md b/VisualPinball.Unity/Documentation~/creators-guide/tutorials/realistic-plastics/3-uv-map-mesh.md similarity index 98% rename from VisualPinball.Unity/Documentation~/creators-guide/tutorials/relatistic-plastics/3-uv-map-mesh.md rename to VisualPinball.Unity/Documentation~/creators-guide/tutorials/realistic-plastics/3-uv-map-mesh.md index 20d7bf34f..04853325d 100644 --- a/VisualPinball.Unity/Documentation~/creators-guide/tutorials/relatistic-plastics/3-uv-map-mesh.md +++ b/VisualPinball.Unity/Documentation~/creators-guide/tutorials/realistic-plastics/3-uv-map-mesh.md @@ -1,71 +1,71 @@ ---- -uid: tutorial_plastics_3 -title: Realistic Looking Plastics - UV-Map Mesh -description: How to UV-map the texture onto your mesh in Blender ---- - -# UV-Map Mesh - - -## Step 1: Create Material Slots - - We need three material slots, for the top and bottom faces, as well as for the edges. We'll split the vertices by firstly assigning everything to an "edge" slot, and then re-assigning the top and bottom faces to their own slots. - - - -In object mode, open *Materials* properties and remove the current material slot (hit `-`). Add three new slots (press 3× `+`), and for each slot, create a new material by hitting the *New* button when the slot is selected. Name them "top", "bottom" and "edge" and set their base color to red, green, and blue respectively. Your slots should now look like in the screenshot. - -Set the 3D viewport to *Material Preview*. Select your mesh, press `Tab` to switch to edit mode. Press `A` to select all vertices, select the "edge" material slot, and hit *Assign*. Your plastics should turn blue. Press `A` twice to deselect everything. - -Then, press `7` on the numpad to switch to top view, zoom in a bit so you can clearly see the triangles, switch to *Face Select* and click on one face of the top surface: - -![Triangle selected](blender-triangle-selected-2.png) - - - -Click on *Select -> Select Similar -> Coplanar*, which should result in all top faces of all plastics being selected (but *not* the bottoms ones). However, you might get the bottom faces selected too, because there's a threshold that might be too large. You can check it by rotating the camera and verify that the bottom faces are not selected. If they are, expand the parameters and set the threshold to a small enough value. Then, select the "top" material slot and hit *Assign*. The top surfaces should turn red. - -For the bottom faces, hit `7`, `9` on the numpad to switch to bottom view, and select again one face. Like before, select all coplanar faces, click the "bottom" material slot, and *Assign*. You should see the bottom faces turn green. - -Now, the "edges" material slot should only contain the edges. Check by unselecting all (`A` `A`), then selecting the "edge" material slot and hitting *Select*. This should only select the edges, like here: - -![Edges selected](blender-edges-selected.png) - -Your meshes should now be colored like this (from top / bottom): - -![Selecting edges](blender-material-geometry.png) - -## Step 2: UV-Map - -Switch to the *UV Editing* workspace. In the left *UV Editor*, choose *Image -> Open*, and select the exported `Plastic-01.png` you've created in part one. On the right, enter edit mode, click on the "top" material slot in the *Materials* property tab, and hit *Select*. Click on "bottom" and then on *Select* again. - -From the *UV* menu, select *Cube Projection*. Move your cursor to the left view and press `A`. You should see both the top and bottom surfaces projected onto your texture: - -![UV Mapping in Blender](blender-uv-mapping.png) - -We're now going to align the projection with the texture. You can do that by using the `G` and `S` keys. What's important is to align the **outer** contour with the texture, like so: - -![UV mapped correctly](blender-uv-mapped.png) - -## Step 3: Prepare and Export - -Once done, switch back to the *Layout* workspace. Before we export, there's still a bit of a clean up to do. In edit mode, hit `A` to select all and choose *Mesh -> Clean Up -> Limited Dissolve*. Exit edit mode, go to *Modifier Properties*, add the *Triangulate* modifier, and hit `Ctrl`+`A` to apply. - -What we just did reduced the complexity of our topology. We triangulate at the end to avoid problems during export. - -![Reduced polygons](blender-poly-reduction.png) - -From left to right: -- Original (102k vertices, 44k triangles) -- After limited dissolve (66k vertices, 30k triangles, but errors in mesh) -- After triangulation (66k vertices, 30k triangles) - -Switch to the *Object Data* properties, and under *Normals*, enable *Auto Smooth*. This will properly align the normals on the bevel side, giving it a more realistic refraction effect. - -We still have one single object, so before exporting, let's split it. In edit mode, hit `A` to select all and choose *Mesh -> Separate -> By Loose Parts*. Before exporting, feel free to rename your objects in the Outliner, it's what you'll see in Unity. - -Lastly, in object mode, hit `A` to select all objects and click on *Object -> Set Origin -> Origin to Geometry*. This will set the local origin of each object to the object itself, making it easier to place it. - -Export the plastics by selecting *File -> Export -> FBX*. Name it `Plastics.fbx` and hit *Export FBX*. - -Now let's [import this into Unity](xref:tutorial_plastics_4)! +--- +uid: tutorial_plastics_3 +title: Realistic Looking Plastics - UV-Map Mesh +description: How to UV-map the texture onto your mesh in Blender +--- + +# UV-Map Mesh + + +## Step 1: Create Material Slots + + We need three material slots, for the top and bottom faces, as well as for the edges. We'll split the vertices by firstly assigning everything to an "edge" slot, and then re-assigning the top and bottom faces to their own slots. + + + +In object mode, open *Materials* properties and remove the current material slot (hit `-`). Add three new slots (press 3× `+`), and for each slot, create a new material by hitting the *New* button when the slot is selected. Name them "top", "bottom" and "edge" and set their base color to red, green, and blue respectively. Your slots should now look like in the screenshot. + +Set the 3D viewport to *Material Preview*. Select your mesh, press `Tab` to switch to edit mode. Press `A` to select all vertices, select the "edge" material slot, and hit *Assign*. Your plastics should turn blue. Press `A` twice to deselect everything. + +Then, press `7` on the numpad to switch to top view, zoom in a bit so you can clearly see the triangles, switch to *Face Select* and click on one face of the top surface: + +![Triangle selected](blender-triangle-selected-2.png) + + + +Click on *Select -> Select Similar -> Coplanar*, which should result in all top faces of all plastics being selected (but *not* the bottoms ones). However, you might get the bottom faces selected too, because there's a threshold that might be too large. You can check it by rotating the camera and verify that the bottom faces are not selected. If they are, expand the parameters and set the threshold to a small enough value. Then, select the "top" material slot and hit *Assign*. The top surfaces should turn red. + +For the bottom faces, hit `7`, `9` on the numpad to switch to bottom view, and select again one face. Like before, select all coplanar faces, click the "bottom" material slot, and *Assign*. You should see the bottom faces turn green. + +Now, the "edges" material slot should only contain the edges. Check by unselecting all (`A` `A`), then selecting the "edge" material slot and hitting *Select*. This should only select the edges, like here: + +![Edges selected](blender-edges-selected.png) + +Your meshes should now be colored like this (from top / bottom): + +![Selecting edges](blender-material-geometry.png) + +## Step 2: UV-Map + +Switch to the *UV Editing* workspace. In the left *UV Editor*, choose *Image -> Open*, and select the exported `Plastic-01.png` you've created in part one. On the right, enter edit mode, click on the "top" material slot in the *Materials* property tab, and hit *Select*. Click on "bottom" and then on *Select* again. + +From the *UV* menu, select *Cube Projection*. Move your cursor to the left view and press `A`. You should see both the top and bottom surfaces projected onto your texture: + +![UV Mapping in Blender](blender-uv-mapping.png) + +We're now going to align the projection with the texture. You can do that by using the `G` and `S` keys. What's important is to align the **outer** contour with the texture, like so: + +![UV mapped correctly](blender-uv-mapped.png) + +## Step 3: Prepare and Export + +Once done, switch back to the *Layout* workspace. Before we export, there's still a bit of a clean up to do. In edit mode, hit `A` to select all and choose *Mesh -> Clean Up -> Limited Dissolve*. Exit edit mode, go to *Modifier Properties*, add the *Triangulate* modifier, and hit `Ctrl`+`A` to apply. + +What we just did reduced the complexity of our topology. We triangulate at the end to avoid problems during export. + +![Reduced polygons](blender-poly-reduction.png) + +From left to right: +- Original (102k vertices, 44k triangles) +- After limited dissolve (66k vertices, 30k triangles, but errors in mesh) +- After triangulation (66k vertices, 30k triangles) + +Switch to the *Object Data* properties, and under *Normals*, enable *Auto Smooth*. This will properly align the normals on the bevel side, giving it a more realistic refraction effect. + +We still have one single object, so before exporting, let's split it. In edit mode, hit `A` to select all and choose *Mesh -> Separate -> By Loose Parts*. Before exporting, feel free to rename your objects in the Outliner, it's what you'll see in Unity. + +Lastly, in object mode, hit `A` to select all objects and click on *Object -> Set Origin -> Origin to Geometry*. This will set the local origin of each object to the object itself, making it easier to place it. + +Export the plastics by selecting *File -> Export -> FBX*. Name it `Plastics.fbx` and hit *Export FBX*. + +Now let's [import this into Unity](xref:tutorial_plastics_4)! diff --git a/VisualPinball.Unity/Documentation~/creators-guide/tutorials/relatistic-plastics/4-import-into-unity.md b/VisualPinball.Unity/Documentation~/creators-guide/tutorials/realistic-plastics/4-import-into-unity.md similarity index 100% rename from VisualPinball.Unity/Documentation~/creators-guide/tutorials/relatistic-plastics/4-import-into-unity.md rename to VisualPinball.Unity/Documentation~/creators-guide/tutorials/realistic-plastics/4-import-into-unity.md diff --git a/VisualPinball.Unity/Documentation~/creators-guide/tutorials/relatistic-plastics/blender-duplicated-surface.png b/VisualPinball.Unity/Documentation~/creators-guide/tutorials/realistic-plastics/blender-duplicated-surface.png similarity index 100% rename from VisualPinball.Unity/Documentation~/creators-guide/tutorials/relatistic-plastics/blender-duplicated-surface.png rename to VisualPinball.Unity/Documentation~/creators-guide/tutorials/realistic-plastics/blender-duplicated-surface.png diff --git a/VisualPinball.Unity/Documentation~/creators-guide/tutorials/relatistic-plastics/blender-edges-selected.png b/VisualPinball.Unity/Documentation~/creators-guide/tutorials/realistic-plastics/blender-edges-selected.png similarity index 100% rename from VisualPinball.Unity/Documentation~/creators-guide/tutorials/relatistic-plastics/blender-edges-selected.png rename to VisualPinball.Unity/Documentation~/creators-guide/tutorials/realistic-plastics/blender-edges-selected.png diff --git a/VisualPinball.Unity/Documentation~/creators-guide/tutorials/relatistic-plastics/blender-extrude.png b/VisualPinball.Unity/Documentation~/creators-guide/tutorials/realistic-plastics/blender-extrude.png similarity index 100% rename from VisualPinball.Unity/Documentation~/creators-guide/tutorials/relatistic-plastics/blender-extrude.png rename to VisualPinball.Unity/Documentation~/creators-guide/tutorials/realistic-plastics/blender-extrude.png diff --git a/VisualPinball.Unity/Documentation~/creators-guide/tutorials/relatistic-plastics/blender-extruded.png b/VisualPinball.Unity/Documentation~/creators-guide/tutorials/realistic-plastics/blender-extruded.png similarity index 100% rename from VisualPinball.Unity/Documentation~/creators-guide/tutorials/relatistic-plastics/blender-extruded.png rename to VisualPinball.Unity/Documentation~/creators-guide/tutorials/realistic-plastics/blender-extruded.png diff --git a/VisualPinball.Unity/Documentation~/creators-guide/tutorials/relatistic-plastics/blender-material-geometry.png b/VisualPinball.Unity/Documentation~/creators-guide/tutorials/realistic-plastics/blender-material-geometry.png similarity index 100% rename from VisualPinball.Unity/Documentation~/creators-guide/tutorials/relatistic-plastics/blender-material-geometry.png rename to VisualPinball.Unity/Documentation~/creators-guide/tutorials/realistic-plastics/blender-material-geometry.png diff --git a/VisualPinball.Unity/Documentation~/creators-guide/tutorials/relatistic-plastics/blender-material-slots.png b/VisualPinball.Unity/Documentation~/creators-guide/tutorials/realistic-plastics/blender-material-slots.png similarity index 100% rename from VisualPinball.Unity/Documentation~/creators-guide/tutorials/relatistic-plastics/blender-material-slots.png rename to VisualPinball.Unity/Documentation~/creators-guide/tutorials/realistic-plastics/blender-material-slots.png diff --git a/VisualPinball.Unity/Documentation~/creators-guide/tutorials/relatistic-plastics/blender-no-lower-bevel.png b/VisualPinball.Unity/Documentation~/creators-guide/tutorials/realistic-plastics/blender-no-lower-bevel.png similarity index 100% rename from VisualPinball.Unity/Documentation~/creators-guide/tutorials/relatistic-plastics/blender-no-lower-bevel.png rename to VisualPinball.Unity/Documentation~/creators-guide/tutorials/realistic-plastics/blender-no-lower-bevel.png diff --git a/VisualPinball.Unity/Documentation~/creators-guide/tutorials/relatistic-plastics/blender-normals.png b/VisualPinball.Unity/Documentation~/creators-guide/tutorials/realistic-plastics/blender-normals.png similarity index 100% rename from VisualPinball.Unity/Documentation~/creators-guide/tutorials/relatistic-plastics/blender-normals.png rename to VisualPinball.Unity/Documentation~/creators-guide/tutorials/realistic-plastics/blender-normals.png diff --git a/VisualPinball.Unity/Documentation~/creators-guide/tutorials/relatistic-plastics/blender-poly-reduction.png b/VisualPinball.Unity/Documentation~/creators-guide/tutorials/realistic-plastics/blender-poly-reduction.png similarity index 100% rename from VisualPinball.Unity/Documentation~/creators-guide/tutorials/relatistic-plastics/blender-poly-reduction.png rename to VisualPinball.Unity/Documentation~/creators-guide/tutorials/realistic-plastics/blender-poly-reduction.png diff --git a/VisualPinball.Unity/Documentation~/creators-guide/tutorials/relatistic-plastics/blender-select-coplanar.png b/VisualPinball.Unity/Documentation~/creators-guide/tutorials/realistic-plastics/blender-select-coplanar.png similarity index 100% rename from VisualPinball.Unity/Documentation~/creators-guide/tutorials/relatistic-plastics/blender-select-coplanar.png rename to VisualPinball.Unity/Documentation~/creators-guide/tutorials/realistic-plastics/blender-select-coplanar.png diff --git a/VisualPinball.Unity/Documentation~/creators-guide/tutorials/relatistic-plastics/blender-shapes.png b/VisualPinball.Unity/Documentation~/creators-guide/tutorials/realistic-plastics/blender-shapes.png similarity index 100% rename from VisualPinball.Unity/Documentation~/creators-guide/tutorials/relatistic-plastics/blender-shapes.png rename to VisualPinball.Unity/Documentation~/creators-guide/tutorials/realistic-plastics/blender-shapes.png diff --git a/VisualPinball.Unity/Documentation~/creators-guide/tutorials/relatistic-plastics/blender-triangle-selected-2.png b/VisualPinball.Unity/Documentation~/creators-guide/tutorials/realistic-plastics/blender-triangle-selected-2.png similarity index 100% rename from VisualPinball.Unity/Documentation~/creators-guide/tutorials/relatistic-plastics/blender-triangle-selected-2.png rename to VisualPinball.Unity/Documentation~/creators-guide/tutorials/realistic-plastics/blender-triangle-selected-2.png diff --git a/VisualPinball.Unity/Documentation~/creators-guide/tutorials/relatistic-plastics/blender-triangle-selected.png b/VisualPinball.Unity/Documentation~/creators-guide/tutorials/realistic-plastics/blender-triangle-selected.png similarity index 100% rename from VisualPinball.Unity/Documentation~/creators-guide/tutorials/relatistic-plastics/blender-triangle-selected.png rename to VisualPinball.Unity/Documentation~/creators-guide/tutorials/realistic-plastics/blender-triangle-selected.png diff --git a/VisualPinball.Unity/Documentation~/creators-guide/tutorials/relatistic-plastics/blender-triangulated.png b/VisualPinball.Unity/Documentation~/creators-guide/tutorials/realistic-plastics/blender-triangulated.png similarity index 100% rename from VisualPinball.Unity/Documentation~/creators-guide/tutorials/relatistic-plastics/blender-triangulated.png rename to VisualPinball.Unity/Documentation~/creators-guide/tutorials/realistic-plastics/blender-triangulated.png diff --git a/VisualPinball.Unity/Documentation~/creators-guide/tutorials/relatistic-plastics/blender-uv-mapped.png b/VisualPinball.Unity/Documentation~/creators-guide/tutorials/realistic-plastics/blender-uv-mapped.png similarity index 100% rename from VisualPinball.Unity/Documentation~/creators-guide/tutorials/relatistic-plastics/blender-uv-mapped.png rename to VisualPinball.Unity/Documentation~/creators-guide/tutorials/realistic-plastics/blender-uv-mapped.png diff --git a/VisualPinball.Unity/Documentation~/creators-guide/tutorials/relatistic-plastics/blender-uv-mapping.png b/VisualPinball.Unity/Documentation~/creators-guide/tutorials/realistic-plastics/blender-uv-mapping.png similarity index 100% rename from VisualPinball.Unity/Documentation~/creators-guide/tutorials/relatistic-plastics/blender-uv-mapping.png rename to VisualPinball.Unity/Documentation~/creators-guide/tutorials/realistic-plastics/blender-uv-mapping.png diff --git a/VisualPinball.Unity/Documentation~/creators-guide/tutorials/relatistic-plastics/illustrator-export-svg.png b/VisualPinball.Unity/Documentation~/creators-guide/tutorials/realistic-plastics/illustrator-export-svg.png similarity index 100% rename from VisualPinball.Unity/Documentation~/creators-guide/tutorials/relatistic-plastics/illustrator-export-svg.png rename to VisualPinball.Unity/Documentation~/creators-guide/tutorials/realistic-plastics/illustrator-export-svg.png diff --git a/VisualPinball.Unity/Documentation~/creators-guide/tutorials/relatistic-plastics/illustrator-export-texture.png b/VisualPinball.Unity/Documentation~/creators-guide/tutorials/realistic-plastics/illustrator-export-texture.png similarity index 100% rename from VisualPinball.Unity/Documentation~/creators-guide/tutorials/relatistic-plastics/illustrator-export-texture.png rename to VisualPinball.Unity/Documentation~/creators-guide/tutorials/realistic-plastics/illustrator-export-texture.png diff --git a/VisualPinball.Unity/Documentation~/creators-guide/tutorials/relatistic-plastics/illustrator-joined-artwork.png b/VisualPinball.Unity/Documentation~/creators-guide/tutorials/realistic-plastics/illustrator-joined-artwork.png similarity index 100% rename from VisualPinball.Unity/Documentation~/creators-guide/tutorials/relatistic-plastics/illustrator-joined-artwork.png rename to VisualPinball.Unity/Documentation~/creators-guide/tutorials/realistic-plastics/illustrator-joined-artwork.png diff --git a/VisualPinball.Unity/Documentation~/creators-guide/tutorials/relatistic-plastics/illustrator-joined-surfaces.png b/VisualPinball.Unity/Documentation~/creators-guide/tutorials/realistic-plastics/illustrator-joined-surfaces.png similarity index 100% rename from VisualPinball.Unity/Documentation~/creators-guide/tutorials/relatistic-plastics/illustrator-joined-surfaces.png rename to VisualPinball.Unity/Documentation~/creators-guide/tutorials/realistic-plastics/illustrator-joined-surfaces.png diff --git a/VisualPinball.Unity/Documentation~/creators-guide/tutorials/relatistic-plastics/illustrator-new-document.png b/VisualPinball.Unity/Documentation~/creators-guide/tutorials/realistic-plastics/illustrator-new-document.png similarity index 100% rename from VisualPinball.Unity/Documentation~/creators-guide/tutorials/relatistic-plastics/illustrator-new-document.png rename to VisualPinball.Unity/Documentation~/creators-guide/tutorials/realistic-plastics/illustrator-new-document.png diff --git a/VisualPinball.Unity/Documentation~/creators-guide/tutorials/relatistic-plastics/illustrator-separate-artwork.png b/VisualPinball.Unity/Documentation~/creators-guide/tutorials/realistic-plastics/illustrator-separate-artwork.png similarity index 100% rename from VisualPinball.Unity/Documentation~/creators-guide/tutorials/relatistic-plastics/illustrator-separate-artwork.png rename to VisualPinball.Unity/Documentation~/creators-guide/tutorials/realistic-plastics/illustrator-separate-artwork.png diff --git a/VisualPinball.Unity/Documentation~/creators-guide/tutorials/relatistic-plastics/index.md b/VisualPinball.Unity/Documentation~/creators-guide/tutorials/realistic-plastics/index.md similarity index 100% rename from VisualPinball.Unity/Documentation~/creators-guide/tutorials/relatistic-plastics/index.md rename to VisualPinball.Unity/Documentation~/creators-guide/tutorials/realistic-plastics/index.md diff --git a/VisualPinball.Unity/Documentation~/creators-guide/tutorials/relatistic-plastics/overview.png b/VisualPinball.Unity/Documentation~/creators-guide/tutorials/realistic-plastics/overview.png similarity index 100% rename from VisualPinball.Unity/Documentation~/creators-guide/tutorials/relatistic-plastics/overview.png rename to VisualPinball.Unity/Documentation~/creators-guide/tutorials/realistic-plastics/overview.png diff --git a/VisualPinball.Unity/Documentation~/creators-guide/tutorials/relatistic-plastics/t2-example.png b/VisualPinball.Unity/Documentation~/creators-guide/tutorials/realistic-plastics/t2-example.png similarity index 100% rename from VisualPinball.Unity/Documentation~/creators-guide/tutorials/relatistic-plastics/t2-example.png rename to VisualPinball.Unity/Documentation~/creators-guide/tutorials/realistic-plastics/t2-example.png diff --git a/VisualPinball.Unity/Documentation~/creators-guide/tutorials/relatistic-plastics/unity-decal-material-preview.png b/VisualPinball.Unity/Documentation~/creators-guide/tutorials/realistic-plastics/unity-decal-material-preview.png similarity index 100% rename from VisualPinball.Unity/Documentation~/creators-guide/tutorials/relatistic-plastics/unity-decal-material-preview.png rename to VisualPinball.Unity/Documentation~/creators-guide/tutorials/realistic-plastics/unity-decal-material-preview.png diff --git a/VisualPinball.Unity/Documentation~/creators-guide/tutorials/relatistic-plastics/unity-imported.png b/VisualPinball.Unity/Documentation~/creators-guide/tutorials/realistic-plastics/unity-imported.png similarity index 100% rename from VisualPinball.Unity/Documentation~/creators-guide/tutorials/relatistic-plastics/unity-imported.png rename to VisualPinball.Unity/Documentation~/creators-guide/tutorials/realistic-plastics/unity-imported.png diff --git a/VisualPinball.Unity/Documentation~/creators-guide/tutorials/relatistic-plastics/unity-textured.png b/VisualPinball.Unity/Documentation~/creators-guide/tutorials/realistic-plastics/unity-textured.png similarity index 100% rename from VisualPinball.Unity/Documentation~/creators-guide/tutorials/relatistic-plastics/unity-textured.png rename to VisualPinball.Unity/Documentation~/creators-guide/tutorials/realistic-plastics/unity-textured.png diff --git a/VisualPinball.Unity/Documentation~/creators-guide/tutorials/relatistic-plastics/unity-transparent-textured.png b/VisualPinball.Unity/Documentation~/creators-guide/tutorials/realistic-plastics/unity-transparent-textured.png similarity index 100% rename from VisualPinball.Unity/Documentation~/creators-guide/tutorials/relatistic-plastics/unity-transparent-textured.png rename to VisualPinball.Unity/Documentation~/creators-guide/tutorials/realistic-plastics/unity-transparent-textured.png diff --git a/VisualPinball.Unity/Documentation~/creators-guide/tutorials/relatistic-plastics/unity-transparent.png b/VisualPinball.Unity/Documentation~/creators-guide/tutorials/realistic-plastics/unity-transparent.png similarity index 100% rename from VisualPinball.Unity/Documentation~/creators-guide/tutorials/relatistic-plastics/unity-transparent.png rename to VisualPinball.Unity/Documentation~/creators-guide/tutorials/realistic-plastics/unity-transparent.png