diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index e65f9b2ed..c5e22d5a9 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -61,7 +61,7 @@ jobs:
- uses: game-ci/unity-test-runner@main
id: test
with:
- unityVersion: '2020.3.13f1'
+ unityVersion: '2021.2.0f1'
projectPath: VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~
artifactsPath: VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/artifacts
testMode: all
diff --git a/CHANGELOG.md b/CHANGELOG.md
index f2ff87577..4d6f5e983 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,11 +4,12 @@
## Unreleased
-Built with Unity 2020.3.
+Built with Unity 2021.2.
### Added
-- A *Teleporter* component ([#336](https://github.com/freezy/VisualPinball.Engine/pull/336), [Documentation](https://docs.visualpinball.org/creators-guide/manual/mechanisms/drop-target-banks.html)).
-- A *Drop Target Bank* component ([#333](https://github.com/freezy/VisualPinball.Engine/pull/333), [Documentation](https://docs.visualpinball.org/creators-guide/manual/mechanisms/teleporters.html)).
+- A *Rotator* component ([#337](https://github.com/freezy/VisualPinball.Engine/pull/337), [Documentation](https://docs.visualpinball.org/creators-guide/manual/mechanisms/rotators.html)).
+- A *Teleporter* component ([#336](https://github.com/freezy/VisualPinball.Engine/pull/336), [Documentation](https://docs.visualpinball.org/creators-guide/manual/mechanisms/teleporters.html)).
+- A *Drop Target Bank* component ([#333](https://github.com/freezy/VisualPinball.Engine/pull/333), [Documentation](https://docs.visualpinball.org/creators-guide/manual/mechanisms/drop-target-banks.html)).
- Editor: Enable manual trigger for coils, switches, lamps and wires during gameplay ([#332](https://github.com/freezy/VisualPinball.Engine/pull/332))
- Support for dynamic wires, also known as *Fast Flip* ([#330](https://github.com/freezy/VisualPinball.Engine/pull/330), [Documentation](https://docs.visualpinball.org/creators-guide/editor/wire-manager.html#dynamic)).
- Component for light groups, allowing easy grouping of GI lamps. ([#330](https://github.com/freezy/VisualPinball.Engine/pull/330) [Documentation](https://docs.visualpinball.org/creators-guide/manual/mechanisms/light-groups.html)).
diff --git a/VisualPinball.Engine.Test/VPT/Kicker/KickerDataTests.cs b/VisualPinball.Engine.Test/VPT/Kicker/KickerDataTests.cs
index ac999b7ac..ba3eccee6 100644
--- a/VisualPinball.Engine.Test/VPT/Kicker/KickerDataTests.cs
+++ b/VisualPinball.Engine.Test/VPT/Kicker/KickerDataTests.cs
@@ -59,11 +59,6 @@ public static void ValidateKickerData(KickerData data)
data.Radius.Should().Be(25.98f);
data.Scatter.Should().Be(4.98f);
data.Surface.Should().Be("");
-
- #if !WRITE_VP106 && !WRITE_VP107
- data.Angle.Should().Be(65.5f);
- data.Speed.Should().Be(5.8f);
- #endif
}
}
}
diff --git a/VisualPinball.Engine/VPT/Kicker/KickerData.cs b/VisualPinball.Engine/VPT/Kicker/KickerData.cs
index 3ae94ca6d..ea9e8658e 100644
--- a/VisualPinball.Engine/VPT/Kicker/KickerData.cs
+++ b/VisualPinball.Engine/VPT/Kicker/KickerData.cs
@@ -82,16 +82,6 @@ public class KickerData : ItemData
[BiffInt("TMIN", Pos = 4)]
public int TimerInterval;
- // -----------------
- // new fields by VPE
- // -----------------
-
- [BiffFloat("ANGL", Pos = 16, SkipHash = true, IsVpeEnhancement = true)]
- public float Angle = 90f;
-
- [BiffFloat("SPED", Pos = 17, SkipHash = true, IsVpeEnhancement = true)]
- public float Speed = 3f;
-
public KickerData() : base(StoragePrefix.GameItem)
{
}
diff --git a/VisualPinball.Unity/Assets/Editor/Icons/large_blue/mech.png b/VisualPinball.Unity/Assets/Editor/Icons/large_blue/mech.png
new file mode 100644
index 000000000..7fbba49f9
Binary files /dev/null and b/VisualPinball.Unity/Assets/Editor/Icons/large_blue/mech.png differ
diff --git a/VisualPinball.Unity/Assets/Editor/Icons/large_blue/mech.png.meta b/VisualPinball.Unity/Assets/Editor/Icons/large_blue/mech.png.meta
new file mode 100644
index 000000000..5d155a34d
--- /dev/null
+++ b/VisualPinball.Unity/Assets/Editor/Icons/large_blue/mech.png.meta
@@ -0,0 +1,122 @@
+fileFormatVersion: 2
+guid: f69f70377ba5a2849b6315198ec065d9
+TextureImporter:
+ internalIDToNameTable: []
+ externalObjects: {}
+ serializedVersion: 11
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 1
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 1
+ 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: 0
+ wrapV: 0
+ wrapW: 0
+ nPOTScale: 1
+ 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: 0
+ textureShape: 1
+ singleChannelComponent: 0
+ flipbookRows: 1
+ flipbookColumns: 1
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ ignorePngGamma: 0
+ applyGammaDecoding: 0
+ platformSettings:
+ - serializedVersion: 3
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: 512
+ 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/large_blue/rotator.png b/VisualPinball.Unity/Assets/Editor/Icons/large_blue/rotator.png
new file mode 100644
index 000000000..fed47cee4
Binary files /dev/null and b/VisualPinball.Unity/Assets/Editor/Icons/large_blue/rotator.png differ
diff --git a/VisualPinball.Unity/Assets/Editor/Icons/large_blue/rotator.png.meta b/VisualPinball.Unity/Assets/Editor/Icons/large_blue/rotator.png.meta
new file mode 100644
index 000000000..aa28282a9
--- /dev/null
+++ b/VisualPinball.Unity/Assets/Editor/Icons/large_blue/rotator.png.meta
@@ -0,0 +1,122 @@
+fileFormatVersion: 2
+guid: 11819c15d4e1ce443bb97ec0f8830302
+TextureImporter:
+ internalIDToNameTable: []
+ externalObjects: {}
+ serializedVersion: 11
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 1
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 1
+ 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: 0
+ wrapV: 0
+ wrapW: 0
+ nPOTScale: 1
+ 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: 0
+ textureShape: 1
+ singleChannelComponent: 0
+ flipbookRows: 1
+ flipbookColumns: 1
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ ignorePngGamma: 0
+ applyGammaDecoding: 0
+ platformSettings:
+ - serializedVersion: 3
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: 512
+ 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/large_gray/mech.png b/VisualPinball.Unity/Assets/Editor/Icons/large_gray/mech.png
new file mode 100644
index 000000000..421cd7246
Binary files /dev/null and b/VisualPinball.Unity/Assets/Editor/Icons/large_gray/mech.png differ
diff --git a/VisualPinball.Unity/Assets/Editor/Icons/large_gray/mech.png.meta b/VisualPinball.Unity/Assets/Editor/Icons/large_gray/mech.png.meta
new file mode 100644
index 000000000..35e556c25
--- /dev/null
+++ b/VisualPinball.Unity/Assets/Editor/Icons/large_gray/mech.png.meta
@@ -0,0 +1,122 @@
+fileFormatVersion: 2
+guid: 58e68a2b3dc2a2843a6f96ced8716558
+TextureImporter:
+ internalIDToNameTable: []
+ externalObjects: {}
+ serializedVersion: 11
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 1
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 1
+ 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: 0
+ wrapV: 0
+ wrapW: 0
+ nPOTScale: 1
+ 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: 0
+ textureShape: 1
+ singleChannelComponent: 0
+ flipbookRows: 1
+ flipbookColumns: 1
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ ignorePngGamma: 0
+ applyGammaDecoding: 0
+ platformSettings:
+ - serializedVersion: 3
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: 512
+ 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/large_gray/rotator.png b/VisualPinball.Unity/Assets/Editor/Icons/large_gray/rotator.png
new file mode 100644
index 000000000..6b44d324e
Binary files /dev/null and b/VisualPinball.Unity/Assets/Editor/Icons/large_gray/rotator.png differ
diff --git a/VisualPinball.Unity/Assets/Editor/Icons/large_gray/rotator.png.meta b/VisualPinball.Unity/Assets/Editor/Icons/large_gray/rotator.png.meta
new file mode 100644
index 000000000..1c6b81c79
--- /dev/null
+++ b/VisualPinball.Unity/Assets/Editor/Icons/large_gray/rotator.png.meta
@@ -0,0 +1,122 @@
+fileFormatVersion: 2
+guid: 933116ec6156efc4eae86909b8d1dabb
+TextureImporter:
+ internalIDToNameTable: []
+ externalObjects: {}
+ serializedVersion: 11
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 1
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 1
+ 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: 0
+ wrapV: 0
+ wrapW: 0
+ nPOTScale: 1
+ 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: 0
+ textureShape: 1
+ singleChannelComponent: 0
+ flipbookRows: 1
+ flipbookColumns: 1
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ ignorePngGamma: 0
+ applyGammaDecoding: 0
+ platformSettings:
+ - serializedVersion: 3
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: 512
+ 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/large_green/mech.png b/VisualPinball.Unity/Assets/Editor/Icons/large_green/mech.png
new file mode 100644
index 000000000..0612cb8c7
Binary files /dev/null and b/VisualPinball.Unity/Assets/Editor/Icons/large_green/mech.png differ
diff --git a/VisualPinball.Unity/Assets/Editor/Icons/large_green/mech.png.meta b/VisualPinball.Unity/Assets/Editor/Icons/large_green/mech.png.meta
new file mode 100644
index 000000000..4b2f8b061
--- /dev/null
+++ b/VisualPinball.Unity/Assets/Editor/Icons/large_green/mech.png.meta
@@ -0,0 +1,122 @@
+fileFormatVersion: 2
+guid: fe51d69592bb5b148900bd5218081d7f
+TextureImporter:
+ internalIDToNameTable: []
+ externalObjects: {}
+ serializedVersion: 11
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 1
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 1
+ 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: 0
+ wrapV: 0
+ wrapW: 0
+ nPOTScale: 1
+ 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: 0
+ textureShape: 1
+ singleChannelComponent: 0
+ flipbookRows: 1
+ flipbookColumns: 1
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ ignorePngGamma: 0
+ applyGammaDecoding: 0
+ platformSettings:
+ - serializedVersion: 3
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: 512
+ 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/large_green/rotator.png b/VisualPinball.Unity/Assets/Editor/Icons/large_green/rotator.png
new file mode 100644
index 000000000..f93aeaf07
Binary files /dev/null and b/VisualPinball.Unity/Assets/Editor/Icons/large_green/rotator.png differ
diff --git a/VisualPinball.Unity/Assets/Editor/Icons/large_green/rotator.png.meta b/VisualPinball.Unity/Assets/Editor/Icons/large_green/rotator.png.meta
new file mode 100644
index 000000000..d4e1ebfb1
--- /dev/null
+++ b/VisualPinball.Unity/Assets/Editor/Icons/large_green/rotator.png.meta
@@ -0,0 +1,122 @@
+fileFormatVersion: 2
+guid: 27156fa6734746944be8b19026ac83db
+TextureImporter:
+ internalIDToNameTable: []
+ externalObjects: {}
+ serializedVersion: 11
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 1
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 1
+ 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: 0
+ wrapV: 0
+ wrapW: 0
+ nPOTScale: 1
+ 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: 0
+ textureShape: 1
+ singleChannelComponent: 0
+ flipbookRows: 1
+ flipbookColumns: 1
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ ignorePngGamma: 0
+ applyGammaDecoding: 0
+ platformSettings:
+ - serializedVersion: 3
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: 512
+ 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/large_orange/mech.png b/VisualPinball.Unity/Assets/Editor/Icons/large_orange/mech.png
new file mode 100644
index 000000000..cb8d01dd7
Binary files /dev/null and b/VisualPinball.Unity/Assets/Editor/Icons/large_orange/mech.png differ
diff --git a/VisualPinball.Unity/Assets/Editor/Icons/large_orange/mech.png.meta b/VisualPinball.Unity/Assets/Editor/Icons/large_orange/mech.png.meta
new file mode 100644
index 000000000..2a4e42b86
--- /dev/null
+++ b/VisualPinball.Unity/Assets/Editor/Icons/large_orange/mech.png.meta
@@ -0,0 +1,122 @@
+fileFormatVersion: 2
+guid: 0a4f50b173346084492196eaccfd5bcd
+TextureImporter:
+ internalIDToNameTable: []
+ externalObjects: {}
+ serializedVersion: 11
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 1
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 1
+ 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: 0
+ wrapV: 0
+ wrapW: 0
+ nPOTScale: 1
+ 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: 0
+ textureShape: 1
+ singleChannelComponent: 0
+ flipbookRows: 1
+ flipbookColumns: 1
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ ignorePngGamma: 0
+ applyGammaDecoding: 0
+ platformSettings:
+ - serializedVersion: 3
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: 512
+ 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/large_orange/rotator.png b/VisualPinball.Unity/Assets/Editor/Icons/large_orange/rotator.png
new file mode 100644
index 000000000..1559ee3e3
Binary files /dev/null and b/VisualPinball.Unity/Assets/Editor/Icons/large_orange/rotator.png differ
diff --git a/VisualPinball.Unity/Assets/Editor/Icons/large_orange/rotator.png.meta b/VisualPinball.Unity/Assets/Editor/Icons/large_orange/rotator.png.meta
new file mode 100644
index 000000000..e6e511b03
--- /dev/null
+++ b/VisualPinball.Unity/Assets/Editor/Icons/large_orange/rotator.png.meta
@@ -0,0 +1,122 @@
+fileFormatVersion: 2
+guid: d1cf99582eae74847965702f8d2daa68
+TextureImporter:
+ internalIDToNameTable: []
+ externalObjects: {}
+ serializedVersion: 11
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 1
+ sRGBTexture: 1
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 1
+ 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: 0
+ wrapV: 0
+ wrapW: 0
+ nPOTScale: 1
+ 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: 0
+ textureShape: 1
+ singleChannelComponent: 0
+ flipbookRows: 1
+ flipbookColumns: 1
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ ignorePngGamma: 0
+ applyGammaDecoding: 0
+ platformSettings:
+ - serializedVersion: 3
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: 512
+ 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_blue/mech.png b/VisualPinball.Unity/Assets/Editor/Icons/small_blue/mech.png
new file mode 100644
index 000000000..bdbb93d32
Binary files /dev/null and b/VisualPinball.Unity/Assets/Editor/Icons/small_blue/mech.png differ
diff --git a/VisualPinball.Unity/Assets/Editor/Icons/small_blue/mech.png.meta b/VisualPinball.Unity/Assets/Editor/Icons/small_blue/mech.png.meta
new file mode 100644
index 000000000..45f15fffe
--- /dev/null
+++ b/VisualPinball.Unity/Assets/Editor/Icons/small_blue/mech.png.meta
@@ -0,0 +1,122 @@
+fileFormatVersion: 2
+guid: 441f67dd65701854fb2e8d6e405c4683
+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_blue/rotator.png b/VisualPinball.Unity/Assets/Editor/Icons/small_blue/rotator.png
new file mode 100644
index 000000000..aaedaace4
Binary files /dev/null and b/VisualPinball.Unity/Assets/Editor/Icons/small_blue/rotator.png differ
diff --git a/VisualPinball.Unity/Assets/Editor/Icons/small_blue/rotator.png.meta b/VisualPinball.Unity/Assets/Editor/Icons/small_blue/rotator.png.meta
new file mode 100644
index 000000000..341a90d30
--- /dev/null
+++ b/VisualPinball.Unity/Assets/Editor/Icons/small_blue/rotator.png.meta
@@ -0,0 +1,122 @@
+fileFormatVersion: 2
+guid: 46c9fd466e7b39a4990e68a253d79bbf
+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/mech.png b/VisualPinball.Unity/Assets/Editor/Icons/small_gray/mech.png
new file mode 100644
index 000000000..4f935e0e0
Binary files /dev/null and b/VisualPinball.Unity/Assets/Editor/Icons/small_gray/mech.png differ
diff --git a/VisualPinball.Unity/Assets/Editor/Icons/small_gray/mech.png.meta b/VisualPinball.Unity/Assets/Editor/Icons/small_gray/mech.png.meta
new file mode 100644
index 000000000..7c121975d
--- /dev/null
+++ b/VisualPinball.Unity/Assets/Editor/Icons/small_gray/mech.png.meta
@@ -0,0 +1,122 @@
+fileFormatVersion: 2
+guid: 56418c7b162776c40bb1c0618abfbb82
+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/rotator.png b/VisualPinball.Unity/Assets/Editor/Icons/small_gray/rotator.png
new file mode 100644
index 000000000..880ba2398
Binary files /dev/null and b/VisualPinball.Unity/Assets/Editor/Icons/small_gray/rotator.png differ
diff --git a/VisualPinball.Unity/Assets/Editor/Icons/small_gray/rotator.png.meta b/VisualPinball.Unity/Assets/Editor/Icons/small_gray/rotator.png.meta
new file mode 100644
index 000000000..6da1cf10b
--- /dev/null
+++ b/VisualPinball.Unity/Assets/Editor/Icons/small_gray/rotator.png.meta
@@ -0,0 +1,122 @@
+fileFormatVersion: 2
+guid: e5f20a46dd160a24b94c984ff5df8939
+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/mech.png b/VisualPinball.Unity/Assets/Editor/Icons/small_green/mech.png
new file mode 100644
index 000000000..78c51e994
Binary files /dev/null and b/VisualPinball.Unity/Assets/Editor/Icons/small_green/mech.png differ
diff --git a/VisualPinball.Unity/Assets/Editor/Icons/small_green/mech.png.meta b/VisualPinball.Unity/Assets/Editor/Icons/small_green/mech.png.meta
new file mode 100644
index 000000000..e7e942494
--- /dev/null
+++ b/VisualPinball.Unity/Assets/Editor/Icons/small_green/mech.png.meta
@@ -0,0 +1,122 @@
+fileFormatVersion: 2
+guid: 07c0681a061c1a34fa72f3d686fb38cb
+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/rotator.png b/VisualPinball.Unity/Assets/Editor/Icons/small_green/rotator.png
new file mode 100644
index 000000000..6dc31af89
Binary files /dev/null and b/VisualPinball.Unity/Assets/Editor/Icons/small_green/rotator.png differ
diff --git a/VisualPinball.Unity/Assets/Editor/Icons/small_green/rotator.png.meta b/VisualPinball.Unity/Assets/Editor/Icons/small_green/rotator.png.meta
new file mode 100644
index 000000000..5ab4645f3
--- /dev/null
+++ b/VisualPinball.Unity/Assets/Editor/Icons/small_green/rotator.png.meta
@@ -0,0 +1,122 @@
+fileFormatVersion: 2
+guid: e7e24632d3ee05b4aa1cfa7585929321
+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_orange/mech.png b/VisualPinball.Unity/Assets/Editor/Icons/small_orange/mech.png
new file mode 100644
index 000000000..71e88de4e
Binary files /dev/null and b/VisualPinball.Unity/Assets/Editor/Icons/small_orange/mech.png differ
diff --git a/VisualPinball.Unity/Assets/Editor/Icons/small_orange/mech.png.meta b/VisualPinball.Unity/Assets/Editor/Icons/small_orange/mech.png.meta
new file mode 100644
index 000000000..0f0cb7d2a
--- /dev/null
+++ b/VisualPinball.Unity/Assets/Editor/Icons/small_orange/mech.png.meta
@@ -0,0 +1,122 @@
+fileFormatVersion: 2
+guid: fb3697293112e424081c5debc2d519fb
+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_orange/rotator.png b/VisualPinball.Unity/Assets/Editor/Icons/small_orange/rotator.png
new file mode 100644
index 000000000..36c298620
Binary files /dev/null and b/VisualPinball.Unity/Assets/Editor/Icons/small_orange/rotator.png differ
diff --git a/VisualPinball.Unity/Assets/Editor/Icons/small_orange/rotator.png.meta b/VisualPinball.Unity/Assets/Editor/Icons/small_orange/rotator.png.meta
new file mode 100644
index 000000000..e55eee493
--- /dev/null
+++ b/VisualPinball.Unity/Assets/Editor/Icons/small_orange/rotator.png.meta
@@ -0,0 +1,122 @@
+fileFormatVersion: 2
+guid: 311ce6f9db0cc1148b42d67735584430
+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/Resources/Materials/Dot Matrix Display (SRP).mat b/VisualPinball.Unity/Assets/Resources/Materials/Dot Matrix Display (SRP).mat
index 46195e0a4..cf9b91a22 100644
--- a/VisualPinball.Unity/Assets/Resources/Materials/Dot Matrix Display (SRP).mat
+++ b/VisualPinball.Unity/Assets/Resources/Materials/Dot Matrix Display (SRP).mat
@@ -1,18 +1,21 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &-7048375842616513859
-MonoBehaviour:
- m_ObjectHideFlags: 11
- m_CorrespondingSourceObject: {fileID: 0}
- m_PrefabInstance: {fileID: 0}
- m_PrefabAsset: {fileID: 0}
- m_GameObject: {fileID: 0}
- m_Enabled: 1
- m_EditorHideFlags: 0
- m_Script: {fileID: 11500000, guid: da692e001514ec24dbc4cca1949ff7e8, type: 3}
- m_Name:
- m_EditorClassIdentifier:
- version: 11
+MonoBehaviour:
+ m_ObjectHideFlags: 11
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 0}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: da692e001514ec24dbc4cca1949ff7e8, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ version: 12
+ hdPluginSubTargetMaterialVersions:
+ m_Keys: []
+ m_Values:
--- !u!21 &2100000
Material:
serializedVersion: 6
@@ -146,6 +149,7 @@ Material:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
+ m_Ints: []
m_Floats:
- Vector1_3ebae42385484fdab87c4c0493f74e5a: 1.49
- Vector1_48868e3f644c4f8d9dc2d14907d07c46: 7
@@ -170,6 +174,7 @@ Material:
- _Anisotropy: 0
- _BlendMode: 0
- _CoatMask: 0
+ - _ConservativeDepthOffsetEnable: 0
- _CullMode: 2
- _CullModeForward: 2
- _Cutoff: 0.5
@@ -183,6 +188,7 @@ Material:
- _DisplacementLockTilingScale: 1
- _DisplacementMode: 0
- _DoubleSidedEnable: 0
+ - _DoubleSidedGIMode: 0
- _DoubleSidedNormalMode: 1
- _DstBlend: 0
- _EmissiveColorMode: 1
@@ -265,9 +271,11 @@ Material:
- _ZTestGBuffer: 4
- _ZTestTransparent: 4
- _ZWrite: 1
- - __Padding: 0.2
+ - __Emission: 1
- __NumChars: 2
- __NumSegments: 15
+ - __Padding: 0.2
+ - __Roundness: 0.35
- __SegmentType: 0
- __SegmentWeight: 0.05
- __SkewAngle: 0
diff --git a/VisualPinball.Unity/Assets/Resources/Materials/Segment Display (SRP).mat b/VisualPinball.Unity/Assets/Resources/Materials/Segment Display (SRP).mat
index 0e4f80a80..86cec9d19 100644
--- a/VisualPinball.Unity/Assets/Resources/Materials/Segment Display (SRP).mat
+++ b/VisualPinball.Unity/Assets/Resources/Materials/Segment Display (SRP).mat
@@ -1,18 +1,21 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &-7048375842616513859
-MonoBehaviour:
- m_ObjectHideFlags: 11
- m_CorrespondingSourceObject: {fileID: 0}
- m_PrefabInstance: {fileID: 0}
- m_PrefabAsset: {fileID: 0}
- m_GameObject: {fileID: 0}
- m_Enabled: 1
- m_EditorHideFlags: 0
- m_Script: {fileID: 11500000, guid: da692e001514ec24dbc4cca1949ff7e8, type: 3}
- m_Name:
- m_EditorClassIdentifier:
- version: 11
+MonoBehaviour:
+ m_ObjectHideFlags: 11
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 0}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: da692e001514ec24dbc4cca1949ff7e8, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ version: 12
+ hdPluginSubTargetMaterialVersions:
+ m_Keys: []
+ m_Values:
--- !u!21 &2100000
Material:
serializedVersion: 6
@@ -102,6 +105,10 @@ Material:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
+ - _SegmentDisplayCustomFunction_a94cb738cee9426e8bf076adaa3b6811_SegmentData_2:
+ m_Texture: {fileID: 0}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
- _SpecularColorMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
@@ -126,6 +133,10 @@ Material:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
+ - __Data:
+ m_Texture: {fileID: 0}
+ m_Scale: {x: 1, y: 1}
+ m_Offset: {x: 0, y: 0}
- unity_Lightmaps:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
@@ -138,6 +149,7 @@ Material:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
+ m_Ints: []
m_Floats:
- Vector1_48868e3f644c4f8d9dc2d14907d07c46: 7
- Vector1_78a66e5d29d14bd2954daf3fb60bb4aa: 0
@@ -161,6 +173,7 @@ Material:
- _Anisotropy: 0
- _BlendMode: 0
- _CoatMask: 0
+ - _ConservativeDepthOffsetEnable: 0
- _CullMode: 2
- _CullModeForward: 2
- _Cutoff: 0.5
@@ -174,6 +187,7 @@ Material:
- _DisplacementLockTilingScale: 1
- _DisplacementMode: 0
- _DoubleSidedEnable: 0
+ - _DoubleSidedGIMode: 0
- _DoubleSidedNormalMode: 1
- _DstBlend: 0
- _EmissiveColorMode: 1
@@ -256,6 +270,13 @@ Material:
- _ZTestGBuffer: 4
- _ZTestTransparent: 4
- _ZWrite: 1
+ - __HorizontalMiddle: 0
+ - __NumChars: 2
+ - __NumSegments: 14
+ - __SegmentWeight: 0.05
+ - __SeparatorEveryThree: 0
+ - __SeparatorType: 2
+ - __SkewAngle: 0
m_Colors:
- Color_754dade2513142578632eb55adb8f59b: {r: 1, g: 0.36865607, b: 0, a: 0}
- Color_a1cf9b5e0df34a8c907984367d220f54: {r: 0.25471696, g: 0.25471696, b: 0.25471696, a: 0}
@@ -276,4 +297,8 @@ Material:
- _UVDetailsMappingMask: {r: 1, g: 0, b: 0, a: 0}
- _UVMappingMask: {r: 1, g: 0, b: 0, a: 0}
- _UVMappingMaskEmissive: {r: 1, g: 0, b: 0, a: 0}
+ - __LitColor: {r: 1, g: 0.39999998, b: 0, a: 0}
+ - __Padding: {r: 0.3, g: 0.5, b: 0, a: 0}
+ - __SeparatorPos: {r: 1.4, g: 0, b: 0, a: 0}
+ - __UnlitColor: {r: 0.25471696, g: 0.25471696, b: 0.25471696, a: 0}
m_BuildTextureStacks: []
diff --git a/VisualPinball.Unity/Documentation~/creators-guide/manual/mechanisms/light-groups.md b/VisualPinball.Unity/Documentation~/creators-guide/manual/mechanisms/light-groups.md
index c8d57803d..9dffbf031 100644
--- a/VisualPinball.Unity/Documentation~/creators-guide/manual/mechanisms/light-groups.md
+++ b/VisualPinball.Unity/Documentation~/creators-guide/manual/mechanisms/light-groups.md
@@ -16,7 +16,7 @@ A light group is a component you can add to any GameObject. It's recommended to
To create a new light group, select the GameObject you want to add your light group to, and in the inspector click on *Add Component* and choose *Visual Pinball -> Game Item -> Light Group*.
-Then use the list control to add and remove lights. There are a few button that make this easier.
+Then use the list control to add and remove lights. There are a few buttons that make this easier.
### Add Children
diff --git a/VisualPinball.Unity/Documentation~/creators-guide/manual/mechanisms/rotator-inspector.png b/VisualPinball.Unity/Documentation~/creators-guide/manual/mechanisms/rotator-inspector.png
new file mode 100644
index 000000000..70bf6df82
Binary files /dev/null and b/VisualPinball.Unity/Documentation~/creators-guide/manual/mechanisms/rotator-inspector.png differ
diff --git a/VisualPinball.Unity/Documentation~/creators-guide/manual/mechanisms/rotators.md b/VisualPinball.Unity/Documentation~/creators-guide/manual/mechanisms/rotators.md
new file mode 100644
index 000000000..eda42327f
--- /dev/null
+++ b/VisualPinball.Unity/Documentation~/creators-guide/manual/mechanisms/rotators.md
@@ -0,0 +1,33 @@
+---
+uid: rotator
+title: Rotators
+description: Rotating objects during gameplay
+---
+
+# Rotators
+
+Sometimes during gameplay, you might need to rotate objects in order to recreate certain mechanisms. Like Visual Pinball, VPE doesn't support dynamic colliders (yet), but visually, objects can still be rotated.
+
+**Rotators** in VPE are components that allow you to easily rotate objects around the Z-axis. The **Rotator** component is applied to a *target*, which will then rotate around its local origin (typically the position on the playfield). Additional objects can be linked to rotate around the same axis at the same time.
+
+## Setup
+
+
+
+In order to create a rotator, add the **Rotator** component to a game object by clicking *Add Component* in the inspector, then choosing *Visual Pinball -> Game Item -> Rotator*. You can use any game object, although we recommend adding it to the target that you want to rotate.
+
+### Target
+
+Just adding the component to your target game object won't automatically rotate the target. You need to explicitly assign it in the **Target** field.
+
+### Rotate With
+
+Add other objects that rotate along with your target here. Currently, the following game items are supported:
+
+- **Primitives** - Apart from the position, the *object rotation* of the primitive is updated. Note that in case your primitive has collision enabled, the colliders will not rotate along with the rendered object.
+- **Kickers** - Rotating kickers applies the new angle to the kicker coils, and if a kicker contains a ball, the ball is rotated along as well.
+- **Flippers** - Rotating flippers updates the start angle of the flipper.
+
+## Usage
+
+When adding a **Rotator** component to a game object, it provides a float input that other components can use to rotate the object. Currently, only the step rotator mech makes use of this input. However, the step rotator will probably be replaced by a more generic system soon, so we won't go into more details here.
diff --git a/VisualPinball.Unity/Documentation~/creators-guide/manual/mechanisms/teleporters.md b/VisualPinball.Unity/Documentation~/creators-guide/manual/mechanisms/teleporters.md
index c8263319e..77397bffe 100644
--- a/VisualPinball.Unity/Documentation~/creators-guide/manual/mechanisms/teleporters.md
+++ b/VisualPinball.Unity/Documentation~/creators-guide/manual/mechanisms/teleporters.md
@@ -6,7 +6,7 @@ description: VPE can teleport the ball from one kicker to another.
# Teleporters
-Sometimes, it's easier to teleport the ball from one place to another instead of setting up the physical environment to simulate the actual movement. VPE provides a simple component that destroys a ball at kicker A and creates a new one at kicker B.
+Sometimes it's easier to teleport the ball from one place to another instead of setting up the physical environment to simulate the actual movement. VPE provides a simple component that destroys a ball at kicker A and creates a new one at kicker B.
> [!NOTE]
> Please note that you shouldn't be using teleporters when the ball is visible, because it breaks the natural flow of the ball and looks choppy.
@@ -26,7 +26,7 @@ In order to create a new teleporter, select the GameObject you want to add it to
Once the ball is created at the destination kicker, it can be ejected immediately or after a delay (see next section), or it can stay in the kicker.
-If disabled, this option makes the destination kicker keep the ball until it's explicitly ejected trough the kicker's coil.
+If disabled, this option makes the destination kicker keep the ball until it's explicitly ejected through the kicker's coil.
### Wait Before Eject
diff --git a/VisualPinball.Unity/Documentation~/creators-guide/toc.yml b/VisualPinball.Unity/Documentation~/creators-guide/toc.yml
index be45f7606..632f8c142 100644
--- a/VisualPinball.Unity/Documentation~/creators-guide/toc.yml
+++ b/VisualPinball.Unity/Documentation~/creators-guide/toc.yml
@@ -53,3 +53,5 @@
href: manual/mechanisms/teleporters.md
- name: Drop Target Banks
href: manual/mechanisms/drop-target-banks.md
+ - name: Rotators
+ href: manual/mechanisms/rotators.md
diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/Import/VpxPrefab.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/Import/VpxPrefab.cs
index 43562da17..60c84067c 100644
--- a/VisualPinball.Unity/VisualPinball.Unity.Editor/Import/VpxPrefab.cs
+++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/Import/VpxPrefab.cs
@@ -67,7 +67,7 @@ public void SetReferencedData(Table table, IMaterialProvider materialProvider, I
public void UpdateTransforms()
{
- if (_mainComponent is IMainRenderableComponent renderComponent) {
+ if (_mainComponent && _mainComponent is IMainRenderableComponent renderComponent) {
renderComponent.UpdateTransforms();
}
}
diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/Utils/Icons.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/Utils/Icons.cs
index 505b7a28f..e783d0265 100644
--- a/VisualPinball.Unity/VisualPinball.Unity.Editor/Utils/Icons.cs
+++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/Utils/Icons.cs
@@ -37,11 +37,11 @@ public IconVariant(string name, IconSize size, IconColor color)
}
private const string BallRollerName = "ball_roller";
- private const string BumperName = "bumper";
private const string BoltName = "bolt";
+ private const string BumperName = "bumper";
private const string CoilName = "coil";
- private const string DropTargetName = "drop_target";
private const string DropTargetBankName = "drop_target_bank";
+ private const string DropTargetName = "drop_target";
private const string FlasherName = "light_flasher";
private const string FlipperName = "flipper";
private const string GateName = "gate";
@@ -50,26 +50,28 @@ public IconVariant(string name, IconSize size, IconColor color)
private const string KickerName = "kicker";
private const string LightGroupName = "light_group";
private const string LightName = "light";
+ private const string MechName = "mech";
private const string PlayfieldName = "playfield";
- private const string PlungerName = "plunger";
private const string PlugName = "plug";
+ private const string PlungerName = "plunger";
private const string PrimitiveName = "primitive";
private const string RampName = "ramp";
+ private const string RotatorName = "rotator";
private const string RubberName = "rubber";
+ private const string SlingshotName = "slingshot";
private const string SpinnerName = "spinner";
private const string SurfaceName = "surface";
- private const string SlingshotName = "slingshot";
+ private const string SwitchNcName = "switch_nc";
+ private const string SwitchNoName = "switch_no";
private const string TableName = "table";
private const string TeleporterName = "teleporter";
private const string TriggerName = "trigger";
private const string TroughName = "trough";
- private const string SwitchNcName = "switch_nc";
- private const string SwitchNoName = "switch_no";
private static readonly string[] Names = {
- BallRollerName, BumperName, BoltName, CoilName, DropTargetName, DropTargetBankName, FlasherName, FlipperName, HitTargetName, GateName, KeyName,
- KickerName, LightGroupName, LightName, PlayfieldName, PlungerName, PlugName, PrimitiveName, RampName, RubberName, SpinnerName, SurfaceName,
- TableName, TeleporterName, TriggerName, TroughName, SlingshotName, SwitchNcName, SwitchNoName
+ BallRollerName, BoltName, BumperName, CoilName, DropTargetBankName, DropTargetName, FlasherName, FlipperName, GateName, HitTargetName, KeyName,
+ KickerName, LightGroupName, LightName, MechName, PlayfieldName, PlugName, PlungerName, PrimitiveName, RampName, RotatorName, RubberName,
+ SlingshotName, SpinnerName, SurfaceName, SwitchNcName, SwitchNoName, TableName, TeleporterName, TriggerName, TroughName,
};
private readonly Dictionary _icons = new Dictionary();
@@ -101,33 +103,35 @@ private Icons()
}
public static Texture2D BallRoller(IconSize size = IconSize.Large, IconColor color = IconColor.Gray) => Instance.GetItem(BallRollerName, size, color);
+ public static Texture2D Bolt(IconSize size = IconSize.Large, IconColor color = IconColor.Gray) => Instance.GetItem(BoltName, size, color);
public static Texture2D Bumper(IconSize size = IconSize.Large, IconColor color = IconColor.Gray) => Instance.GetItem(BumperName, size, color);
+ public static Texture2D Coil(IconSize size = IconSize.Large, IconColor color = IconColor.Gray) => Instance.GetItem(CoilName, size, color);
public static Texture2D DropTarget(IconSize size = IconSize.Large, IconColor color = IconColor.Gray) => Instance.GetItem(DropTargetName, size, color);
public static Texture2D DropTargetBank(IconSize size = IconSize.Large, IconColor color = IconColor.Gray) => Instance.GetItem(DropTargetBankName, size, color);
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 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);
public static Texture2D Light(IconSize size = IconSize.Large, IconColor color = IconColor.Gray) => Instance.GetItem(LightName, size, color);
public static Texture2D LightGroup(IconSize size = IconSize.Large, IconColor color = IconColor.Gray) => Instance.GetItem(LightGroupName, size, color);
+ public static Texture2D Mech(IconSize size = IconSize.Large, IconColor color = IconColor.Gray) => Instance.GetItem(MechName, size, color);
public static Texture2D Playfield(IconSize size = IconSize.Large, IconColor color = IconColor.Gray) => Instance.GetItem(PlayfieldName, size, color);
- public static Texture2D Plunger(IconSize size = IconSize.Large, IconColor color = IconColor.Gray) => Instance.GetItem(PlungerName, size, color);
public static Texture2D Plug(IconSize size = IconSize.Large, IconColor color = IconColor.Gray) => Instance.GetItem(PlugName, size, color);
+ public static Texture2D Plunger(IconSize size = IconSize.Large, IconColor color = IconColor.Gray) => Instance.GetItem(PlungerName, size, color);
public static Texture2D Primitive(IconSize size = IconSize.Large, IconColor color = IconColor.Gray) => Instance.GetItem(PrimitiveName, size, color);
public static Texture2D Ramp(IconSize size = IconSize.Large, IconColor color = IconColor.Gray) => Instance.GetItem(RampName, size, color);
+ public static Texture2D Rotator(IconSize size = IconSize.Large, IconColor color = IconColor.Gray) => Instance.GetItem(RotatorName, size, color);
public static Texture2D Rubber(IconSize size = IconSize.Large, IconColor color = IconColor.Gray) => Instance.GetItem(RubberName, size, color);
+ public static Texture2D Slingshot(IconSize size = IconSize.Large, IconColor color = IconColor.Gray) => Instance.GetItem(SlingshotName, size, color);
public static Texture2D Spinner(IconSize size = IconSize.Large, IconColor color = IconColor.Gray) => Instance.GetItem(SpinnerName, size, color);
public static Texture2D Surface(IconSize size = IconSize.Large, IconColor color = IconColor.Gray) => Instance.GetItem(SurfaceName, size, color);
+ public static Texture2D Switch(bool isClosed, IconSize size = IconSize.Large, IconColor color = IconColor.Gray) => Instance.GetItem(isClosed ? SwitchNcName : SwitchNoName, size, color);
public static Texture2D Table(IconSize size = IconSize.Large, IconColor color = IconColor.Gray) => Instance.GetItem(TableName, size, color);
public static Texture2D Teleporter(IconSize size = IconSize.Large, IconColor color = IconColor.Gray) => Instance.GetItem(TeleporterName, size, color);
public static Texture2D Trigger(IconSize size = IconSize.Large, IconColor color = IconColor.Gray) => Instance.GetItem(TriggerName, size, color);
public static Texture2D Trough(IconSize size = IconSize.Large, IconColor color = IconColor.Gray) => Instance.GetItem(TroughName, size, color);
- public static Texture2D Slingshot(IconSize size = IconSize.Large, IconColor color = IconColor.Gray) => Instance.GetItem(SlingshotName, size, color);
- public static Texture2D Switch(bool isClosed, IconSize size = IconSize.Large, IconColor color = IconColor.Gray) => Instance.GetItem(isClosed ? SwitchNcName : SwitchNoName, size, color);
- public static Texture2D Coil(IconSize size = IconSize.Large, IconColor color = IconColor.Gray) => Instance.GetItem(CoilName, size, color);
- public static Texture2D Key(IconSize size = IconSize.Large, IconColor color = IconColor.Gray) => Instance.GetItem(KeyName, size, color);
- public static Texture2D Bolt(IconSize size = IconSize.Large, IconColor color = IconColor.Gray) => Instance.GetItem(BoltName, size, color);
public static Texture2D ByComponent(T mb, IconSize size = IconSize.Large, IconColor color = IconColor.Gray)
where T : class
@@ -148,10 +152,12 @@ public static Texture2D ByComponent(T mb, IconSize size = IconSize.Large, Ico
case PlayfieldComponent _: return Playfield(size, color);
case PrimitiveComponent _: return Primitive(size, color);
case RampComponent _: return Ramp(size, color);
+ case RotatorComponent _: return Rotator(size, color);
case RubberComponent _: return Rubber(size, color);
case SpinnerComponent _: return Spinner(size, color);
case SlingshotComponent _: return Slingshot(size, color);
case SurfaceComponent _: return Surface(size, color);
+ case StepRotatorMechComponent _: return Mech(size, color);
case TeleporterComponent _: return Teleporter(size, color);
case TriggerComponent _: return Trigger(size, color);
case TroughComponent _: return Trough(size, color);
@@ -204,6 +210,7 @@ public static void DisableGizmoIcons()
DisableGizmo();
DisableGizmo();
DisableGizmo();
+ DisableGizmo();
DisableGizmo();
DisableGizmo();
DisableGizmo();
diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Kicker/KickerColliderInspector.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Kicker/KickerColliderInspector.cs
index f05a93495..dc2f67a66 100644
--- a/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Kicker/KickerColliderInspector.cs
+++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Kicker/KickerColliderInspector.cs
@@ -29,8 +29,6 @@ public class KickerColliderInspector : ColliderInspector();
- if (surfaceComponent != null && (TMainComponent)surfaceComponent.Surface == MainComponent) {
+ if (surfaceComponent != null && surfaceComponent.Surface == MainComponent) {
surfaceComponent.OnSurfaceUpdated();
}
}
diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Mech.meta b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Mech.meta
new file mode 100644
index 000000000..8e79e0947
--- /dev/null
+++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Mech.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 7af66892ce9cbfc4bb8a176ac3979d07
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Mech/RotatorInspector.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Mech/RotatorInspector.cs
new file mode 100644
index 000000000..df4a6bb95
--- /dev/null
+++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Mech/RotatorInspector.cs
@@ -0,0 +1,55 @@
+// Visual Pinball Engine
+// Copyright (C) 2021 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 AssignmentInConditionalExpression
+
+using UnityEditor;
+using UnityEngine;
+using VisualPinball.Engine.VPT.Primitive;
+
+namespace VisualPinball.Unity.Editor
+{
+ [CustomEditor(typeof(RotatorComponent)), CanEditMultipleObjects]
+ public class RotatorInspector : ItemInspector
+ {
+ private SerializedProperty _targetProperty;
+ private SerializedProperty _rotateWithProperty;
+
+ protected override MonoBehaviour UndoTarget => target as MonoBehaviour;
+
+ protected override void OnEnable()
+ {
+ base.OnEnable();
+
+ _targetProperty = serializedObject.FindProperty(nameof(RotatorComponent._target));
+ _rotateWithProperty = serializedObject.FindProperty(nameof(RotatorComponent._rotateWith));
+ }
+
+ public override void OnInspectorGUI()
+ {
+ BeginEditing();
+
+ OnPreInspectorGUI();
+
+ PropertyField(_targetProperty);
+ PropertyField(_rotateWithProperty);
+
+ base.OnInspectorGUI();
+
+ EndEditing();
+ }
+ }
+}
diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Mech/CannonApi.cs.meta b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Mech/RotatorInspector.cs.meta
similarity index 83%
rename from VisualPinball.Unity/VisualPinball.Unity/VPT/Mech/CannonApi.cs.meta
rename to VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Mech/RotatorInspector.cs.meta
index 70bfb520b..392cc45f6 100644
--- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Mech/CannonApi.cs.meta
+++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Mech/RotatorInspector.cs.meta
@@ -1,5 +1,5 @@
fileFormatVersion: 2
-guid: 22e0181ba659a436ab6bb57d9744d241
+guid: a1659b98b1b7e504f9b2731e3c474c36
MonoImporter:
externalObjects: {}
serializedVersion: 2
diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Mech/StepRotatorMarkPropertyDrawer.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Mech/StepRotatorMarkPropertyDrawer.cs
new file mode 100644
index 000000000..89010e79b
--- /dev/null
+++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Mech/StepRotatorMarkPropertyDrawer.cs
@@ -0,0 +1,65 @@
+// Visual Pinball Engine
+// Copyright (C) 2021 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
+{
+ [CustomPropertyDrawer(typeof(StepRotatorMark))]
+ public class StepRotatorMarkPropertyDrawer : PropertyDrawer
+ {
+ private const float Padding = 2f;
+
+ public override float GetPropertyHeight(SerializedProperty property, GUIContent label) => (EditorGUIUtility.singleLineHeight + Padding) * 3f;
+
+ public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
+ {
+ EditorGUI.BeginProperty(position, label, property);
+
+ position.height = EditorGUIUtility.singleLineHeight;
+
+ // save indent level
+ var indent = EditorGUI.indentLevel;
+ EditorGUI.indentLevel = 0;
+
+ // description and switch id
+ EditorGUI.PropertyField(position, property.FindPropertyRelative(nameof(StepRotatorMark.Description)), new GUIContent("Title"));
+ position.y += EditorGUIUtility.singleLineHeight + Padding;
+ EditorGUI.PropertyField(position, property.FindPropertyRelative(nameof(StepRotatorMark.SwitchId)));
+
+ // step line
+ position.y += EditorGUIUtility.singleLineHeight + Padding;
+ position = EditorGUI.PrefixLabel(position, GUIUtility.GetControlID(FocusType.Passive), new GUIContent("Between"));
+
+ var width = (position.width - 40) / 2f - 10f;
+ var fromRect = new Rect(position.x, position.y, width, position.height);
+ var toRect = new Rect(position.x + width + 20f, position.y, width, position.height);
+ var midRect = new Rect(position.x + width + 6f, position.y, width, position.height);
+ var rightRect = new Rect(position.x + position.width - 40 + 4, position.y, 40, position.height);
+
+ EditorGUI.PropertyField(fromRect, property.FindPropertyRelative(nameof(StepRotatorMark.StepBeginning)), GUIContent.none);
+ EditorGUI.LabelField(midRect, new GUIContent("-"));
+ EditorGUI.PropertyField(toRect, property.FindPropertyRelative(nameof(StepRotatorMark.StepEnd)), GUIContent.none);
+ EditorGUI.LabelField(rightRect, new GUIContent("steps"));
+
+ // set indent back to what it was
+ EditorGUI.indentLevel = indent;
+
+ EditorGUI.EndProperty();
+ }
+ }
+}
diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Mech/CannonComponent.cs.meta b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Mech/StepRotatorMarkPropertyDrawer.cs.meta
similarity index 83%
rename from VisualPinball.Unity/VisualPinball.Unity/VPT/Mech/CannonComponent.cs.meta
rename to VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Mech/StepRotatorMarkPropertyDrawer.cs.meta
index 384ef875c..9c0971866 100644
--- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Mech/CannonComponent.cs.meta
+++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Mech/StepRotatorMarkPropertyDrawer.cs.meta
@@ -1,5 +1,5 @@
fileFormatVersion: 2
-guid: 3f853fba4c41e47bfb470ad3b384e3c9
+guid: 94401e36468dcb343b369d6683fcc34a
MonoImporter:
externalObjects: {}
serializedVersion: 2
diff --git a/VisualPinball.Unity/VisualPinball.Unity.Patcher/Matcher/TablePatcher.cs b/VisualPinball.Unity/VisualPinball.Unity.Patcher/Matcher/TablePatcher.cs
index 274e99ea5..d9c2fa870 100644
--- a/VisualPinball.Unity/VisualPinball.Unity.Patcher/Matcher/TablePatcher.cs
+++ b/VisualPinball.Unity/VisualPinball.Unity.Patcher/Matcher/TablePatcher.cs
@@ -92,6 +92,23 @@ protected static GameObject GetOrCreateGameObject(GameObject parentGo, string na
return CreateEmptyGameObject(parentGo, name);
}
+ ///
+ /// Set a new parent for the given child while keeping the position and rotation.
+ ///
+ ///
+ ///
+ protected static void Reparent(GameObject child, GameObject parent)
+ {
+ var rot = child.transform.rotation;
+ var pos = child.transform.position;
+
+ // re-parent the child
+ child.transform.SetParent(parent.transform, false);
+
+ child.transform.rotation = rot;
+ child.transform.position = pos;
+ }
+
#endregion
#region Element Helpers
@@ -439,6 +456,23 @@ protected static void LinkLights(GameObject go, params string[] lightNames)
#region Mapping Helpers
+ ///
+ /// Links a coil device to an existing coil mapping.
+ ///
+ /// Table component for retrieving mappings.
+ /// The ID of the coil mapping that the coil device will be linked to
+ /// The coil device to be linked
+ /// If set, it's the device item, otherwise the first item of the device.
+ protected static void LinkCoil(TableComponent tableComponent, string coilId, ICoilDeviceComponent coilDevice, string deviceItem = null)
+ {
+ var coilMapping = tableComponent.MappingConfig.Coils.FirstOrDefault(cm => cm.Id == coilId);
+ if (coilMapping == null) {
+ return;
+ }
+ coilMapping.Device = coilDevice;
+ coilMapping.DeviceItem = deviceItem ?? coilDevice.AvailableCoils.First().Id;
+ }
+
///
/// Links a coil device to an existing coil mapping if it matches a given name.
///
@@ -452,12 +486,24 @@ protected static void LinkCoil(TableComponent tableComponent, string elementName
if (!string.Equals(coilDevice.gameObject.name, elementName, StringComparison.OrdinalIgnoreCase)) {
return;
}
- var coilMapping = tableComponent.MappingConfig.Coils.FirstOrDefault(cm => cm.Id == coilId);
- if (coilMapping == null) {
+ LinkCoil(tableComponent, coilId, coilDevice, deviceItem);
+ }
+
+ ///
+ /// Links a switch device to an existing switch mapping.
+ ///
+ /// Table component for retrieving mappings.
+ /// The ID of the switch mapping that the switch device will be linked to
+ /// The switch device to be linked
+ /// Switch ID inside of the device item. If null, the first switch will be used.
+ protected static void LinkSwitch(TableComponent tableComponent, string switchId, ISwitchDeviceComponent switchDevice, string switchDeviceItem = null)
+ {
+ var switchMapping = tableComponent.MappingConfig.Switches.FirstOrDefault(sw => sw.Id == switchId);
+ if (switchMapping == null) {
return;
}
- coilMapping.Device = coilDevice;
- coilMapping.DeviceItem = deviceItem ?? coilDevice.AvailableCoils.First().Id;
+ switchMapping.Device = switchDevice;
+ switchMapping.DeviceItem = switchDeviceItem ?? switchDevice.AvailableSwitches.First().Id;
}
///
@@ -472,12 +518,7 @@ protected static void LinkSwitch(TableComponent tableComponent, string elementNa
if (!string.Equals(switchDevice.gameObject.name, elementName, StringComparison.OrdinalIgnoreCase)) {
return;
}
- var switchMapping = tableComponent.MappingConfig.Switches.FirstOrDefault(sw => sw.Id == switchId);
- if (switchMapping == null) {
- return;
- }
- switchMapping.Device = switchDevice;
- switchMapping.DeviceItem = switchDevice.AvailableSwitches.First().Id;
+ LinkSwitch(tableComponent, switchId, switchDevice);
}
#endregion
diff --git a/VisualPinball.Unity/VisualPinball.Unity.Patcher/Patcher/Tables/Terminator2.cs b/VisualPinball.Unity/VisualPinball.Unity.Patcher/Patcher/Tables/Terminator2.cs
index 9ba2e4548..a015b0ab3 100644
--- a/VisualPinball.Unity/VisualPinball.Unity.Patcher/Patcher/Tables/Terminator2.cs
+++ b/VisualPinball.Unity/VisualPinball.Unity.Patcher/Patcher/Tables/Terminator2.cs
@@ -111,6 +111,9 @@ private static void SetupMapping(GameObject tableGo)
// left lock
LinkCoil(tc, "sw51", "16", kicker);
+
+ // cannon
+ LinkCoil(tc, "sw31", "02", kicker);
}
var plungers = tableGo.GetComponentsInChildren();
@@ -125,6 +128,20 @@ private static void SetupMapping(GameObject tableGo)
// skull kicker
LinkCoil(tc, "sw76", "01", teleporter, TeleporterComponent.CoilItem);
}
+
+ var bumpers = tableGo.GetComponentsInChildren();
+ foreach (var bumper in bumpers) {
+ LinkSwitch(tc, "Bumper1", "41", bumper);
+ LinkSwitch(tc, "Bumper2", "43", bumper);
+ LinkSwitch(tc, "Bumper3", "42", bumper);
+ }
+
+ // cannon
+ var cannonGo = tc.transform.Find("Playfield/Mechs/Cannon").gameObject;
+ var cannonMech = cannonGo.GetComponent();
+ LinkSwitch(tc, "32", cannonMech, "gun_mark_switch");
+ LinkSwitch(tc, "33", cannonMech, "gun_home_switch");
+ LinkCoil(tc, "11", cannonMech);
}
private static void SetupDmd(GameObject tableGo)
@@ -367,7 +384,7 @@ public void SkullKicker(KickerComponent kickerComponent)
public void Teleporter(KickerComponent kickerComponent)
{
kickerComponent.Coils[0].Name = "Teleporter Out";
- kickerComponent.Coils[0].Speed = 15;
+ kickerComponent.Coils[0].Speed = 3;
kickerComponent.Coils[0].Angle = 72;
}
@@ -389,7 +406,7 @@ public void LeftLock(KickerComponent kickerComponent)
#endregion
- #region Drop Target Banks
+ #region Mechs
[NameMatch("sw77")]
public void CreateDropTargetBank(GameObject dropTargetGo, DropTargetComponent dropTargetComponent)
@@ -399,6 +416,28 @@ public void CreateDropTargetBank(GameObject dropTargetGo, DropTargetComponent dr
dropTargetBank.DropTargets = new[] { dropTargetComponent };
}
+ [NameMatch("T2_Gun")]
+ public void SetupCannon(GameObject primitiveGo, PrimitiveComponent cannonComp)
+ {
+ var playfieldGo = primitiveGo.GetComponentInParent().gameObject;
+ var mechsParent = GetOrCreateGameObject(playfieldGo, "Mechs");
+
+ var rotatorGo = CreateEmptyGameObject(mechsParent, "Cannon");
+ var rotatorComp = rotatorGo.AddComponent();
+ var mechComp = rotatorGo.AddComponent();
+ mechComp.Target = rotatorComp;
+ mechComp.NumSteps = 240;
+ mechComp.Marks = new[] {
+ new StepRotatorMark("Gun Home", "gun_home_switch", 0, 5),
+ new StepRotatorMark("Gun Mark", "gun_mark_switch", 98, 105),
+ };
+
+ rotatorComp.Target = cannonComp;
+ rotatorComp.RotateWith = new IRotatableComponent[] {
+ playfieldGo.transform.Find("Kickers/sw31").GetComponent(),
+ };
+ }
+
#endregion
#region Materials
@@ -877,8 +916,8 @@ public void T2Eyes(GameObject go)
[NameMatch("L55")]
[NameMatch("L56")]
[NameMatch("L57")]
- [NameMatch("L58")]
public void RightRedRect(GameObject go) => LightPos(go, 8.5f, -11.7f, -50f);
+ [NameMatch("L58")] public void L58Pos(GameObject go) => LightPos(go, -2.3f, 20f, -50f);
[NameMatch("L61")]
[NameMatch("L62")]
diff --git a/VisualPinball.Unity/VisualPinball.Unity/Game/BallRollerComponent.cs b/VisualPinball.Unity/VisualPinball.Unity/Game/BallRollerComponent.cs
index ae7a1d475..78edc4bf6 100644
--- a/VisualPinball.Unity/VisualPinball.Unity/Game/BallRollerComponent.cs
+++ b/VisualPinball.Unity/VisualPinball.Unity/Game/BallRollerComponent.cs
@@ -31,7 +31,7 @@ public class BallRollerComponent : MonoBehaviour
private Plane _playfieldPlane;
private EntityManager _entityManager;
- private Entity _ballEntity;
+ private Entity _ballEntity = Entity.Null;
private EntityQuery _ballEntityQuery;
private void Awake()
@@ -84,17 +84,18 @@ private void Update()
}
}
- } else if (Mouse.current.middleButton.isPressed) {
+ } else if (Mouse.current.middleButton.isPressed && _ballEntity != Entity.Null) {
if (GetCursorPositionOnPlayfield(out var mousePosition)) {
var ballData = _entityManager.GetComponentData(_ballEntity);
UpdateBall(ref ballData, mousePosition);
}
}
- if (Mouse.current.middleButton.wasReleasedThisFrame) {
+ if (Mouse.current.middleButton.wasReleasedThisFrame && _ballEntity != Entity.Null) {
var ballData = _entityManager.GetComponentData(_ballEntity);
ballData.ManualControl = false;
_entityManager.SetComponentData(_ballEntity, ballData);
+ _ballEntity = Entity.Null;
}
}
diff --git a/VisualPinball.Unity/VisualPinball.Unity/Game/DeviceCoil.cs b/VisualPinball.Unity/VisualPinball.Unity/Game/DeviceCoil.cs
index 25646c10c..e1d6c75b1 100644
--- a/VisualPinball.Unity/VisualPinball.Unity/Game/DeviceCoil.cs
+++ b/VisualPinball.Unity/VisualPinball.Unity/Game/DeviceCoil.cs
@@ -22,22 +22,22 @@ public class DeviceCoil: IApiCoil
{
public bool IsEnabled;
- private readonly Action _onEnable;
- private readonly Action _onDisable;
+ protected Action OnEnable;
+ protected Action OnDisable;
public DeviceCoil(Action onEnable = null, Action onDisable = null)
{
- _onEnable = onEnable;
- _onDisable = onDisable;
+ OnEnable = onEnable;
+ OnDisable = onDisable;
}
public void OnCoil(bool enabled)
{
IsEnabled = enabled;
if (enabled) {
- _onEnable?.Invoke();
+ OnEnable?.Invoke();
} else {
- _onDisable?.Invoke();
+ OnDisable?.Invoke();
}
#if UNITY_EDITOR
UnityEditorInternal.InternalEditorUtility.RepaintAllViews();
diff --git a/VisualPinball.Unity/VisualPinball.Unity/Game/DeviceSwitch.cs b/VisualPinball.Unity/VisualPinball.Unity/Game/DeviceSwitch.cs
index 5d9a36739..7d9d35118 100644
--- a/VisualPinball.Unity/VisualPinball.Unity/Game/DeviceSwitch.cs
+++ b/VisualPinball.Unity/VisualPinball.Unity/Game/DeviceSwitch.cs
@@ -41,6 +41,8 @@ public class DeviceSwitch : IApiSwitch
///
public bool IsSwitchClosed => _switchDefault == SwitchDefault.NormallyClosed ? !IsSwitchEnabled : IsSwitchEnabled;
+ public string Id => _switchHandler.Name;
+
///
/// Indicates whether the switch is currently opened or closed.
///
diff --git a/VisualPinball.Unity/VisualPinball.Unity/Game/Engine/DefaultGamelogicEngine.cs b/VisualPinball.Unity/VisualPinball.Unity/Game/Engine/DefaultGamelogicEngine.cs
index 08e31e031..2f58b56a0 100644
--- a/VisualPinball.Unity/VisualPinball.Unity/Game/Engine/DefaultGamelogicEngine.cs
+++ b/VisualPinball.Unity/VisualPinball.Unity/Game/Engine/DefaultGamelogicEngine.cs
@@ -67,6 +67,10 @@ public class DefaultGamelogicEngine : MonoBehaviour, IGamelogicEngine
private const string SwCreateBall = "s_create_ball";
private const string SwRedBumper = "s_red_bumper";
+ private const string SwCannon = "s_cannon";
+ private const string SwMotorStart = "s_motor_start";
+ private const string SwMotorEnd = "s_motor_end";
+
public GamelogicEngineSwitch[] AvailableSwitches => _availableSwitches.ToArray();
private readonly List _availableSwitches = new List {
new GamelogicEngineSwitch(SwLeftFlipper) { Description = "Left Flipper (Button)", InputActionHint = InputConstants.ActionLeftFlipper },
@@ -78,7 +82,11 @@ public class DefaultGamelogicEngine : MonoBehaviour, IGamelogicEngine
new GamelogicEngineSwitch(SwTrough4) { Description = "Trough 4", DeviceHint = "^Trough\\s*\\d?", DeviceItemHint = "4"},
new GamelogicEngineSwitch(SwTrough4) { Description = "Trough 4", DeviceHint = "^Trough\\s*\\d?", DeviceItemHint = "4"},
new GamelogicEngineSwitch(SwCreateBall) { Description = "Create Debug Ball", InputActionHint = InputConstants.ActionCreateBall, InputMapHint = InputConstants.MapDebug },
- new GamelogicEngineSwitch(SwRedBumper) { Description = "Red Bumper", DeviceHint = "^Bumper1$" }
+ new GamelogicEngineSwitch(SwRedBumper) { Description = "Red Bumper", DeviceHint = "^Bumper1$" },
+
+ new GamelogicEngineSwitch(SwCannon) { Description = "Cannon" },
+ new GamelogicEngineSwitch(SwMotorStart) { Description = "Motor Start" },
+ new GamelogicEngineSwitch(SwMotorEnd) { Description = "Motor End" }
};
private const string CoilLeftFlipperMain = "c_flipper_left_main";
@@ -87,6 +95,7 @@ public class DefaultGamelogicEngine : MonoBehaviour, IGamelogicEngine
private const string CoilRightFlipperHold = "c_flipper_right_hold";
private const string CoilTroughEntry = "c_trough_entry";
private const string CoilTroughEject = "c_trough_eject";
+ private const string CoilMotorStart = "c_motor_start";
public GamelogicEngineCoil[] AvailableCoils => _availableCoils.ToArray();
private readonly List _availableCoils = new List {
@@ -96,6 +105,7 @@ public class DefaultGamelogicEngine : MonoBehaviour, IGamelogicEngine
new GamelogicEngineCoil(CoilRightFlipperHold) { Description = "Right Flipper (Hold)", DeviceHint = "^(RightFlipper|RFlipper|FlipperRight|FlipperR)$", DeviceItemHint = FlipperComponent.HoldCoilItem },
new GamelogicEngineCoil(CoilTroughEject) { Description = "Trough Eject", DeviceHint = "^Trough\\s*\\d?", DeviceItemHint = TroughComponent.EjectCoilId},
new GamelogicEngineCoil(CoilTroughEntry) { Description = "Trough Entry", DeviceHint = "^Trough\\s*\\d?", DeviceItemHint = TroughComponent.EntryCoilId},
+ new GamelogicEngineCoil(CoilMotorStart) { Description = "Cannon Motor" },
};
public GamelogicEngineWire[] AvailableWires { get; } = {
@@ -256,6 +266,23 @@ public void Switch(string id, bool isClosed)
}
break;
}
+
+ case SwCannon: {
+ SetCoil(CoilMotorStart, true);
+ break;
+ }
+
+ case SwMotorStart: {
+ if (isClosed) {
+ SetCoil(CoilMotorStart, false);
+ }
+ break;
+ }
+
+ case SwMotorEnd: {
+
+ break;
+ }
}
}
diff --git a/VisualPinball.Unity/VisualPinball.Unity/Game/Player.cs b/VisualPinball.Unity/VisualPinball.Unity/Game/Player.cs
index 68cd10352..a009db5ff 100644
--- a/VisualPinball.Unity/VisualPinball.Unity/Game/Player.cs
+++ b/VisualPinball.Unity/VisualPinball.Unity/Game/Player.cs
@@ -239,9 +239,9 @@ public void RegisterLampGroup(LightGroupComponent component)
Register(new LightGroupApi(component.Lights.Select(l => l.GetApi(this)).ToArray()), component);
}
- public void RegisterCannonComponent(CannonComponent component)
+ public void RegisterStepRotator(StepRotatorMechComponent component)
{
- Register(new CannonApi(component.gameObject, this), component);
+ Register(new StepRotatorMechApi(component.gameObject, this), component);
}
public void RegisterDropTargetBankComponent(DropTargetBankComponent component)
diff --git a/VisualPinball.Unity/VisualPinball.Unity/Game/SwitchHandler.cs b/VisualPinball.Unity/VisualPinball.Unity/Game/SwitchHandler.cs
index 564ade289..3bc557b11 100644
--- a/VisualPinball.Unity/VisualPinball.Unity/Game/SwitchHandler.cs
+++ b/VisualPinball.Unity/VisualPinball.Unity/Game/SwitchHandler.cs
@@ -22,7 +22,7 @@ public class SwitchHandler
///
public bool IsEnabled;
- private readonly string _name;
+ public readonly string Name;
private readonly Player _player;
private IGamelogicEngine Engine => _player.GamelogicEngine;
@@ -43,7 +43,7 @@ public class SwitchHandler
public SwitchHandler(string name, Player player, bool isEnabled = false)
{
- _name = name;
+ Name = name;
_player = player;
IsEnabled = isEnabled;
}
@@ -163,7 +163,7 @@ internal void ScheduleSwitch(bool enabled, int delay, Action onSwitched)
// handle own status
SimulationSystemGroup.ScheduleAction(delay, () => {
- Debug.Log($"Setting scheduled switch {_name} to {enabled}.");
+ Debug.Log($"Setting scheduled switch {Name} to {enabled}.");
IsEnabled = enabled;
#if UNITY_EDITOR
diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Flipper/FlipperApi.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Flipper/FlipperApi.cs
index 5d41e5b89..b0bbb4780 100644
--- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Flipper/FlipperApi.cs
+++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Flipper/FlipperApi.cs
@@ -107,6 +107,15 @@ public void RotateToStart()
EngineProvider.Get().FlipperRotateToStart(Entity);
}
+ internal float StartAngle
+ {
+ set {
+ var staticData = EntityManager.GetComponentData(Entity);
+ staticData.AngleStart = value;
+ EntityManager.SetComponentData(Entity, staticData);
+ }
+ }
+
#region Coil Handling
private DeviceCoil _mainCoil;
diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Flipper/FlipperComponent.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Flipper/FlipperComponent.cs
index 6ea2aef75..609964e63 100644
--- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Flipper/FlipperComponent.cs
+++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Flipper/FlipperComponent.cs
@@ -41,7 +41,8 @@ namespace VisualPinball.Unity
[AddComponentMenu("Visual Pinball/Game Item/Flipper")]
[HelpURL("https://docs.visualpinball.org/creators-guide/manual/mechanisms/flippers.html")]
public class FlipperComponent : MainRenderableComponent,
- IFlipperData, ISwitchDeviceComponent, ICoilDeviceComponent, IOnSurfaceComponent, IConvertGameObjectToEntity
+ IFlipperData, ISwitchDeviceComponent, ICoilDeviceComponent, IOnSurfaceComponent,
+ IRotatableComponent, IConvertGameObjectToEntity
{
#region Data
@@ -177,6 +178,26 @@ public override void UpdateTransforms()
t.localEulerAngles = new Vector3(0, 0, _startAngle);
}
+ private FlipperApi _flipperApi;
+ public float _originalRotateZ;
+
+ public float RotateZ {
+ set {
+ _startAngle = _originalRotateZ + value;
+ _flipperApi.StartAngle = _originalRotateZ + value;
+ UpdateTransforms();
+ }
+ }
+
+ public float2 RotatedPosition {
+ get => new(Position.x, Position.y);
+ set {
+ Position.x = value.x;
+ Position.y = value.y;
+ UpdateTransforms();
+ }
+ }
+
#endregion
#region Conversion
@@ -545,6 +566,20 @@ public TriggerData CreateCorrectionTriggerData()
#endregion
+ #region Runtime
+
+ private void Awake()
+ {
+ _originalRotateZ = _startAngle;
+ }
+
+ private void Start()
+ {
+ _flipperApi = GetComponentInParent().TableApi.Flipper(this);
+ }
+
+ #endregion
+
#region DOTS Data
private FlipperStaticData GetMaterialData(FlipperColliderComponent colliderComponent)
diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/IRotatableComponent.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/IRotatableComponent.cs
new file mode 100644
index 000000000..37c6ae560
--- /dev/null
+++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/IRotatableComponent.cs
@@ -0,0 +1,36 @@
+// Visual Pinball Engine
+// Copyright (C) 2021 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.Collections.Generic;
+using Unity.Mathematics;
+using VisualPinball.Engine.Game.Engines;
+
+namespace VisualPinball.Unity
+{
+ ///
+ /// A component that can be rotated along the Z-axis
+ ///
+ public interface IRotatableComponent
+ {
+ ///
+ /// Sets the rotation
+ ///
+ float RotateZ { set; }
+
+ float2 RotatedPosition { set; get; }
+ }
+
+}
diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/IRotatableComponent.cs.meta b/VisualPinball.Unity/VisualPinball.Unity/VPT/IRotatableComponent.cs.meta
new file mode 100644
index 000000000..81f576e12
--- /dev/null
+++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/IRotatableComponent.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 28e93b51aff5c2a459a72b49fba40f82
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Kicker/KickerApi.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Kicker/KickerApi.cs
index 8fed6e36e..b2ca5606d 100644
--- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Kicker/KickerApi.cs
+++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Kicker/KickerApi.cs
@@ -48,13 +48,17 @@ public class KickerApi : CollidableApi
public event EventHandler Switch;
- private readonly Dictionary _coils = new Dictionary();
+ internal float3 Position => new(MainComponent.Position.x, MainComponent.Position.y, MainComponent.PositionZ);
+
+ public KickerDeviceCoil KickerCoil => _coils.Values.FirstOrDefault();
+
+ private readonly Dictionary _coils = new Dictionary();
public KickerApi(GameObject go, Entity entity, Entity parentEntity, Player player)
: base(go, entity, parentEntity, player)
{
foreach (var coil in MainComponent.Coils) {
- _coils[coil.Id] = new DeviceCoil(() => Kick(coil.Angle, coil.Speed, coil.Inclination));
+ _coils[coil.Id] = new KickerDeviceCoil(coil, this);
}
}
@@ -83,11 +87,6 @@ public void CreateSizedBall(float radius)
BallManager.CreateBall(MainComponent, radius, 1f, Entity);
}
- public void Kick()
- {
- SimulationSystemGroup.QueueAfterBallCreation(() => KickXYZ(Entity, ColliderComponent.EjectAngle, ColliderComponent.EjectSpeed, 0, 0, 0, 0));
- }
-
public void Kick(float angle, float speed, float inclination = 0)
{
SimulationSystemGroup.QueueAfterBallCreation(() => KickXYZ(Entity, angle, speed, inclination, 0, 0, 0));
@@ -128,6 +127,15 @@ internal BallData GetBallData()
: default;
}
+ internal Entity BallEntity
+ {
+ get {
+ var entityManager = World.DefaultGameObjectInjectionWorld.EntityManager;
+ var kickerCollisionData = entityManager.GetComponentData(Entity);
+ return kickerCollisionData.BallEntity;
+ }
+ }
+
#region Wiring
public bool IsSwitchEnabled => SwitchHandler.IsEnabled;
@@ -145,6 +153,8 @@ void IApiSwitch.DestroyBall(Entity ballEntity)
IApiWireDest IApiWireDeviceDest.Wire(string deviceItem) => Coil(deviceItem);
+ public IApiCoil Coil() => _coils.Values.FirstOrDefault();
+
private IApiCoil Coil(string deviceItem)
{
if (_coils.ContainsKey(deviceItem)) {
@@ -267,4 +277,20 @@ void IApiHittable.OnHit(Entity ballEntity, bool isUnHit)
#endregion
}
+
+ public class KickerDeviceCoil : DeviceCoil
+ {
+ public readonly KickerCoil Coil;
+ private readonly KickerApi _kickerApi;
+
+ public KickerDeviceCoil(KickerCoil coil, KickerApi api)
+ {
+ Coil = coil;
+ _kickerApi = api;
+ OnEnable = Kick;
+ }
+
+ private void Kick() => _kickerApi.Kick(Coil.Angle, Coil.Speed, Coil.Inclination);
+
+ }
}
diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Kicker/KickerCollider.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Kicker/KickerCollider.cs
index 1ad9e875e..93d5b822c 100644
--- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Kicker/KickerCollider.cs
+++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Kicker/KickerCollider.cs
@@ -100,9 +100,11 @@ public static void Collide(ref BallData ball, ref NativeQueue.Paralle
// Only mess with variables if ball was not kicked during event
ball.Velocity = float3.zero;
ball.AngularMomentum = float3.zero;
- var posZ = staticData.FallThrough
- ? staticData.ZLow - ball.Radius - 5.0f
- : staticData.ZLow + ball.Radius;
+ var posZ = !staticData.FallIn
+ ? staticData.ZLow + ball.Radius * 2
+ : staticData.FallThrough
+ ? staticData.ZLow - ball.Radius - 5.0f
+ : staticData.ZLow + ball.Radius;
ball.Position = new float3(staticData.Center.x, staticData.Center.y, posZ);
} else {
diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Kicker/KickerColliderComponent.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Kicker/KickerColliderComponent.cs
index 9a0e7b41e..dd62a50fc 100644
--- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Kicker/KickerColliderComponent.cs
+++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Kicker/KickerColliderComponent.cs
@@ -43,17 +43,12 @@ public class KickerColliderComponent : ColliderComponent,
- ICoilDeviceComponent, ITriggerComponent, IBallCreationPosition, IOnSurfaceComponent, IConvertGameObjectToEntity, ISerializationCallbackReceiver
+ ICoilDeviceComponent, ITriggerComponent, IBallCreationPosition, IOnSurfaceComponent,
+ IRotatableComponent, IConvertGameObjectToEntity, ISerializationCallbackReceiver
{
#region Data
@@ -57,7 +58,7 @@ public class KickerComponent : MainRenderableComponent,
[Tooltip("On which surface the kicker is attached to. Updates Z-translation.")]
public MonoBehaviour _surface;
- public List Coils = new List {
+ public List Coils = new() {
new KickerCoil { Name = "Default Coil" }
};
@@ -131,6 +132,26 @@ public override void UpdateTransforms()
};
}
+ private float _originalRotationZ;
+ private float _originalKickerAngle;
+ private KickerApi _kickerApi;
+
+ public float RotateZ {
+ set {
+ Orientation = _originalRotationZ + value;
+ _kickerApi.KickerCoil.Coil.Angle = _originalKickerAngle + value;
+ }
+ }
+
+ public float2 RotatedPosition {
+ get => new(Position.x, Position.y);
+ set {
+ Position.x = value.x;
+ Position.y = value.y;
+ UpdateTransforms();
+ }
+ }
+
#endregion
#region Conversion
@@ -144,6 +165,7 @@ public void Convert(Entity entity, EntityManager dstManager, GameObjectConversio
if (colliderComponent) {
dstManager.AddComponentData(entity, new KickerStaticData {
Center = Position,
+ FallIn = colliderComponent.FallIn,
FallThrough = colliderComponent.FallThrough,
HitAccuracy = colliderComponent.HitAccuracy,
Scatter = colliderComponent.Scatter,
@@ -205,8 +227,6 @@ public override IEnumerable SetData(KickerData data)
colliderComponent.HitHeight = data.HitHeight;
colliderComponent.FallThrough = data.FallThrough;
colliderComponent.LegacyMode = data.LegacyMode;
- colliderComponent.EjectAngle = data.Angle;
- colliderComponent.EjectSpeed = data.Speed;
updatedComponents.Add(colliderComponent);
}
@@ -242,8 +262,6 @@ public override KickerData CopyDataTo(KickerData data, string[] materialNames, s
data.HitHeight = colliderComponent.HitHeight;
data.FallThrough = colliderComponent.FallThrough;
data.LegacyMode = colliderComponent.LegacyMode;
- data.Angle = colliderComponent.EjectAngle;
- data.Speed = colliderComponent.EjectSpeed;
} else {
data.IsEnabled = false;
@@ -280,6 +298,21 @@ public void OnAfterDeserialize()
#endregion
+ #region Runtime
+
+ private void Awake()
+ {
+ _originalRotationZ = Orientation;
+ }
+
+ private void Start()
+ {
+ _kickerApi = GetComponentInParent().TableApi.Kicker(this);
+ _originalKickerAngle = _kickerApi.KickerCoil.Coil.Angle;
+ }
+
+ #endregion
+
#region IBallCreationPosition
public Vertex3D GetBallCreationPosition() => new Vertex3D(Position.x, Position.y, PositionZ);
diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Kicker/KickerStaticData.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Kicker/KickerStaticData.cs
index 71793f1b1..787907fbd 100644
--- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Kicker/KickerStaticData.cs
+++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Kicker/KickerStaticData.cs
@@ -23,6 +23,7 @@ internal struct KickerStaticData : IComponentData
{
public bool LegacyMode;
public bool FallThrough;
+ public bool FallIn;
public float2 Center;
public float ZLow;
public float HitAccuracy;
diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/MainComponent.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/MainComponent.cs
index c5eecb062..95b3fe9ac 100644
--- a/VisualPinball.Unity/VisualPinball.Unity/VPT/MainComponent.cs
+++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/MainComponent.cs
@@ -95,6 +95,9 @@ protected Entity ParentEntity {
public bool IsCorrectlyParented {
get {
+ if (!ValidParents.Any()) {
+ return true;
+ }
var parentComponent = ParentComponent;
return parentComponent == null || ValidParents.Any(validParent => parentComponent.GetType() == validParent);
}
diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/MainRenderableComponent.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/MainRenderableComponent.cs
index 81a94b31c..7df39f3ab 100644
--- a/VisualPinball.Unity/VisualPinball.Unity/VPT/MainRenderableComponent.cs
+++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/MainRenderableComponent.cs
@@ -90,9 +90,10 @@ protected void Convert(Entity entity, EntityManager dstManager)
{
Entity = entity;
var parentComponent = ParentComponent;
- if (parentComponent != null && !(parentComponent is TableComponent)) {
- ParentEntity = parentComponent.Entity;
- }
+ // todo remove the parenting stuff
+ // if (parentComponent != null && !(parentComponent is TableComponent)) {
+ // ParentEntity = parentComponent.Entity;
+ // }
}
protected float SurfaceHeight(ISurfaceComponent surface, Vector2 position)
diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Mech/CannonApi.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Mech/CannonApi.cs
deleted file mode 100644
index c5841be08..000000000
--- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Mech/CannonApi.cs
+++ /dev/null
@@ -1,178 +0,0 @@
-// Visual Pinball Engine
-// Copyright (C) 2021 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 Logger = NLog.Logger;
-using NLog;
-using UnityEngine;
-
-namespace VisualPinball.Unity
-{
- public class CannonApi : IApi, IApiSwitchDevice, IApiCoilDevice
- {
- private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
-
- public const int Length = 240;
-
- private enum Direction
- {
- Forward = 0,
- Reverse = 1
- }
-
- private readonly CannonComponent _cannonComponent;
- private Player _player;
-
- public DeviceCoil GunMotorCoil;
- public DeviceSwitch GunHomeSwitch;
- public DeviceSwitch GunMarkSwitch;
-
- public event EventHandler Init;
-
- private bool _enabled;
- private float _position;
- private Direction _direction;
-
- internal CannonApi(GameObject go, Player player)
- {
- _cannonComponent = go.GetComponentInChildren();
- _player = player;
- }
-
- IApiCoil IApiCoilDevice.Coil(string deviceItem) => Coil(deviceItem);
-
- private IApiCoil Coil(string deviceItem)
- {
- return deviceItem switch
- {
- CannonComponent.GunMotorCoilItem => GunMotorCoil,
- _ => throw new ArgumentException($"Unknown coil \"{deviceItem}\". Valid name is: \"{CannonComponent.GunMotorCoilItem}\".")
- };
- }
-
- IApiSwitch IApiSwitchDevice.Switch(string deviceItem)
- {
- return deviceItem switch
- {
- CannonComponent.GunHomeSwitchItem => GunHomeSwitch,
- CannonComponent.GunMarkSwitchItem => GunMarkSwitch,
- _ => throw new ArgumentException($"Unknown switch \"{deviceItem}\". Valid names are: [ \"{CannonComponent.GunHomeSwitchItem}\", \"{CannonComponent.GunMarkSwitchItem}\" ].")
- };
- }
-
- void IApi.OnInit(BallManager ballManager)
- {
- _enabled = false;
- _position = 0;
- _direction = Direction.Forward;
-
- GunMotorCoil = new DeviceCoil(OnGunMotorCoilEnabled, OnGunMotorCoilDisabled);
-
- GunHomeSwitch = new DeviceSwitch(CannonComponent.GunHomeSwitchItem, false, SwitchDefault.NormallyOpen, _player);
- GunHomeSwitch.SetSwitch(true);
-
- GunMarkSwitch = new DeviceSwitch(CannonComponent.GunMarkSwitchItem, false, SwitchDefault.NormallyOpen, _player);
- GunMarkSwitch.SetSwitch(false);
-
- _player.OnUpdate += OnUpdate;
-
- Init?.Invoke(this, EventArgs.Empty);
- }
-
- private void OnGunMotorCoilEnabled()
- {
- _enabled = true;
-
- Logger.Info("OnGunMotorCoilEnabled - starting rotation");
- }
-
- private void OnGunMotorCoilDisabled()
- {
- _enabled = false;
-
- Logger.Info("OnGunMotorCoilDisabled - stopping rotation");
- }
-
- private void OnUpdate(object sender, EventArgs eventArgs)
- {
- if (!_enabled)
- {
- return;
- }
-
- float speed = (Length * 2 / 6.5f) * Time.deltaTime;
-
- if (_direction == Direction.Forward)
- {
- _position += speed;
-
- if (_position >= Length)
- {
- _position = Length - (_position - Length);
-
- _direction = Direction.Reverse;
- }
- }
- else
- {
- _position -= speed;
-
- if (_position <= 0)
- {
- _position = -_position;
-
- _direction = Direction.Forward;
- }
- }
-
- if (_position >= 0 && _position <= 5)
- {
- if (!GunHomeSwitch.IsSwitchEnabled)
- {
- GunHomeSwitch.SetSwitch(true);
- }
- }
- else if (GunHomeSwitch.IsSwitchEnabled)
- {
- GunHomeSwitch.SetSwitch(false);
- }
-
- if (_position >= 98 && _position <= 105)
- {
- if (!GunMarkSwitch.IsSwitchEnabled)
- {
- GunMarkSwitch.SetSwitch(true);
- }
- }
- else if (GunMarkSwitch.IsSwitchEnabled)
- {
- GunMarkSwitch.SetSwitch(false);
- }
-
- _cannonComponent.UpdateRotation(_position / Length);
-
- Logger.Debug($"{_cannonComponent.name} position={_position}");
- }
-
- void IApi.OnDestroy()
- {
- _player.OnUpdate -= OnUpdate;
-
- Logger.Info($"Destroying {_cannonComponent.name}");
- }
- }
-}
-
diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Mech/CannonComponent.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Mech/CannonComponent.cs
deleted file mode 100644
index 4b37ce6b7..000000000
--- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Mech/CannonComponent.cs
+++ /dev/null
@@ -1,77 +0,0 @@
-// Visual Pinball Engine
-// Copyright (C) 2021 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.Collections.Generic;
-using UnityEngine;
-using VisualPinball.Engine.Game.Engines;
-using Logger = NLog.Logger;
-using NLog;
-
-namespace VisualPinball.Unity
-{
- [AddComponentMenu("Visual Pinball/Game Item/Cannon")]
- public class CannonComponent : MonoBehaviour, ISwitchDeviceComponent, ICoilDeviceComponent
- {
- private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
-
- public const string GunMotorCoilItem = "gun_motor_coil";
-
- public IEnumerable AvailableCoils => new[] {
- new GamelogicEngineCoil(GunMotorCoilItem) {
- Description = "Gun Motor"
- }
- };
-
- public const string GunMarkSwitchItem = "gun_mark_switch";
- public const string GunHomeSwitchItem = "gun_home_switch";
-
- public IEnumerable AvailableSwitches => new[] {
- new GamelogicEngineSwitch(GunMarkSwitchItem) {
- Description = "Gun Mark"
- },
- new GamelogicEngineSwitch(GunHomeSwitchItem) {
- Description = "Gun Home"
- }
- };
-
- public SwitchDefault SwitchDefault => SwitchDefault.NormallyOpen;
-
- IEnumerable IDeviceComponent.AvailableDeviceItems => AvailableCoils;
- IEnumerable IDeviceComponent.AvailableDeviceItems => AvailableSwitches;
- IEnumerable IWireableComponent.AvailableWireDestinations => AvailableCoils;
- IEnumerable IDeviceComponent.AvailableDeviceItems => AvailableCoils;
-
- private void Awake()
- {
- var player = GetComponentInParent();
- if (player == null)
- {
- Logger.Error($"Cannot find player for cannon {name}.");
- return;
- }
-
- player.RegisterCannonComponent(this);
- }
-
- public void UpdateRotation(float y)
- {
- var rotation = transform.rotation;
- rotation.y = -(y * 0.65f);
-
- transform.rotation = rotation;
- }
- }
-}
diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Mech/RotatorComponent.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Mech/RotatorComponent.cs
new file mode 100644
index 000000000..143af97e6
--- /dev/null
+++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Mech/RotatorComponent.cs
@@ -0,0 +1,134 @@
+// Visual Pinball Engine
+// Copyright (C) 2021 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.Generic;
+using System.Linq;
+using Unity.Entities;
+using Unity.Mathematics;
+using UnityEngine;
+
+namespace VisualPinball.Unity
+{
+ [AddComponentMenu("Visual Pinball/Game Item/Rotator")]
+ public class RotatorComponent : MonoBehaviour
+ {
+ #region Data
+
+ public IRotatableComponent Target { get => _target as IRotatableComponent; set => _target = value as MonoBehaviour; }
+ [SerializeField]
+ [TypeRestriction(typeof(IRotatableComponent), PickerLabel = "Rotatable Objects")]
+ [Tooltip("The target that will rotate.")]
+ public MonoBehaviour _target;
+
+ [SerializeField]
+ [TypeRestriction(typeof(IRotatableComponent), PickerLabel = "Rotatable Objects")]
+ [Tooltip("Other objects at will rotate around the target.")]
+ public MonoBehaviour[] _rotateWith;
+ public IRotatableComponent[] RotateWith {
+ get => _rotateWith.OfType().ToArray();
+ set => _rotateWith = value.OfType().ToArray();
+ }
+
+ #endregion
+
+ #region Access
+
+ internal IEnumerable Kickers => _rotateWith.OfType();
+
+ #endregion
+
+ #region Runtime
+
+ private Player _player;
+ private KickerApi[] _kickers;
+ private (KickerApi kicker, float distance, float angle, Entity ballEntity)[] _ballEntities;
+
+ private Dictionary _rotatingObjectDistances = new();
+ private static EntityManager EntityManager => World.DefaultGameObjectInjectionWorld.EntityManager;
+
+ private void Awake()
+ {
+ _player = GetComponentInParent();
+
+ var pos = Target.RotatedPosition;
+ _rotatingObjectDistances = RotateWith.ToDictionary(
+ r => r,
+ r => (
+ math.distance(pos, r.RotatedPosition),
+ math.sign(pos.x - r.RotatedPosition.x) * Vector2.Angle(r.RotatedPosition - pos, new float2(0f, -1f))
+ )
+ );
+ }
+
+ private void Start()
+ {
+ _kickers = Kickers
+ .Select(k => _player.TableApi.Kicker(k))
+ .ToArray();
+ }
+
+ public void StartRotating()
+ {
+ var pos = Target.RotatedPosition;
+ _ballEntities = _kickers.Where(k => k.HasBall()).Select(k => (
+ k,
+ math.distance(pos, k.Position.xy),
+ math.sign(pos.x - k.Position.x) * Vector2.Angle(k.Position.xy - pos, new float2(0f, -1f)),
+ k.BallEntity)
+ ).ToArray();
+ }
+
+ public void UpdateRotation(float angleDeg)
+ {
+ // rotate target
+ Target.RotateZ = -angleDeg;
+ var pos = Target.RotatedPosition;
+
+ // rotate objects
+ foreach (var obj in _rotatingObjectDistances.Keys) {
+ var (distance, angle) = _rotatingObjectDistances[obj];
+ obj.RotateZ = -angleDeg;
+ obj.RotatedPosition = new float2(
+ pos.x -distance * math.sin(math.radians(angleDeg + angle)),
+ pos.y -distance * math.cos(math.radians(angleDeg + angle))
+ );
+ }
+
+ // rotate ball(s) in kicker(s)
+ foreach (var (kicker, distance, angle, ballEntity) in _ballEntities) {
+ if (!kicker.HasBall()) {
+ return;
+ }
+ var ballData = EntityManager.GetComponentData(ballEntity);
+ ballData.Position = new float3(
+ pos.x -distance * math.sin(math.radians(angleDeg + angle)),
+ pos.y -distance * math.cos(math.radians(angleDeg + angle)),
+ ballData.Position.z
+ );
+ ballData.Velocity = float3.zero;
+ ballData.AngularMomentum = float3.zero;
+ ballData.AngularVelocity = float3.zero;
+
+ EntityManager.SetComponentData(ballEntity, ballData);
+ }
+ }
+
+ #endregion
+ }
+
+}
diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Mech/RotatorComponent.cs.meta b/VisualPinball.Unity/VisualPinball.Unity/VPT/Mech/RotatorComponent.cs.meta
new file mode 100644
index 000000000..1377eb924
--- /dev/null
+++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Mech/RotatorComponent.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 815586529ac0612409629e7eba366f76
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {fileID: 2800000, guid: 311ce6f9db0cc1148b42d67735584430, type: 3}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Mech/StepRotatorMechApi.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Mech/StepRotatorMechApi.cs
new file mode 100644
index 000000000..afe055e29
--- /dev/null
+++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Mech/StepRotatorMechApi.cs
@@ -0,0 +1,163 @@
+// Visual Pinball Engine
+// Copyright (C) 2021 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 System.Collections.Generic;
+using System.Linq;
+using NLog;
+using UnityEngine;
+using Logger = NLog.Logger;
+
+namespace VisualPinball.Unity
+{
+ public class StepRotatorMechApi : IApi, IApiSwitchDevice, IApiCoilDevice
+ {
+ public event EventHandler Init;
+
+ private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
+
+ private enum Direction
+ {
+ Forward = 0,
+ Reverse = 1
+ }
+
+ private readonly Player _player;
+ private readonly StepRotatorMechComponent _component;
+
+ private DeviceCoil _motorCoil;
+ private bool _enabled;
+ private float _currentStep;
+ private Direction _direction;
+
+ private Dictionary _switches;
+ private Dictionary _marks;
+
+ internal StepRotatorMechApi(GameObject go, Player player)
+ {
+ _component = go.GetComponentInChildren();
+ _player = player;
+ }
+
+
+ void IApi.OnInit(BallManager ballManager)
+ {
+ _enabled = false;
+ _currentStep = 0;
+ _direction = Direction.Forward;
+
+ _motorCoil = new DeviceCoil(OnMotorCoilEnabled, OnMotorCoilDisabled);
+
+ _marks = _component.Marks.ToDictionary(m => m.SwitchId, m => m);
+ _switches = _component.Marks.ToDictionary(m => m.SwitchId, m => new DeviceSwitch(m.SwitchId, false, SwitchDefault.NormallyOpen, _player));
+ var i = 0;
+ foreach (var sw in _switches.Values) {
+ sw.SetSwitch(i == 0);
+ i++;
+ }
+
+ Init?.Invoke(this, EventArgs.Empty);
+ }
+
+ IApiCoil IApiCoilDevice.Coil(string deviceItem) => Coil(deviceItem);
+
+ private IApiCoil Coil(string deviceItem)
+ {
+ return deviceItem switch {
+ StepRotatorMechComponent.MotorCoilItem => _motorCoil,
+ _ => throw new ArgumentException($"Unknown coil \"{deviceItem}\". Valid name is: \"{StepRotatorMechComponent.MotorCoilItem}\".")
+ };
+ }
+
+ IApiSwitch IApiSwitchDevice.Switch(string deviceItem)
+ {
+ if (!_switches.ContainsKey(deviceItem)) {
+ throw new ArgumentException($"Unknown switch \"{deviceItem}\". Valid names are: [ \"{string.Join("\", ", _switches.Keys)}\" ].");
+ }
+ return _switches[deviceItem];
+ }
+
+ private void OnMotorCoilEnabled()
+ {
+ _player.OnUpdate += OnUpdate;
+ _component.Target.StartRotating();
+ _enabled = true;
+ Logger.Info("OnGunMotorCoilEnabled - starting rotation");
+ }
+
+ private void OnMotorCoilDisabled()
+ {
+ _enabled = false;
+ Logger.Info("OnGunMotorCoilDisabled - stopping rotation");
+ _player.OnUpdate -= OnUpdate;
+ }
+
+ private void OnUpdate(object sender, EventArgs eventArgs)
+ {
+ if (!_enabled || _component.NumSteps == 0)
+ {
+ return;
+ }
+
+ var numSteps = _component.NumSteps;
+ var speed = numSteps * 2 / 6.5f * Time.deltaTime;
+
+ // determine position
+ if (_direction == Direction.Forward)
+ {
+ _currentStep += speed;
+
+ if (_currentStep >= numSteps)
+ {
+ _currentStep = numSteps - (_currentStep - numSteps);
+ _direction = Direction.Reverse;
+ }
+ }
+ else
+ {
+ _currentStep -= speed;
+
+ if (_currentStep <= 0)
+ {
+ _currentStep = -_currentStep;
+ _direction = Direction.Forward;
+ }
+ }
+
+ // check if any mark hit
+ foreach (var mark in _marks.Values) {
+ var sw = _switches[mark.SwitchId];
+ if (_currentStep >= mark.StepBeginning && _currentStep <= mark.StepEnd) {
+ if (!sw.IsSwitchEnabled) {
+ sw.SetSwitch(true);
+ }
+
+ } else if (sw.IsSwitchEnabled) {
+ sw.SetSwitch(false);
+ }
+ }
+
+ // rotate target
+ _component.UpdateRotation(_currentStep / numSteps);
+ }
+
+ void IApi.OnDestroy()
+ {
+ Logger.Info($"Destroying {_component.name}");
+ }
+ }
+}
+
diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Mech/StepRotatorMechApi.cs.meta b/VisualPinball.Unity/VisualPinball.Unity/VPT/Mech/StepRotatorMechApi.cs.meta
new file mode 100644
index 000000000..0a56babc8
--- /dev/null
+++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Mech/StepRotatorMechApi.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: f40159dfaad83b941ae9e60688743475
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Mech/StepRotatorMechComponent.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Mech/StepRotatorMechComponent.cs
new file mode 100644
index 000000000..9ec85b3da
--- /dev/null
+++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Mech/StepRotatorMechComponent.cs
@@ -0,0 +1,119 @@
+// Visual Pinball Engine
+// Copyright (C) 2021 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;
+using System.Collections.Generic;
+using System.Linq;
+using NLog;
+using Unity.Mathematics;
+using UnityEngine;
+using VisualPinball.Engine.Game.Engines;
+using Logger = NLog.Logger;
+
+namespace VisualPinball.Unity
+{
+ [AddComponentMenu("Visual Pinball/Mechs/Step Rotator")]
+ public class StepRotatorMechComponent : MonoBehaviour, ISwitchDeviceComponent, ICoilDeviceComponent
+ {
+ #region Data
+
+ [Tooltip("The target to rotate.")]
+ public RotatorComponent Target;
+
+ [Range(0f, 360f)]
+ [Tooltip("Angle in degrees the object rotates until it changes rotation and goes back. It's the angle that corresponds to the number of steps below.")]
+ public float TotalRotationDegrees = 65;
+
+ [Min(0)]
+ public int NumSteps;
+
+ [Tooltip("On each mark, the switch changes are transmitted to the gamelogic engine.")]
+ public StepRotatorMark[] Marks;
+
+ #endregion
+
+ #region Constants
+
+ public const string MotorCoilItem = "motor_coil";
+
+ private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
+
+ #endregion
+
+ #region Wiring
+
+ public IEnumerable AvailableCoils => new[] {
+ new GamelogicEngineCoil(MotorCoilItem) {
+ Description = "Motor"
+ }
+ };
+
+ public IEnumerable AvailableSwitches => Marks.Select(m => m.Switch);
+
+ public SwitchDefault SwitchDefault => SwitchDefault.NormallyOpen;
+
+ IEnumerable IDeviceComponent.AvailableDeviceItems => AvailableCoils;
+ IEnumerable IDeviceComponent.AvailableDeviceItems => AvailableSwitches;
+ IEnumerable IWireableComponent.AvailableWireDestinations => AvailableCoils;
+ IEnumerable IDeviceComponent.AvailableDeviceItems => AvailableCoils;
+
+ #endregion
+
+ #region Runtime
+
+ private void Awake()
+ {
+ var player = GetComponentInParent();
+ if (player == null) {
+ Logger.Error($"Cannot find player for step rotator {name}.");
+ return;
+ }
+
+ player.RegisterStepRotator(this);
+ }
+
+ public void UpdateRotation(float value)
+ {
+ if (Target != null) {
+ Target.UpdateRotation(value * TotalRotationDegrees);
+ }
+ }
+
+ #endregion
+ }
+
+ [Serializable]
+ public class StepRotatorMark
+ {
+ public string Description;
+ public string SwitchId;
+ public int StepBeginning;
+ public int StepEnd;
+
+ public GamelogicEngineSwitch Switch => new(SwitchId) { Description = Description };
+
+ public StepRotatorMark(string description, string switchId, int stepBeginning, int stepEnd)
+ {
+ Description = description;
+ SwitchId = switchId;
+ StepBeginning = stepBeginning;
+ StepEnd = stepEnd;
+ }
+ }
+
+}
diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Mech/StepRotatorMechComponent.cs.meta b/VisualPinball.Unity/VisualPinball.Unity/VPT/Mech/StepRotatorMechComponent.cs.meta
new file mode 100644
index 000000000..cd0d80033
--- /dev/null
+++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Mech/StepRotatorMechComponent.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 924da895b2d85c6478716801dcc07b7c
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {fileID: 2800000, guid: fb3697293112e424081c5debc2d519fb, type: 3}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Primitive/PrimitiveComponent.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Primitive/PrimitiveComponent.cs
index e161dee67..54cc13503 100644
--- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Primitive/PrimitiveComponent.cs
+++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Primitive/PrimitiveComponent.cs
@@ -25,6 +25,7 @@
using System.Collections.Generic;
using System.Linq;
using Unity.Entities;
+using Unity.Mathematics;
using UnityEngine;
using VisualPinball.Engine.Math;
using VisualPinball.Engine.VPT;
@@ -36,7 +37,8 @@
namespace VisualPinball.Unity
{
[AddComponentMenu("Visual Pinball/Game Item/Primitive")]
- public class PrimitiveComponent : MainRenderableComponent, IMeshGenerator, IConvertGameObjectToEntity
+ public class PrimitiveComponent : MainRenderableComponent, IMeshGenerator,
+ IRotatableComponent, IConvertGameObjectToEntity
{
#region Data
@@ -81,6 +83,22 @@ public override void UpdateTransforms()
transform.SetFromMatrix(GetTransformationMatrix().ToUnityMatrix());
}
+ public float _originalRotateZ;
+ public float RotateZ {
+ set {
+ ObjectRotation.z = _originalRotateZ + value;
+ UpdateTransforms();
+ }
+ }
+ public float2 RotatedPosition {
+ get => new(Position.x, Position.y);
+ set {
+ Position.x = value.x;
+ Position.y = value.y;
+ UpdateTransforms();
+ }
+ }
+
#endregion
#region Conversion
@@ -214,6 +232,15 @@ public override PrimitiveData CopyDataTo(PrimitiveData data, string[] materialNa
#endregion
+ #region Runtime
+
+ private void Awake()
+ {
+ _originalRotateZ = ObjectRotation.z;
+ }
+
+ #endregion
+
#region IMeshGenerator
public Mesh GetMesh() => GetDefaultMesh();
diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Ramp/RampApi.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Ramp/RampApi.cs
index 396b852e5..7733890bb 100644
--- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Ramp/RampApi.cs
+++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Ramp/RampApi.cs
@@ -21,13 +21,18 @@
namespace VisualPinball.Unity
{
- public class RampApi : CollidableApi, IApi
+ public class RampApi : CollidableApi, IApi, IApiHittable
{
///
/// Event emitted when the table is started.
///
public event EventHandler Init;
+ ///
+ /// Event emitted when the ball hits the ramp.
+ ///
+ public event EventHandler Hit;
+
internal RampApi(GameObject go, Entity entity, Entity parentEntity, Player player) : base(go, entity, parentEntity, player)
{
}
@@ -40,6 +45,11 @@ void IApi.OnInit(BallManager ballManager)
Init?.Invoke(this, EventArgs.Empty);
}
+ public void OnHit(Entity ballEntity, bool isUnHit = false)
+ {
+ Hit?.Invoke(this, new HitEventArgs(ballEntity));
+ }
+
void IApi.OnDestroy()
{
}
diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Ramp/RampComponent.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Ramp/RampComponent.cs
index 7c9b24b76..a0972e988 100644
--- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Ramp/RampComponent.cs
+++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Ramp/RampComponent.cs
@@ -399,7 +399,7 @@ protected static void WalkChildren(IEnumerable node, Action action)
protected void UpdateSurfaceReferences(Transform obj)
{
var surfaceComponent = obj.gameObject.GetComponent();
- if (surfaceComponent != null && (RampComponent)surfaceComponent.Surface == this) {
+ if (surfaceComponent != null && surfaceComponent.Surface == this) {
surfaceComponent.OnSurfaceUpdated();
}
}
diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/SubComponent.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/SubComponent.cs
index b98850367..f7c16e78a 100644
--- a/VisualPinball.Unity/VisualPinball.Unity/VPT/SubComponent.cs
+++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/SubComponent.cs
@@ -39,6 +39,9 @@ public abstract class SubComponent : ItemComponent
public bool IsCorrectlyParented {
get {
+ if (!ValidParents.Any()) {
+ return true;
+ }
var parentComponent = ParentComponent;
return parentComponent == null || ValidParents.Any(validParent => parentComponent.GetType() == validParent);
}
diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Table/TableApi.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Table/TableApi.cs
index 8a075d197..b7d30327f 100644
--- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Table/TableApi.cs
+++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Table/TableApi.cs
@@ -27,8 +27,6 @@ public class TableApi : IApi
#region Dictionaries
private readonly Dictionary _bumpersByName = new Dictionary();
- private readonly Dictionary _cannonsByName = new Dictionary();
- private readonly Dictionary _mechsByName = new Dictionary();
private readonly Dictionary _dropTargetsByName = new Dictionary();
private readonly Dictionary _dropTargetBanksByName = new Dictionary();
private readonly Dictionary _flippersByName = new Dictionary();
@@ -42,6 +40,7 @@ public class TableApi : IApi
private readonly Dictionary _rampsByName = new Dictionary();
private readonly Dictionary _rubbersByName = new Dictionary();
private readonly Dictionary _spinnersByName = new Dictionary();
+ private readonly Dictionary _stepRotatorsByName = new Dictionary();
private readonly Dictionary _surfacesByName = new Dictionary();
private readonly Dictionary _teleportersByName = new Dictionary();
private readonly Dictionary _triggersByName = new Dictionary();
@@ -49,8 +48,6 @@ public class TableApi : IApi
private readonly Dictionary _bumpersByComponent = new Dictionary();
- private readonly Dictionary _cannonsByComponent = new Dictionary();
- private readonly Dictionary _mechsByComponent = new Dictionary();
private readonly Dictionary _dropTargetsByComponent = new Dictionary();
private readonly Dictionary _dropTargetBanksByComponent = new Dictionary();
private readonly Dictionary _flippersByComponent = new Dictionary();
@@ -64,6 +61,7 @@ public class TableApi : IApi
private readonly Dictionary _rampsByComponent = new Dictionary();
private readonly Dictionary _rubbersByComponent = new Dictionary();
private readonly Dictionary _spinnersByComponent = new Dictionary();
+ private readonly Dictionary _stepRotatorsByComponent = new Dictionary();
private readonly Dictionary _surfacesByComponent = new Dictionary();
private readonly Dictionary _teleportersByComponent = new Dictionary();
private readonly Dictionary _triggersByComponent = new Dictionary();
@@ -199,12 +197,12 @@ public TableApi(Player player)
public TroughApi Trough(MonoBehaviour component) => Get(component);
///
- /// Returns a cannon by name.
+ /// Returns a step rotator by name.
///
- /// Name of the cannon
- /// Cannon or `null` if no cannon with that name exists.
- public CannonApi Cannon(string name) => Get(name);
- public CannonApi Cannon(MonoBehaviour component) => Get(component);
+ /// Name of the step rotator
+ /// Step rotator or `null` if no step rotator with that name exists.
+ public StepRotatorMechApi StepRotator(string name) => Get(name);
+ public StepRotatorMechApi StepRotator(MonoBehaviour component) => Get(component);
///
/// Returns a drop target by name.
@@ -246,8 +244,6 @@ internal void Register(MonoBehaviour component, T api) where T : IApi
private Dictionary GetNameDictionary(Type t) where T : IApi
{
if (t == typeof(BumperApi)) return _bumpersByName as Dictionary;
- if (t == typeof(CannonApi)) return _cannonsByName as Dictionary;
- if (t == typeof(CannonApi)) return _mechsByName as Dictionary;
if (t == typeof(DropTargetApi)) return _dropTargetsByName as Dictionary;
if (t == typeof(DropTargetBankApi)) return _dropTargetBanksByName as Dictionary;
if (t == typeof(FlipperApi)) return _flippersByName as Dictionary;
@@ -262,6 +258,7 @@ private Dictionary GetNameDictionary(Type t) where T : IApi
if (t == typeof(RampApi)) return _rampsByName as Dictionary;
if (t == typeof(RubberApi)) return _rubbersByName as Dictionary;
if (t == typeof(SpinnerApi)) return _spinnersByName as Dictionary;
+ if (t == typeof(StepRotatorMechApi)) return _stepRotatorsByName as Dictionary;
if (t == typeof(SurfaceApi)) return _surfacesByName as Dictionary;
if (t == typeof(TeleporterApi)) return _teleportersByName as Dictionary;
if (t == typeof(TriggerApi)) return _triggersByName as Dictionary;
@@ -272,8 +269,6 @@ private Dictionary GetNameDictionary(Type t) where T : IApi
private Dictionary GetComponentDictionary(Type t) where T : IApi
{
if (t == typeof(BumperApi)) return _bumpersByComponent as Dictionary;
- if (t == typeof(CannonApi)) return _cannonsByComponent as Dictionary;
- if (t == typeof(CannonApi)) return _mechsByComponent as Dictionary;
if (t == typeof(DropTargetApi)) return _dropTargetsByComponent as Dictionary;
if (t == typeof(DropTargetBankApi)) return _dropTargetBanksByComponent as Dictionary;
if (t == typeof(FlipperApi)) return _flippersByComponent as Dictionary;
@@ -288,6 +283,7 @@ private Dictionary GetComponentDictionary(Type t) where T :
if (t == typeof(RampApi)) return _rampsByComponent as Dictionary;
if (t == typeof(RubberApi)) return _rubbersByComponent as Dictionary;
if (t == typeof(SpinnerApi)) return _spinnersByComponent as Dictionary;
+ if (t == typeof(StepRotatorMechApi)) return _stepRotatorsByComponent as Dictionary;
if (t == typeof(SurfaceApi)) return _surfacesByComponent as Dictionary;
if (t == typeof(TeleporterApi)) return _teleportersByComponent as Dictionary;
if (t == typeof(TriggerApi)) return _triggersByComponent as Dictionary;
diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Teleporter/TeleporterApi.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Teleporter/TeleporterApi.cs
index c56dd538a..65b5f86a1 100644
--- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Teleporter/TeleporterApi.cs
+++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Teleporter/TeleporterApi.cs
@@ -66,11 +66,16 @@ private void OnTeleport()
var ballInSrc = _fromKicker.HasBall();
var ballInDst = _toKicker.HasBall();
- if (!ballInSrc || ballInDst) {
+ if (!ballInSrc && !ballInDst || ballInSrc && ballInDst) {
// duh, do nothing.
return;
}
+ if (ballInDst) {
+ Eject();
+ return;
+ }
+
var ballData = _fromKicker.GetBallData();
_fromKicker.DestroyBall();
_toKicker.CreateSizedBallWithMass(ballData.Radius, ballData.Mass);
@@ -80,15 +85,20 @@ private void OnTeleport()
return;
}
+ Eject();
+ }
+
+ private void Eject()
+ {
if (_component.EjectDelay > 0) {
- _simulationSystemGroup.ScheduleAction((int)math.round(_component.EjectDelay * 1000f), Eject);
+ _simulationSystemGroup.ScheduleAction((int)math.round(_component.EjectDelay * 1000f), TriggerEjectCoil);
} else {
- Eject();
+ TriggerEjectCoil();
}
}
- private void Eject()
+ private void TriggerEjectCoil()
{
if (!string.IsNullOrEmpty(_component.ToKickerItem)) {
var kickerCoil = (_toKicker as IApiCoilDevice).Coil(_component.ToKickerItem);
diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Teleporter/TeleporterComponent.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Teleporter/TeleporterComponent.cs
index 706681aa5..1fc2648c8 100644
--- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Teleporter/TeleporterComponent.cs
+++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Teleporter/TeleporterComponent.cs
@@ -74,12 +74,16 @@ public class TeleporterComponent : MonoBehaviour, ICoilDeviceComponent
private void Awake()
{
var player = GetComponentInParent();
- if (player == null)
- {
- Logger.Error($"Cannot find player for cannon {name}.");
+ if (player == null) {
+ Logger.Error($"Cannot find player for teleporter {name}.");
return;
}
+ // disable destination kicker collider
+ if (ToKicker != null) {
+ ToKicker.GetComponent().enabled = false;
+ }
+
player.RegisterTeleporter(this);
}