diff --git a/CHANGELOG.md b/CHANGELOG.md index da5906e21..f2ff87577 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,8 @@ Built with Unity 2020.3. ### Added -- 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)). +- 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)). - 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.Unity/Assets/Editor/Icons/large_blue/ball_roller.png b/VisualPinball.Unity/Assets/Editor/Icons/large_blue/ball_roller.png new file mode 100644 index 000000000..da9b4ab3a Binary files /dev/null and b/VisualPinball.Unity/Assets/Editor/Icons/large_blue/ball_roller.png differ diff --git a/VisualPinball.Unity/Assets/Editor/Icons/large_blue/ball_roller.png.meta b/VisualPinball.Unity/Assets/Editor/Icons/large_blue/ball_roller.png.meta new file mode 100644 index 000000000..8e44f72f4 --- /dev/null +++ b/VisualPinball.Unity/Assets/Editor/Icons/large_blue/ball_roller.png.meta @@ -0,0 +1,108 @@ +fileFormatVersion: 2 +guid: 5a048f1cf2c31c142866a8c295b2b50d +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 + 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: 512 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + 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: [] + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/Assets/Editor/Icons/large_blue/teleporter.png b/VisualPinball.Unity/Assets/Editor/Icons/large_blue/teleporter.png new file mode 100644 index 000000000..be843ffa6 Binary files /dev/null and b/VisualPinball.Unity/Assets/Editor/Icons/large_blue/teleporter.png differ diff --git a/VisualPinball.Unity/Assets/Editor/Icons/large_blue/teleporter.png.meta b/VisualPinball.Unity/Assets/Editor/Icons/large_blue/teleporter.png.meta new file mode 100644 index 000000000..33375f743 --- /dev/null +++ b/VisualPinball.Unity/Assets/Editor/Icons/large_blue/teleporter.png.meta @@ -0,0 +1,108 @@ +fileFormatVersion: 2 +guid: 7e5305f747acd2945b61ba6f5f3680fa +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + 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 + 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: 512 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + 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: [] + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/Assets/Editor/Icons/large_gray/ball_roller.png b/VisualPinball.Unity/Assets/Editor/Icons/large_gray/ball_roller.png new file mode 100644 index 000000000..eb27dee90 Binary files /dev/null and b/VisualPinball.Unity/Assets/Editor/Icons/large_gray/ball_roller.png differ diff --git a/VisualPinball.Unity/Assets/Editor/Icons/large_gray/ball_roller.png.meta b/VisualPinball.Unity/Assets/Editor/Icons/large_gray/ball_roller.png.meta new file mode 100644 index 000000000..0e2eb408e --- /dev/null +++ b/VisualPinball.Unity/Assets/Editor/Icons/large_gray/ball_roller.png.meta @@ -0,0 +1,108 @@ +fileFormatVersion: 2 +guid: d875bb1b18c51e34ea79a43799ce38ff +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 + 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: 512 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + 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: [] + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/Assets/Editor/Icons/large_gray/teleporter.png b/VisualPinball.Unity/Assets/Editor/Icons/large_gray/teleporter.png new file mode 100644 index 000000000..2204a85cb Binary files /dev/null and b/VisualPinball.Unity/Assets/Editor/Icons/large_gray/teleporter.png differ diff --git a/VisualPinball.Unity/Assets/Editor/Icons/large_gray/teleporter.png.meta b/VisualPinball.Unity/Assets/Editor/Icons/large_gray/teleporter.png.meta new file mode 100644 index 000000000..dbc4bde6d --- /dev/null +++ b/VisualPinball.Unity/Assets/Editor/Icons/large_gray/teleporter.png.meta @@ -0,0 +1,108 @@ +fileFormatVersion: 2 +guid: b69f01a1d3ebdbb45a757af9834de674 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + 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 + 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: 512 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + 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: [] + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/Assets/Editor/Icons/large_green/ball_roller.png b/VisualPinball.Unity/Assets/Editor/Icons/large_green/ball_roller.png new file mode 100644 index 000000000..502359304 Binary files /dev/null and b/VisualPinball.Unity/Assets/Editor/Icons/large_green/ball_roller.png differ diff --git a/VisualPinball.Unity/Assets/Editor/Icons/large_green/ball_roller.png.meta b/VisualPinball.Unity/Assets/Editor/Icons/large_green/ball_roller.png.meta new file mode 100644 index 000000000..dff6a6f39 --- /dev/null +++ b/VisualPinball.Unity/Assets/Editor/Icons/large_green/ball_roller.png.meta @@ -0,0 +1,108 @@ +fileFormatVersion: 2 +guid: e22f43052894ced418fa3ca9b311742a +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 + 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: 512 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + 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: [] + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/Assets/Editor/Icons/large_green/teleporter.png b/VisualPinball.Unity/Assets/Editor/Icons/large_green/teleporter.png new file mode 100644 index 000000000..ab99e4a21 Binary files /dev/null and b/VisualPinball.Unity/Assets/Editor/Icons/large_green/teleporter.png differ diff --git a/VisualPinball.Unity/Assets/Editor/Icons/large_green/teleporter.png.meta b/VisualPinball.Unity/Assets/Editor/Icons/large_green/teleporter.png.meta new file mode 100644 index 000000000..a6a1f2a43 --- /dev/null +++ b/VisualPinball.Unity/Assets/Editor/Icons/large_green/teleporter.png.meta @@ -0,0 +1,108 @@ +fileFormatVersion: 2 +guid: 6e0922aff57702e438b1a1fbc3f7e825 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + 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 + 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: 512 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + 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: [] + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/Assets/Editor/Icons/large_orange/ball_roller.png b/VisualPinball.Unity/Assets/Editor/Icons/large_orange/ball_roller.png new file mode 100644 index 000000000..1bd7082d8 Binary files /dev/null and b/VisualPinball.Unity/Assets/Editor/Icons/large_orange/ball_roller.png differ diff --git a/VisualPinball.Unity/Assets/Editor/Icons/large_orange/ball_roller.png.meta b/VisualPinball.Unity/Assets/Editor/Icons/large_orange/ball_roller.png.meta new file mode 100644 index 000000000..8117248a7 --- /dev/null +++ b/VisualPinball.Unity/Assets/Editor/Icons/large_orange/ball_roller.png.meta @@ -0,0 +1,108 @@ +fileFormatVersion: 2 +guid: da56aa07ff467c347987f288bdbd8103 +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 + 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: 512 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + 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: [] + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/Assets/Editor/Icons/large_orange/teleporter.png b/VisualPinball.Unity/Assets/Editor/Icons/large_orange/teleporter.png new file mode 100644 index 000000000..e4470e3e2 Binary files /dev/null and b/VisualPinball.Unity/Assets/Editor/Icons/large_orange/teleporter.png differ diff --git a/VisualPinball.Unity/Assets/Editor/Icons/large_orange/teleporter.png.meta b/VisualPinball.Unity/Assets/Editor/Icons/large_orange/teleporter.png.meta new file mode 100644 index 000000000..56b94c8fa --- /dev/null +++ b/VisualPinball.Unity/Assets/Editor/Icons/large_orange/teleporter.png.meta @@ -0,0 +1,108 @@ +fileFormatVersion: 2 +guid: fa75c51a5e472874bb97b926d505b942 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + 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 + 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: 512 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + 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: [] + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/Assets/Editor/Icons/small_blue/ball_roller.png b/VisualPinball.Unity/Assets/Editor/Icons/small_blue/ball_roller.png new file mode 100644 index 000000000..2694dc9e0 Binary files /dev/null and b/VisualPinball.Unity/Assets/Editor/Icons/small_blue/ball_roller.png differ diff --git a/VisualPinball.Unity/Assets/Editor/Icons/small_blue/ball_roller.png.meta b/VisualPinball.Unity/Assets/Editor/Icons/small_blue/ball_roller.png.meta new file mode 100644 index 000000000..660fd55e7 --- /dev/null +++ b/VisualPinball.Unity/Assets/Editor/Icons/small_blue/ball_roller.png.meta @@ -0,0 +1,108 @@ +fileFormatVersion: 2 +guid: 0b5c61c9044493b40b141c9860397c73 +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 + 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: 64 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + 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: [] + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/Assets/Editor/Icons/small_blue/teleporter.png b/VisualPinball.Unity/Assets/Editor/Icons/small_blue/teleporter.png new file mode 100644 index 000000000..ecd8b2c0a Binary files /dev/null and b/VisualPinball.Unity/Assets/Editor/Icons/small_blue/teleporter.png differ diff --git a/VisualPinball.Unity/Assets/Editor/Icons/small_blue/teleporter.png.meta b/VisualPinball.Unity/Assets/Editor/Icons/small_blue/teleporter.png.meta new file mode 100644 index 000000000..20a41f633 --- /dev/null +++ b/VisualPinball.Unity/Assets/Editor/Icons/small_blue/teleporter.png.meta @@ -0,0 +1,108 @@ +fileFormatVersion: 2 +guid: 8687ac85dd7121d4681aa20faaffcc7b +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 + 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: 64 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + 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: [] + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/Assets/Editor/Icons/small_gray/ball_roller.png b/VisualPinball.Unity/Assets/Editor/Icons/small_gray/ball_roller.png new file mode 100644 index 000000000..cc423caac Binary files /dev/null and b/VisualPinball.Unity/Assets/Editor/Icons/small_gray/ball_roller.png differ diff --git a/VisualPinball.Unity/Assets/Editor/Icons/small_gray/ball_roller.png.meta b/VisualPinball.Unity/Assets/Editor/Icons/small_gray/ball_roller.png.meta new file mode 100644 index 000000000..ef9537a87 --- /dev/null +++ b/VisualPinball.Unity/Assets/Editor/Icons/small_gray/ball_roller.png.meta @@ -0,0 +1,108 @@ +fileFormatVersion: 2 +guid: 3dcb1474894669c41ada07e2c9b6395b +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 + 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: 64 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + 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: [] + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/Assets/Editor/Icons/small_gray/teleporter.png b/VisualPinball.Unity/Assets/Editor/Icons/small_gray/teleporter.png new file mode 100644 index 000000000..9b92087d0 Binary files /dev/null and b/VisualPinball.Unity/Assets/Editor/Icons/small_gray/teleporter.png differ diff --git a/VisualPinball.Unity/Assets/Editor/Icons/small_gray/teleporter.png.meta b/VisualPinball.Unity/Assets/Editor/Icons/small_gray/teleporter.png.meta new file mode 100644 index 000000000..494ac1b0d --- /dev/null +++ b/VisualPinball.Unity/Assets/Editor/Icons/small_gray/teleporter.png.meta @@ -0,0 +1,108 @@ +fileFormatVersion: 2 +guid: 6d406e97aa1e0fa43b3f716865637918 +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 + 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: 64 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + 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: [] + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/Assets/Editor/Icons/small_green/ball_roller.png b/VisualPinball.Unity/Assets/Editor/Icons/small_green/ball_roller.png new file mode 100644 index 000000000..3bd86bb30 Binary files /dev/null and b/VisualPinball.Unity/Assets/Editor/Icons/small_green/ball_roller.png differ diff --git a/VisualPinball.Unity/Assets/Editor/Icons/small_green/ball_roller.png.meta b/VisualPinball.Unity/Assets/Editor/Icons/small_green/ball_roller.png.meta new file mode 100644 index 000000000..014c48b35 --- /dev/null +++ b/VisualPinball.Unity/Assets/Editor/Icons/small_green/ball_roller.png.meta @@ -0,0 +1,108 @@ +fileFormatVersion: 2 +guid: 07cd7e11b2f26e847b8c55e0598d135d +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 + 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: 64 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + 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: [] + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/Assets/Editor/Icons/small_green/teleporter.png b/VisualPinball.Unity/Assets/Editor/Icons/small_green/teleporter.png new file mode 100644 index 000000000..54cacbc17 Binary files /dev/null and b/VisualPinball.Unity/Assets/Editor/Icons/small_green/teleporter.png differ diff --git a/VisualPinball.Unity/Assets/Editor/Icons/small_green/teleporter.png.meta b/VisualPinball.Unity/Assets/Editor/Icons/small_green/teleporter.png.meta new file mode 100644 index 000000000..6315b4983 --- /dev/null +++ b/VisualPinball.Unity/Assets/Editor/Icons/small_green/teleporter.png.meta @@ -0,0 +1,108 @@ +fileFormatVersion: 2 +guid: ae260860fcbb8f644927bab24f650e70 +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 + 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: 64 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + 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: [] + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/Assets/Editor/Icons/small_orange/ball_roller.png b/VisualPinball.Unity/Assets/Editor/Icons/small_orange/ball_roller.png new file mode 100644 index 000000000..4d8fd8759 Binary files /dev/null and b/VisualPinball.Unity/Assets/Editor/Icons/small_orange/ball_roller.png differ diff --git a/VisualPinball.Unity/Assets/Editor/Icons/small_orange/ball_roller.png.meta b/VisualPinball.Unity/Assets/Editor/Icons/small_orange/ball_roller.png.meta new file mode 100644 index 000000000..20716c40d --- /dev/null +++ b/VisualPinball.Unity/Assets/Editor/Icons/small_orange/ball_roller.png.meta @@ -0,0 +1,108 @@ +fileFormatVersion: 2 +guid: 41211858d62e7904ab09fc592d292bba +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 + 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: 64 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + 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: [] + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/Assets/Editor/Icons/small_orange/teleporter.png b/VisualPinball.Unity/Assets/Editor/Icons/small_orange/teleporter.png new file mode 100644 index 000000000..161aabda9 Binary files /dev/null and b/VisualPinball.Unity/Assets/Editor/Icons/small_orange/teleporter.png differ diff --git a/VisualPinball.Unity/Assets/Editor/Icons/small_orange/teleporter.png.meta b/VisualPinball.Unity/Assets/Editor/Icons/small_orange/teleporter.png.meta new file mode 100644 index 000000000..4072ed2cd --- /dev/null +++ b/VisualPinball.Unity/Assets/Editor/Icons/small_orange/teleporter.png.meta @@ -0,0 +1,108 @@ +fileFormatVersion: 2 +guid: 57668c3df120da245975f2022cbf0551 +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 + 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: 64 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + 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: [] + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/Documentation~/creators-guide/manual/mechanisms/slingshots.md b/VisualPinball.Unity/Documentation~/creators-guide/manual/mechanisms/slingshots.md index 415025a41..9e12add05 100644 --- a/VisualPinball.Unity/Documentation~/creators-guide/manual/mechanisms/slingshots.md +++ b/VisualPinball.Unity/Documentation~/creators-guide/manual/mechanisms/slingshots.md @@ -1,3 +1,9 @@ +--- +uid: slingshots +title: Slingshots +description: How to animate VPE's slingshots +--- + # Slingshots Slingshots are most commonly located just above the flippers. They usually consist of two "blade" switches on the inner side of a triangular rubber. Between the switches there is a coil driven arm that propels the ball away from the slingshot when either switch closes. diff --git a/VisualPinball.Unity/Documentation~/creators-guide/manual/mechanisms/teleporter-inspector.png b/VisualPinball.Unity/Documentation~/creators-guide/manual/mechanisms/teleporter-inspector.png new file mode 100644 index 000000000..c0f25ce4f Binary files /dev/null and b/VisualPinball.Unity/Documentation~/creators-guide/manual/mechanisms/teleporter-inspector.png differ diff --git a/VisualPinball.Unity/Documentation~/creators-guide/manual/mechanisms/teleporters.md b/VisualPinball.Unity/Documentation~/creators-guide/manual/mechanisms/teleporters.md new file mode 100644 index 000000000..c8263319e --- /dev/null +++ b/VisualPinball.Unity/Documentation~/creators-guide/manual/mechanisms/teleporters.md @@ -0,0 +1,44 @@ +--- +uid: teleporters +title: Teleporters +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. + +> [!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. + + +## Setup + + +Teleporter Inspector + +In order to create a new teleporter, select the GameObject you want to add it to, click on *Add Component* and select *Visual Pinball -> Game Item -> Teleporter*. You can choose any GameObject, although we recommend putting it on same GameObject as the source kicker. + +> [!NOTE] +> The teleporter's features are very basic. If there is need, we will add more features like teleportation to multiple types of game elements or the possibility to teleport in both directions. + +### Eject After Teleport + +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. + + +### Wait Before Eject + +You should use teleporters only for trajectories that are hidden and that emulate a physical ball going from A to B. In that case, the time it would take for the ball to travel from A to B can be simulated by waiting for the destination kicker to pop out the ball. + +This is the time in seconds that is waited before the ball is ejected from the destination kicker, but only if *Eject After Teleport* is enabled. + +### From Kicker + +A reference to the source kicker. Note that if you use this kicker for teleportation only, it's recommended to remove any coils from the kicker, since it will make it easier to select the right element when linking to it in the Coil Manager. + +### To Kicker + +The destination kicker. Here you also select a coil in case the ball is ejected after teleportation. diff --git a/VisualPinball.Unity/Documentation~/creators-guide/toc.yml b/VisualPinball.Unity/Documentation~/creators-guide/toc.yml index 63dd79668..be45f7606 100644 --- a/VisualPinball.Unity/Documentation~/creators-guide/toc.yml +++ b/VisualPinball.Unity/Documentation~/creators-guide/toc.yml @@ -49,5 +49,7 @@ href: manual/mechanisms/slingshots.md - name: Light Groups href: manual/mechanisms/light-groups.md + - name: Teleporters + href: manual/mechanisms/teleporters.md - name: Drop Target Banks href: manual/mechanisms/drop-target-banks.md diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/Common/ObjectReferencePicker.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/Common/ObjectReferencePicker.cs index 843011716..3e986a3dc 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Editor/Common/ObjectReferencePicker.cs +++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/Common/ObjectReferencePicker.cs @@ -15,6 +15,7 @@ // along with this program. If not, see . using System; +using System.Linq; using UnityEditor; using UnityEditor.IMGUI.Controls; using UnityEngine; @@ -38,7 +39,7 @@ public ObjectReferencePicker(string pickerTitle, TableComponent tableComp, bool _showIcon = showIcon; } - public void Render(Rect pos, T currentObj, Action onUpdated) + public void Render(Rect pos, T currentObj, Action onUpdated, Func filter = null) { // render content var content = currentObj == null @@ -70,7 +71,8 @@ public void Render(Rect pos, T currentObj, Action onUpdated) _itemPickDropdownState, _tableComp, _pickerTitle, - onUpdated + onUpdated, + filter ); dropdown.Show(pos); } @@ -90,10 +92,13 @@ public class ItemSearchableDropdown : AdvancedDropdown where T : class, IIden private readonly TableComponent _tableComponent; private readonly Action _onElementSelected; + private readonly Func _filter; - public ItemSearchableDropdown(AdvancedDropdownState state, TableComponent tableComponent, string title, Action onElementSelected) : base(state) + public ItemSearchableDropdown(AdvancedDropdownState state, TableComponent tableComponent, + string title, Action onElementSelected, Func filter) : base(state) { _onElementSelected = onElementSelected; + _filter = filter; _tableComponent = tableComponent; minimumSize = new Vector2(200, 300); _title = title; @@ -102,7 +107,10 @@ public ItemSearchableDropdown(AdvancedDropdownState state, TableComponent tableC protected override AdvancedDropdownItem BuildRoot() { var node = new AdvancedDropdownItem(_title); - var elements = _tableComponent.GetComponentsInChildren(); + var elements = _filter == null + ? _tableComponent.GetComponentsInChildren() + : _tableComponent.GetComponentsInChildren().Where(_filter); + node.AddChild(new ElementDropdownItem(null)); foreach (var element in elements) { node.AddChild(new ElementDropdownItem(element)); diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/Common/TypeRestrictionPropertyDrawer.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/Common/TypeRestrictionPropertyDrawer.cs index 1fb88abc3..77eaeb57b 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Editor/Common/TypeRestrictionPropertyDrawer.cs +++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/Common/TypeRestrictionPropertyDrawer.cs @@ -56,14 +56,16 @@ public override void OnGUI(Rect pos, SerializedProperty property, GUIContent lab var ta = go.GetComponentInParent(); var field = property.objectReferenceValue; + var indentedOffset = EditorGUI.indentLevel * 15f; + pos = EditorGUI.PrefixLabel(pos, label); if (!string.IsNullOrEmpty(attrib.DeviceItem) && attrib.DeviceType != null) { - pos.width = pos.width / 2f + 10f; + const float padding = 4f; + pos.width = (pos.width - padding + indentedOffset) / 2f; DevicePicker(pos, property, attrib, comp, field, ta); - pos.width -= 10f; - pos.x += pos.width; + pos.x += pos.width + padding - indentedOffset; DeviceItemDropdown(pos, property, attrib, field); } else { @@ -155,29 +157,35 @@ private void DeviceItemDropdown(Rect pos, SerializedProperty property, TypeRestr if (attrib.DeviceType == typeof(ICoilDeviceComponent) && field is ICoilDeviceComponent coilDeviceComponent) { count = coilDeviceComponent.AvailableCoils.Count(); - firstItemDescription = coilDeviceComponent.AvailableCoils.First().Description; + firstItemDescription = count > 0 ? coilDeviceComponent.AvailableCoils.First().Description : string.Empty; labels = coilDeviceComponent.AvailableCoils.Select(s => s.Description).ToArray(); ids = coilDeviceComponent.AvailableCoils.Select(s => s.Id).ToArray(); currentIndex = coilDeviceComponent.AvailableCoils.TakeWhile(s => s.Id != deviceItemPropField.stringValue).Count(); } if (attrib.DeviceType == typeof(ISwitchDeviceComponent) && field is ISwitchDeviceComponent switchDeviceComponent) { count = switchDeviceComponent.AvailableSwitches.Count(); - firstItemDescription = switchDeviceComponent.AvailableSwitches.First().Description; + firstItemDescription = count > 0 ? switchDeviceComponent.AvailableSwitches.First().Description : string.Empty; labels = switchDeviceComponent.AvailableSwitches.Select(s => s.Description).ToArray(); ids = switchDeviceComponent.AvailableSwitches.Select(s => s.Id).ToArray(); currentIndex = switchDeviceComponent.AvailableSwitches.TakeWhile(s => s.Id != deviceItemPropField.stringValue).Count(); } if (attrib.DeviceType == typeof(ILampDeviceComponent) && field is ILampDeviceComponent lampDeviceComponent) { count = lampDeviceComponent.AvailableLamps.Count(); - firstItemDescription = lampDeviceComponent.AvailableLamps.First().Description; + firstItemDescription = count > 0 ? lampDeviceComponent.AvailableLamps.First().Description : string.Empty; labels = lampDeviceComponent.AvailableLamps.Select(s => s.Description).ToArray(); ids = lampDeviceComponent.AvailableLamps.Select(s => s.Id).ToArray(); currentIndex = lampDeviceComponent.AvailableLamps.TakeWhile(s => s.Id != deviceItemPropField.stringValue).Count(); } + if (field != null && count == 0) { + deviceItemPropField.stringValue = null; + deviceItemPropField.serializedObject.ApplyModifiedProperties(); + return; + } + if (field != null && count == 1) { - deviceItemPropField.stringValue = ids[0]; - deviceItemPropField.serializedObject.ApplyModifiedProperties(); + deviceItemPropField.stringValue = ids[0]; + deviceItemPropField.serializedObject.ApplyModifiedProperties(); if (string.IsNullOrEmpty(firstItemDescription)) { return; } diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/Import/VpxSceneConverter.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/Import/VpxSceneConverter.cs index b66afcc26..82389a04a 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Editor/Import/VpxSceneConverter.cs +++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/Import/VpxSceneConverter.cs @@ -463,6 +463,7 @@ private void ConfigurePlayer(Dictionary components) { // add the player script and default game engine _tableGo.AddComponent(); + _tableGo.AddComponent(); var dga = _tableGo.AddComponent(); // populate hardware diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/Managers/Coil/CoilListViewItemRenderer.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/Managers/Coil/CoilListViewItemRenderer.cs index 798db5eac..3ad000a3d 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Editor/Managers/Coil/CoilListViewItemRenderer.cs +++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/Managers/Coil/CoilListViewItemRenderer.cs @@ -152,7 +152,7 @@ protected override void RenderDeviceElement(CoilListData coilListData, Rect cell coilListData.Device = item; UpdateDeviceItem(coilListData); updateAction(coilListData); - }); + }, item => item.AvailableCoils.Any()); } protected override Texture GetIcon(CoilListData coilListData) diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/Managers/ListViewItemRenderer.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/Managers/ListViewItemRenderer.cs index 3f394d97e..e2c464afa 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Editor/Managers/ListViewItemRenderer.cs +++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/Managers/ListViewItemRenderer.cs @@ -138,13 +138,34 @@ protected void RenderDevice(TListData listData, Rect cellRect, Action private void RenderDeviceItemElement(TListData listData, Rect cellRect, Action updateAction) { + // sets the item if only one coil UpdateDeviceItem(listData); - var onlyOneDeviceItem = listData.DeviceComponent != null && listData.DeviceComponent.AvailableDeviceItems.Count() == 1; - if (onlyOneDeviceItem && string.IsNullOrEmpty(listData.DeviceComponent.AvailableDeviceItems.First().Description)) { + var numDeviceItems = listData.DeviceComponent == null ? -1 : listData.DeviceComponent.AvailableDeviceItems.Count(); + + // no coils: show error + if (numDeviceItems == 0) { + var icon = EditorGUIUtility.IconContent("Error@2x").image; + var iconRect = cellRect; + iconRect.width = 20; + var guiColor = GUI.color; + GUI.color = Color.clear; + EditorGUI.DrawTextureTransparent(iconRect, icon, ScaleMode.ScaleToFit); + GUI.color = guiColor; + cellRect.x += 20; + + var s = new GUIStyle(EditorStyles.label) { normal = { textColor = new Color(1f, 0.431f, 0.25f) } }; + EditorGUI.LabelField(cellRect, "No coils!", s); + return; + } + + // only one coil with no description: show nothing + if (numDeviceItems == 1 && string.IsNullOrEmpty(listData.DeviceComponent!.AvailableDeviceItems.First().Description)) { return; } - EditorGUI.BeginDisabledGroup(listData.DeviceComponent == null || onlyOneDeviceItem); + + // disable if nothing to select + EditorGUI.BeginDisabledGroup(numDeviceItems <= 1); var currentIndex = 0; var labels = Array.Empty(); @@ -167,9 +188,12 @@ private void RenderDeviceItemElement(TListData listData, Rect cellRect, Action listData.DeviceComponent!.AvailableDeviceItems.First().Id, + 0 => null, + _ => listData.DeviceItem + }; } protected Rect RenderIcon(TListData listData, Rect cellRect) diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/Managers/Switch/SwitchListViewItemRenderer.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/Managers/Switch/SwitchListViewItemRenderer.cs index c07d0257f..53f7e3790 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Editor/Managers/Switch/SwitchListViewItemRenderer.cs +++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/Managers/Switch/SwitchListViewItemRenderer.cs @@ -220,7 +220,7 @@ protected override void RenderDeviceElement(SwitchListData switchListData, Rect switchListData.Device = component; UpdateDeviceItem(switchListData); updateAction(switchListData); - }); + }, switchDevice => switchDevice.AvailableSwitches.Any()); } private void RenderPulseDelay(SwitchListData switchListData, Rect cellRect, Action updateAction) diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/Utils/Icons.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/Utils/Icons.cs index 2651b0af5..505b7a28f 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Editor/Utils/Icons.cs +++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/Utils/Icons.cs @@ -36,6 +36,7 @@ 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 CoilName = "coil"; @@ -59,15 +60,16 @@ public IconVariant(string name, IconSize size, IconColor color) private const string SurfaceName = "surface"; private const string SlingshotName = "slingshot"; 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 = { - BumperName, BoltName, CoilName, DropTargetName, DropTargetBankName, FlasherName, FlipperName, HitTargetName, GateName, KeyName, KickerName, - LightGroupName, LightName, PlayfieldName, PlungerName, PlugName, PrimitiveName, RampName, RubberName, SpinnerName, SurfaceName, TableName, - TriggerName, TroughName, SlingshotName, SwitchNcName, SwitchNoName + 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 }; private readonly Dictionary _icons = new Dictionary(); @@ -85,16 +87,12 @@ public IconVariant(string name, IconSize size, IconColor color) private Icons() { const string iconPath = "Packages/org.visualpinball.engine.unity/VisualPinball.Unity/Assets/Editor/Icons"; - foreach (var name in Names) - { - foreach (var size in Enum.GetValues(typeof(IconSize)).Cast()) - { - foreach (var color in Enum.GetValues(typeof(IconColor)).Cast()) - { + foreach (var name in Names) { + foreach (var size in Enum.GetValues(typeof(IconSize)).Cast()) { + foreach (var color in Enum.GetValues(typeof(IconColor)).Cast()) { var variant = new IconVariant(name, size, color); var path = $"{iconPath}/{size.ToString().ToLower()}_{color.ToString().ToLower()}/{name}.png"; - if (File.Exists(path)) - { + if (File.Exists(path)) { _icons[variant] = AssetDatabase.LoadAssetAtPath(path); } } @@ -102,6 +100,7 @@ private Icons() } } + public static Texture2D BallRoller(IconSize size = IconSize.Large, IconColor color = IconColor.Gray) => Instance.GetItem(BallRollerName, size, color); public static Texture2D Bumper(IconSize size = IconSize.Large, IconColor color = IconColor.Gray) => Instance.GetItem(BumperName, 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); @@ -121,6 +120,7 @@ private Icons() 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 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); @@ -132,8 +132,8 @@ private Icons() public static Texture2D ByComponent(T mb, IconSize size = IconSize.Large, IconColor color = IconColor.Gray) where T : class { - switch (mb) - { + switch (mb) { + case BallRollerComponent _: return BallRoller(size, color); case BumperComponent _: return Bumper(size, color); case DropTargetComponent _: return DropTarget(size, color); case DropTargetBankComponent _: return DropTargetBank(size, color); @@ -152,6 +152,7 @@ public static Texture2D ByComponent(T mb, IconSize size = IconSize.Large, Ico case SpinnerComponent _: return Spinner(size, color); case SlingshotComponent _: return Slingshot(size, color); case SurfaceComponent _: return Surface(size, color); + case TeleporterComponent _: return Teleporter(size, color); case TriggerComponent _: return Trigger(size, color); case TroughComponent _: return Trough(size, color); default: return null; @@ -161,6 +162,7 @@ public static Texture2D ByComponent(T mb, IconSize size = IconSize.Large, Ico [MenuItem("Visual Pinball/Editor/Disable Gizmo Icons", false, 510)] public static void DisableGizmoIcons() { + DisableGizmo(); DisableGizmo(); DisableGizmo(); DisableGizmo(); @@ -215,6 +217,7 @@ public static void DisableGizmoIcons() DisableGizmo(); DisableGizmo(); DisableGizmo(); + DisableGizmo(); DisableGizmo(); DisableGizmo(); DisableGizmo(); @@ -223,35 +226,30 @@ public static void DisableGizmoIcons() public static void ApplyToComponent(Object target, Texture2D tex) where T : MonoBehaviour { - if (target == null || tex == null) - { + if (target == null || tex == null) { throw new ArgumentNullException(); } - SetIconForObject.Invoke(null, new object[] { target, tex }); + SetIconForObject.Invoke(null, new object[]{ target, tex }); DisableGizmo(); var monoScript = target as MonoScript; - if (monoScript) - { - CopyMonoScriptIconToImporters.Invoke(null, new object[] { monoScript }); + if (monoScript) { + CopyMonoScriptIconToImporters.Invoke(null, new object[]{ monoScript }); } } private Texture2D GetItem(string name, IconSize size, IconColor color) { var variant = new IconVariant(name, size, color); - if (!_icons.ContainsKey(variant)) - { + if (!_icons.ContainsKey(variant)) { variant = new IconVariant(name, IconSize.Large, color); } - if (!_icons.ContainsKey(variant)) - { + if (!_icons.ContainsKey(variant)) { variant = new IconVariant(name, IconSize.Large, IconColor.Gray); } - if (!_icons.ContainsKey(variant)) - { + if (!_icons.ContainsKey(variant)) { throw new InvalidOperationException($"Cannot find {variant.Size} {variant.Name} icon of color {variant.Color}."); } diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Kicker/KickerInspector.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Kicker/KickerInspector.cs index 85f8c37b8..d05526341 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Kicker/KickerInspector.cs +++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Kicker/KickerInspector.cs @@ -97,20 +97,24 @@ private void OnSceneGUI() Handles.color = Color.cyan; var transform = MainComponent.transform; - var position = transform.parent.TransformPoint(MainComponent.GetEditorPosition()); + var localPos = MainComponent.GetEditorPosition(); + localPos.z = MainComponent.PositionZ; + + var worldPos = transform.parent.TransformPoint(localPos); foreach (var coil in MainComponent.Coils) { var from = MainComponent.GetBallCreationPosition().ToUnityVector3(); - var l = 20f * coil.Speed; + var l = coil.Speed == 0 ? 1f : 20f * coil.Speed; var dir = new Vector3( - l * math.cos(math.radians(coil.Angle)), l * math.sin(math.radians(coil.Angle)), + -l * math.cos(math.radians(coil.Angle)), l * math.sin(math.radians(coil.Inclination)) ); var to = from + dir; var worldDir = transform.TransformDirection(math.normalize( to - from)); + var length = coil.Speed == 0 ? 0.1f : coil.Speed / 10f; - Handles.ArrowHandleCap(-1, position, Quaternion.LookRotation(worldDir), coil.Speed / 10f, EventType.Repaint); + Handles.ArrowHandleCap(-1, worldPos, Quaternion.LookRotation(worldDir), length, EventType.Repaint); } } } diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Teleporter.meta b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Teleporter.meta new file mode 100644 index 000000000..910c1e38b --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Teleporter.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d1ff4e3d75b370148b959b0272fb348f +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Teleporter/TeleporterInspector.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Teleporter/TeleporterInspector.cs new file mode 100644 index 000000000..b9226c109 --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Teleporter/TeleporterInspector.cs @@ -0,0 +1,59 @@ +// 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 +{ + [CustomEditor(typeof(TeleporterComponent)), CanEditMultipleObjects] + public class TeleporterInspector : ItemInspector + { + private SerializedProperty _kickAfterTeleportationProperty; + private SerializedProperty _kickDelayProperty; + private SerializedProperty _fromKickerProperty; + private SerializedProperty _toKickerProperty; + + protected override MonoBehaviour UndoTarget => target as MonoBehaviour; + + protected override void OnEnable() + { + base.OnEnable(); + + _kickAfterTeleportationProperty = serializedObject.FindProperty(nameof(TeleporterComponent.EjectAfterTeleportation)); + _kickDelayProperty = serializedObject.FindProperty(nameof(TeleporterComponent.EjectDelay)); + _fromKickerProperty = serializedObject.FindProperty(nameof(TeleporterComponent.FromKicker)); + _toKickerProperty = serializedObject.FindProperty(nameof(TeleporterComponent.ToKicker)); + } + + public override void OnInspectorGUI() + { + BeginEditing(); + + OnPreInspectorGUI(); + + PropertyField(_kickAfterTeleportationProperty, "Eject After Teleport"); + PropertyField(_kickDelayProperty, "Wait Before Eject (s)"); + + PropertyField(_fromKickerProperty); + PropertyField(_toKickerProperty); + + base.OnInspectorGUI(); + + EndEditing(); + } + } +} diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Teleporter/TeleporterInspector.cs.meta b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Teleporter/TeleporterInspector.cs.meta new file mode 100644 index 000000000..77be5481b --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Teleporter/TeleporterInspector.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: eda12254ad6c8504280d727e59dec3c0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/VisualPinball.Unity.Patcher/Matcher/TablePatcher.cs b/VisualPinball.Unity/VisualPinball.Unity.Patcher/Matcher/TablePatcher.cs index 7e1ff7b7d..274e99ea5 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Patcher/Matcher/TablePatcher.cs +++ b/VisualPinball.Unity/VisualPinball.Unity.Patcher/Matcher/TablePatcher.cs @@ -142,6 +142,11 @@ protected static TroughComponent CreateTrough(GameObject tableGo, GameObject par return troughComponent; } + protected T FindSiblingComponent(MonoBehaviour mb, string name) where T : MonoBehaviour + { + return mb.gameObject.transform.parent.transform.Find(name).gameObject.GetComponent(); + } + /// /// Creates a drop target bank component. /// @@ -240,6 +245,24 @@ protected static void SpotAngle(GameObject go, float outer, float inner) } } + + /// + /// Sets the angle of a spot light. + /// + /// + /// Supports multiple light sources. + /// + /// Game object of the spot light + /// Outer angle of the spot + /// Inner angle of the spot, in percent of the outer angle + protected static void PointRange(GameObject go, float outer, float inner) + { + var lights = go.GetComponentsInChildren(); + foreach (var light in lights) { + RenderPipeline.Current.LightConverter.SpotLight(light, outer, inner); + } + } + /// /// Sets a light source to pyramid spotlight and sets its parameters. /// @@ -423,7 +446,8 @@ protected static void LinkLights(GameObject go, params string[] lightNames) /// The name that the coil device's GameObject has to match in order to be linked. /// The ID of the coil mapping that the coil device will be linked to /// The coil device to be linked - protected static void LinkCoil(TableComponent tableComponent, string elementName, string coilId, ICoilDeviceComponent coilDevice) + /// If set, it's the device item, otherwise the first item of the device. + protected static void LinkCoil(TableComponent tableComponent, string elementName, string coilId, ICoilDeviceComponent coilDevice, string deviceItem = null) { if (!string.Equals(coilDevice.gameObject.name, elementName, StringComparison.OrdinalIgnoreCase)) { return; @@ -433,7 +457,7 @@ protected static void LinkCoil(TableComponent tableComponent, string elementName return; } coilMapping.Device = coilDevice; - coilMapping.DeviceItem = coilDevice.AvailableCoils.First().Id; + coilMapping.DeviceItem = deviceItem ?? coilDevice.AvailableCoils.First().Id; } /// diff --git a/VisualPinball.Unity/VisualPinball.Unity.Patcher/Patcher/Tables/Terminator2.cs b/VisualPinball.Unity/VisualPinball.Unity.Patcher/Patcher/Tables/Terminator2.cs index e9f8f913c..3f0238ce3 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Patcher/Patcher/Tables/Terminator2.cs +++ b/VisualPinball.Unity/VisualPinball.Unity.Patcher/Patcher/Tables/Terminator2.cs @@ -23,6 +23,7 @@ using UnityEditor; using UnityEngine; using VisualPinball.Engine.Math; +using VisualPinball.Engine.PinMAME; using VisualPinball.Engine.VPT; using Color = UnityEngine.Color; @@ -71,7 +72,7 @@ private static void SetupPinMame(GameObject tableGo, GameObject playfieldGo) // GLE Object.DestroyImmediate(tableGo.GetComponent()); - var pinmameGle = tableGo.AddComponent(); + var pinmameGle = tableGo.AddComponent(); pinmameGle.Game = new Engine.PinMAME.Games.Terminator2(); pinmameGle.romId = "t2_l82"; tableComponent.RepopulateHardware(pinmameGle); @@ -105,6 +106,25 @@ private static void SetupMapping(GameObject tableGo) // shooter LinkSwitch(tc, "sw78", "78", kicker); LinkCoil(tc, "sw78", "09", kicker); + + // top lock + LinkCoil(tc, "sw55", "10", kicker); + + // left lock + LinkCoil(tc, "sw51", "16", kicker); + } + + var plungers = tableGo.GetComponentsInChildren(); + foreach (var plunger in plungers) { + // kickback + LinkCoil(tc, "Plunger1", "08", plunger, PlungerComponent.FireCoilId); + } + + var teleporters = tableGo.GetComponentsInChildren(); + foreach (var teleporter in teleporters) { + + // skull kicker + LinkCoil(tc, "sw76", "01", teleporter, TeleporterComponent.CoilItem); } } @@ -197,6 +217,16 @@ public void Disable(GameObject go) go.SetActive(false); } + + [NameMatch("Wall002")] + [NameMatch("Wall003")] + public void InvisibleWall(GameObject go) + { + foreach (var mr in go.GetComponentsInChildren()) { + mr.gameObject.SetActive(false); + } + } + #endregion #region Flippers @@ -317,7 +347,7 @@ public void FixSw17(KickerComponent kickerComponent) [NameMatch("sw78")] public void Shooter(KickerComponent kickerComponent) { - kickerComponent.Coils[0].Name = "kicker_coil"; + kickerComponent.Coils[0].Name = "Shooter"; kickerComponent.Coils[0].Speed = 50; kickerComponent.Coils[0].Angle = 0; } @@ -325,11 +355,39 @@ public void Shooter(KickerComponent kickerComponent) [NameMatch("sw76")] public void SkullKicker(KickerComponent kickerComponent) { - kickerComponent.Coils[0].Name = "kicker_coil"; + kickerComponent.Coils.Clear(); + var tp = kickerComponent.gameObject.AddComponent(); + tp.FromKicker = kickerComponent; + tp.ToKicker = FindSiblingComponent(kickerComponent, "sw76a"); + tp.ToKickerItem = tp.ToKicker.AvailableCoils.First().Id; + tp.EjectDelay = 0; + tp.EjectAfterTeleportation = true; + } + + [NameMatch("sw76a")] + public void Teleporter(KickerComponent kickerComponent) + { + kickerComponent.Coils[0].Name = "Teleporter Out"; kickerComponent.Coils[0].Speed = 15; kickerComponent.Coils[0].Angle = 72; } + [NameMatch("sw55")] + public void TopLock(KickerComponent kickerComponent) + { + kickerComponent.Coils[0].Name = "Kick Out"; + kickerComponent.Coils[0].Speed = 5; + kickerComponent.Coils[0].Angle = 270; + } + + [NameMatch("sw51")] + public void LeftLock(KickerComponent kickerComponent) + { + kickerComponent.Coils[0].Name = "Kick Out"; + kickerComponent.Coils[0].Speed = 13; + kickerComponent.Coils[0].Angle = 160; + } + #endregion #region Drop Target Banks @@ -347,14 +405,43 @@ public void CreateDropTargetBank(GameObject dropTargetGo, DropTargetComponent dr #region Materials [NameMatch("_Plastics")] + [NameMatch("_RedPlastics")] [NameMatch("_RightRampPlastic")] - public void FixPlasticsMaterial(GameObject go) + [NameMatch("_StarPosts")] + public void FixTranslucentMaterials(GameObject go) { var material = go.GetComponent().sharedMaterial; RenderPipeline.Current.MaterialConverter.SetDiffusionProfile(material, DiffusionProfileTemplate.Plastics); RenderPipeline.Current.MaterialConverter.SetMaterialType(material, MaterialType.Translucent); } + [NameMatch("Cab_DT")] + [NameMatch("L52")] + [NameMatch("LSling")] + [NameMatch("Rubber2")] + [NameMatch("Rubber7")] + [NameMatch("SLING1")] + [NameMatch("T2_Gun")] + [NameMatch("_Apron")] + [NameMatch("_ChromeRails")] + [NameMatch("_CliffyPosts")] + [NameMatch("_LeftRampMetal")] + [NameMatch("_MetalPosts")] + [NameMatch("_Rubbers")] + [NameMatch("_Screws")] + [NameMatch("_SteelWalls")] + [NameMatch("_Targets")] + [NameMatch("_Washers")] + [NameMatch("_Wireforms")] + [NameMatch("batleft")] + [NameMatch("batright")] + [NameMatch("sw53")] + public void FixSolidMaterials(GameObject go) + { + var material = go.GetComponent().sharedMaterial; + RenderPipeline.Current.MaterialConverter.SetMaterialType(material, MaterialType.Standard); + } + [NameMatch("_HKShip")] public void FixShip(GameObject go) { @@ -435,9 +522,6 @@ private static void CreateFlasher28(GameObject playfieldGo) #region Global Illumination - [NameMatch("B1")] - [NameMatch("B2")] - [NameMatch("B3")] [NameMatch("GI_1")] [NameMatch("GI_2")] [NameMatch("GI_3")] @@ -523,6 +607,14 @@ public void GiIntensity(GameObject go) [NameMatch("GI_28")] public void GiDisable(GameObject go) => go.SetActive(false); + [NameMatch("B1")] + [NameMatch("B2")] + [NameMatch("B3")] + public void Bumpers(GameObject go) + { + LightIntensity(go, 1000f); + LightTemperature(go, 2700f); + } #endregion #region Insert Links diff --git a/VisualPinball.Unity/VisualPinball.Unity/Game/BallRollerComponent.cs b/VisualPinball.Unity/VisualPinball.Unity/Game/BallRollerComponent.cs new file mode 100644 index 000000000..ae7a1d475 --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity/Game/BallRollerComponent.cs @@ -0,0 +1,131 @@ +// 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 Unity.Collections; +using Unity.Entities; +using Unity.Mathematics; +using UnityEngine; +using UnityEngine.InputSystem; + +namespace VisualPinball.Unity +{ + public class BallRollerComponent : MonoBehaviour + { + private PlayfieldComponent _playfield; + private Matrix4x4 _ltw; + private Matrix4x4 _wtl; + + private Plane _playfieldPlane; + + private EntityManager _entityManager; + private Entity _ballEntity; + private EntityQuery _ballEntityQuery; + + private void Awake() + { + _playfield = GetComponentInChildren(); + + var playfieldTransform = _playfield.transform; + _ltw = playfieldTransform.localToWorldMatrix; + _wtl = playfieldTransform.worldToLocalMatrix; + + var z = _playfield.PlayfieldHeight; + var p1 = _ltw.MultiplyPoint(new Vector3(-100f, 100f, z)); + var p2 = _ltw.MultiplyPoint(new Vector3(100f, 100f, z)); + var p3 = _ltw.MultiplyPoint(new Vector3(100f, -100f, z)); + _playfieldPlane.Set3Points(p1, p2, p3); + + _entityManager = World.DefaultGameObjectInjectionWorld.EntityManager; + _ballEntityQuery = _entityManager.CreateEntityQuery(typeof(BallData)); + } + + private void Update() + { + if (Camera.main == null || _playfield == null) { + return; + } + + // find nearest ball + if (Mouse.current.middleButton.wasPressedThisFrame) { + if (GetCursorPositionOnPlayfield(out var mousePosition)) { + var ballEntities = _ballEntityQuery.ToEntityArray(Allocator.Temp); + var nearestDistance = float.PositiveInfinity; + BallData nearestBall = default; + var ballFound = false; + foreach (var ballEntity in ballEntities) { + var ballData = _entityManager.GetComponentData(ballEntity); + if (ballData.IsFrozen) { + continue; + } + var distance = math.distance(mousePosition, ballData.Position.xy); + if (distance < nearestDistance) { + nearestDistance = distance; + nearestBall = ballData; + ballFound = true; + _ballEntity = ballEntity; + } + } + + if (ballFound) { + UpdateBall(ref nearestBall, mousePosition); + } + } + + } else if (Mouse.current.middleButton.isPressed) { + if (GetCursorPositionOnPlayfield(out var mousePosition)) { + var ballData = _entityManager.GetComponentData(_ballEntity); + UpdateBall(ref ballData, mousePosition); + } + } + + if (Mouse.current.middleButton.wasReleasedThisFrame) { + var ballData = _entityManager.GetComponentData(_ballEntity); + ballData.ManualControl = false; + _entityManager.SetComponentData(_ballEntity, ballData); + } + } + + private void UpdateBall(ref BallData ballData, float2 position) + { + ballData.ManualControl = true; + ballData.ManualPosition = position; + _entityManager.SetComponentData(_ballEntity, ballData); + } + + private bool GetCursorPositionOnPlayfield(out float2 position) + { + if (Camera.main == null) { + position = float2.zero; + return false; + } + + var mouseOnScreenPos = Mouse.current.position.ReadValue(); + var ray = Camera.main.ScreenPointToRay(mouseOnScreenPos); + + if (_playfieldPlane.Raycast(ray, out var enter)) { + var playfieldPosWorld = ray.GetPoint(enter); + var playfieldPosLocal = _wtl.MultiplyPoint(playfieldPosWorld); + + position = new float2(playfieldPosLocal.x, playfieldPosLocal.y); + + // todo check playfield bounds + return true; + } + position = float2.zero; + return false; + } + } +} diff --git a/VisualPinball.Unity/VisualPinball.Unity/Game/BallRollerComponent.cs.meta b/VisualPinball.Unity/VisualPinball.Unity/Game/BallRollerComponent.cs.meta new file mode 100644 index 000000000..720d88f71 --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity/Game/BallRollerComponent.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f1b73baf8371338429320656a070566d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 41211858d62e7904ab09fc592d292bba, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/VisualPinball.Unity/Game/CameraTranslateAndOrbit.cs b/VisualPinball.Unity/VisualPinball.Unity/Game/CameraTranslateAndOrbit.cs new file mode 100644 index 000000000..450e712ac --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity/Game/CameraTranslateAndOrbit.cs @@ -0,0 +1,142 @@ +using UnityEngine; +using UnityEngine.InputSystem; + +/// +/// A simple camera orbit script that works with Unity's new Input System. +/// +public class CameraTranslateAndOrbit : MonoBehaviour +{ + public float zoomSpeed = 0.1f; + + public Transform transformCache; + public bool isAnimating; + + public GameObject dummyForRotation; + public Transform dummyTransform; + + private float _radius; + private Vector3 _focusPoint; + private float _radiusCurrent = 15f; + private bool _isTrackingMouse0; + private Vector2 _mouse0StartPosition; + + private bool _isTrackingMouse1; + private Vector2 _mouse1StartPosition; + + public Vector3 positionOffset = Vector3.zero; + private Vector3 _positionOffsetCurrent = Vector3.zero; + + private Quaternion _rot2 = Quaternion.identity; + + private const float RadiusMin = 0.5f; + + private void Start() + { + _radius = Vector3.Distance(Vector3.zero, transform.position); + transformCache = transform; + _focusPoint = transformCache.forward * -1f * _radius; + _positionOffsetCurrent = positionOffset; + _radiusCurrent = _radius; + dummyForRotation = new GameObject(); + dummyTransform = dummyForRotation.transform; + + dummyTransform.rotation = transformCache.rotation; + dummyTransform.position = transformCache.position; + _rot2 = transformCache.rotation; + } + + + private void OrbitAroundObject(Vector3 newOffset, float radiusRef) + { + positionOffset = newOffset; + _positionOffsetCurrent = positionOffset; + _radius = radiusRef; + _radiusCurrent = _radius; + } + + + // Update is called once per frame + private void Update() + { + transformCache.position = dummyTransform.position = Vector3.zero; + + var hasHitRestrictedHitArea = false; + if (Mouse.current == null) { + return; + } + + if (Mouse.current.leftButton.wasPressedThisFrame) { + _mouse0StartPosition = Mouse.current.position.ReadValue(); + _isTrackingMouse0 = true; + } + + if (_mouse0StartPosition.x < 200f && _mouse0StartPosition.y > Screen.height - 200f) { + hasHitRestrictedHitArea = true; + } + + if (!hasHitRestrictedHitArea) { + if (_isTrackingMouse0) { + Vector3 mousePositionDifference = Mouse.current.position.ReadValue() - _mouse0StartPosition; + dummyTransform.Rotate(Vector3.up, mousePositionDifference.x * 0.4f, Space.World); + + dummyTransform.Rotate(dummyTransform.right.normalized, mousePositionDifference.y * -0.4f, + Space.World); + _rot2 = dummyTransform.rotation; + _mouse0StartPosition = Mouse.current.position.ReadValue(); + } + transformCache.rotation = Quaternion.Lerp(transformCache.rotation, _rot2, Time.deltaTime * 4f); + } + + + if (Mouse.current.leftButton.wasReleasedThisFrame) { + _isTrackingMouse0 = false; + } + + + if (Mouse.current.rightButton.wasPressedThisFrame) { + _mouse1StartPosition = Mouse.current.position.ReadValue(); + _isTrackingMouse1 = true; + } + + if (!hasHitRestrictedHitArea) { + if (_isTrackingMouse1) { + var mousePositionDifference = Mouse.current.position.ReadValue() - _mouse1StartPosition; + //Vector3 XZPlanerDirection = transformCache.forward.normalized; + //XZPlanerDirection.y = 0; + + positionOffset += transformCache.up.normalized * (mousePositionDifference.y * -(_radius / 2f / 100f)); + + positionOffset += transformCache.right.normalized * + (mousePositionDifference.x * -(_radius / 2f / 100f)); + /* + if(positionOffset.y < 0){ + positionOffset.y = 0; + }*/ + + _mouse1StartPosition = Mouse.current.position.ReadValue(); + } + } + + if (Mouse.current.rightButton.wasReleasedThisFrame) { + _isTrackingMouse1 = false; + } + + if (!hasHitRestrictedHitArea) { + if (!isAnimating) { + var delta = Mouse.current.scroll.y.ReadValue() / 1000f * zoomSpeed * -_radius; + _radius += delta; + if (_radius < RadiusMin) { + var radDiff = RadiusMin - _radius; + positionOffset += transformCache.forward * (radDiff * 4f); + _radius = RadiusMin; + } + } + } + + _positionOffsetCurrent = Vector3.Lerp(_positionOffsetCurrent, positionOffset, Time.deltaTime * 4f); + _radiusCurrent = Mathf.Lerp(_radiusCurrent, _radius, Time.deltaTime * 4f); + _focusPoint = transformCache.forward * -1f * _radiusCurrent; + transformCache.position = _focusPoint + _positionOffsetCurrent; + dummyTransform.position = transformCache.position; + } +} diff --git a/VisualPinball.Unity/VisualPinball.Unity/Game/CameraTranslateAndOrbit.cs.meta b/VisualPinball.Unity/VisualPinball.Unity/Game/CameraTranslateAndOrbit.cs.meta new file mode 100644 index 000000000..d24c39a80 --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity/Game/CameraTranslateAndOrbit.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2bbdee04830a45449bbceaa234a2a2b6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/VisualPinball.Unity/Game/Player.cs b/VisualPinball.Unity/VisualPinball.Unity/Game/Player.cs index 0c9ecdd32..68cd10352 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/Game/Player.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/Game/Player.cs @@ -294,6 +294,11 @@ public void RegisterSurface(SurfaceComponent component, Entity entity, Entity pa Register(new SurfaceApi(component.gameObject, entity, parentEntity, this), component, entity); } + public void RegisterTeleporter(TeleporterComponent component) + { + Register(new TeleporterApi(component.gameObject, this), component); + } + public void RegisterTrigger(TriggerComponent component, Entity entity, Entity parentEntity) { Register(new TriggerApi(component.gameObject, entity, parentEntity, this), component, entity); diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Ball/BallData.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Ball/BallData.cs index 66a8f476f..89890b652 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Ball/BallData.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Ball/BallData.cs @@ -34,6 +34,9 @@ internal struct BallData : IComponentData public bool IsFrozen; public int RingCounterOldPos; + public bool ManualControl; + public float2 ManualPosition; + public float3 OldVelocity; public Aabb Aabb { diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Ball/BallManager.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Ball/BallManager.cs index a3e2be90b..669950667 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Ball/BallManager.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Ball/BallManager.cs @@ -104,7 +104,7 @@ public void CreateEntity(GameObject ballGo, int id, in float3 worldPos, in float ecb.AddComponent(entity, new BallData { Id = id, - IsFrozen = false, + IsFrozen = kickerEntity != Entity.Null, Position = localPos, Radius = radius, Mass = mass, diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Ball/BallVelocitySystem.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Ball/BallVelocitySystem.cs index 774330782..86d5448b9 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Ball/BallVelocitySystem.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Ball/BallVelocitySystem.cs @@ -47,7 +47,16 @@ protected override void OnUpdate() marker.Begin(); - ball.Velocity += gravity * (float)PhysicsConstants.PhysFactor; + if (ball.ManualControl) { + ball.Velocity *= 0.5f; // Null out most of the X/Y velocity, want a little bit so the ball can sort of find its way out of obstacles. + ball.Velocity += new float3( + math.max(-10.0f, math.min(10.0f, (ball.ManualPosition.x - ball.Position.x) * (float)(1.0/10.0))), + math.max(-10.0f, math.min(10.0f, (ball.ManualPosition.y - ball.Position.y) * (float)(1.0/10.0))), + -2.0f + ); + } else { + ball.Velocity += gravity * (float)PhysicsConstants.PhysFactor; + } marker.End(); diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Bumper/BumperComponent.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Bumper/BumperComponent.cs index 9c7750026..87a5ffeea 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Bumper/BumperComponent.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Bumper/BumperComponent.cs @@ -215,7 +215,7 @@ public override IEnumerable SetData(BumperData data) public override IEnumerable SetReferencedData(BumperData data, Table table, IMaterialProvider materialProvider, ITextureProvider textureProvider, Dictionary components) { - Surface = FindComponent(components, data.Surface); + Surface = FindComponent(components, data.Surface); UpdateTransforms(); // children visibility diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Flipper/FlipperComponent.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Flipper/FlipperComponent.cs index 771ba5855..6ea2aef75 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Flipper/FlipperComponent.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Flipper/FlipperComponent.cs @@ -253,7 +253,7 @@ public override IEnumerable SetData(FlipperData data) public override IEnumerable SetReferencedData(FlipperData data, Table table, IMaterialProvider materialProvider, ITextureProvider textureProvider, Dictionary components) { - Surface = FindComponent(components, data.Surface); + Surface = FindComponent(components, data.Surface); UpdateTransforms(); // children mesh creation and visibility diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Gate/GateComponent.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Gate/GateComponent.cs index 053803db9..febbf4612 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Gate/GateComponent.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Gate/GateComponent.cs @@ -211,7 +211,7 @@ public override IEnumerable SetData(GateData data) public override IEnumerable SetReferencedData(GateData data, Table table, IMaterialProvider materialProvider, ITextureProvider textureProvider, Dictionary components) { - Surface = FindComponent(components, data.Surface); + Surface = FindComponent(components, data.Surface); // visibility foreach (var mf in GetComponentsInChildren()) { diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Kicker/KickerApi.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Kicker/KickerApi.cs index 5ff8f40ad..8fed6e36e 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Kicker/KickerApi.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Kicker/KickerApi.cs @@ -108,6 +108,26 @@ public void DestroyBall() (this as IApiSwitch).DestroyBall(ballEntity); } + /// + /// Checks whether the kicker contains a ball. + /// + /// True if there is a ball in the kicker, false otherwise. + public bool HasBall() + { + var entityManager = World.DefaultGameObjectInjectionWorld.EntityManager; + var kickerCollisionData = entityManager.GetComponentData(Entity); + return kickerCollisionData.HasBall; + } + + internal BallData GetBallData() + { + var entityManager = World.DefaultGameObjectInjectionWorld.EntityManager; + var kickerCollisionData = entityManager.GetComponentData(Entity); + return kickerCollisionData.HasBall + ? entityManager.GetComponentData(kickerCollisionData.BallEntity) + : default; + } + #region Wiring public bool IsSwitchEnabled => SwitchHandler.IsEnabled; diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Kicker/KickerComponent.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Kicker/KickerComponent.cs index 4ee8a9c22..dfe3263d0 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Kicker/KickerComponent.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Kicker/KickerComponent.cs @@ -216,7 +216,7 @@ public override IEnumerable SetData(KickerData data) public override IEnumerable SetReferencedData(KickerData data, Table table, IMaterialProvider materialProvider, ITextureProvider textureProvider, Dictionary components) { - Surface = FindComponent(components, data.Surface); + Surface = FindComponent(components, data.Surface); return Array.Empty(); } diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Light/LightComponent.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Light/LightComponent.cs index 478e372ec..692a558b3 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Light/LightComponent.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Light/LightComponent.cs @@ -301,7 +301,7 @@ public override IEnumerable SetData(LightData data) public override IEnumerable SetReferencedData(LightData data, Table table, IMaterialProvider materialProvider, ITextureProvider textureProvider, Dictionary components) { - Surface = FindComponent(components, data.Surface); + Surface = FindComponent(components, data.Surface); // visibility if (!data.ShowBulbMesh) { diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/MainComponent.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/MainComponent.cs index 4969f625d..c5eecb062 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/MainComponent.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/MainComponent.cs @@ -55,7 +55,7 @@ public int PlayfieldDetailLevel { public abstract ItemType ItemType { get; } - protected T FindComponent(Dictionary components, string surfaceName) where T : class, IMainComponent + protected T FindComponent(Dictionary components, string surfaceName) where T : class { return (components != null && components.ContainsKey(surfaceName.ToLower()) ? components[surfaceName.ToLower()] diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Mech/CannonApi.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Mech/CannonApi.cs index f610492bb..c5841be08 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Mech/CannonApi.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Mech/CannonApi.cs @@ -1,9 +1,25 @@ -using System; -using Logger = NLog.Logger; -using NLog; -using UnityEngine; - -namespace VisualPinball.Unity +// 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 { @@ -26,7 +42,7 @@ private enum Direction public event EventHandler Init; - private bool _enabled; + private bool _enabled; private float _position; private Direction _direction; @@ -158,5 +174,5 @@ void IApi.OnDestroy() 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 index c8e0c6e94..4b37ce6b7 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Mech/CannonComponent.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Mech/CannonComponent.cs @@ -1,10 +1,26 @@ -using System.Collections.Generic; -using UnityEngine; -using VisualPinball.Engine.Game.Engines; -using Logger = NLog.Logger; -using NLog; - -namespace VisualPinball.Unity +// 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 @@ -57,5 +73,5 @@ public void UpdateRotation(float y) transform.rotation = rotation; } - } -} + } +} diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Plunger/PlungerComponent.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Plunger/PlungerComponent.cs index bd658722e..3d71472a3 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Plunger/PlungerComponent.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Plunger/PlungerComponent.cs @@ -245,7 +245,7 @@ public override IEnumerable SetData(PlungerData data) public override IEnumerable SetReferencedData(PlungerData data, Table table, IMaterialProvider materialProvider, ITextureProvider textureProvider, Dictionary components) { - Surface = FindComponent(components, data.Surface); + Surface = FindComponent(components, data.Surface); // rod mesh var rodMesh = GetComponentInChildren(true); diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Spinner/SpinnerComponent.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Spinner/SpinnerComponent.cs index 4f85ad30b..5c82f73ef 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Spinner/SpinnerComponent.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Spinner/SpinnerComponent.cs @@ -199,7 +199,7 @@ public override IEnumerable SetData(SpinnerData data) public override IEnumerable SetReferencedData(SpinnerData data, Table table, IMaterialProvider materialProvider, ITextureProvider textureProvider, Dictionary components) { - Surface = FindComponent(components, data.Surface); + Surface = FindComponent(components, data.Surface); return Array.Empty(); } diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Table/TableApi.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Table/TableApi.cs index f5b64795f..8a075d197 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Table/TableApi.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Table/TableApi.cs @@ -27,43 +27,47 @@ public class TableApi : IApi #region Dictionaries private readonly Dictionary _bumpersByName = new Dictionary(); - private readonly Dictionary _flippersByName = 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(); private readonly Dictionary _gatesByName = new Dictionary(); private readonly Dictionary _hitTargetsByName = new Dictionary(); private readonly Dictionary _kickersByName = new Dictionary(); private readonly Dictionary _lightsByName = new Dictionary(); private readonly Dictionary _lightGroupsByName = new Dictionary(); private readonly Dictionary _plungersByName = new Dictionary(); + private readonly Dictionary _primitivesByName = new Dictionary(); private readonly Dictionary _rampsByName = new Dictionary(); private readonly Dictionary _rubbersByName = new Dictionary(); private readonly Dictionary _spinnersByName = new Dictionary(); private readonly Dictionary _surfacesByName = new Dictionary(); + private readonly Dictionary _teleportersByName = new Dictionary(); private readonly Dictionary _triggersByName = new Dictionary(); private readonly Dictionary _troughsByName = new Dictionary(); - private readonly Dictionary _primitivesByName = new Dictionary(); - private readonly Dictionary _cannonsByName = new Dictionary(); - private readonly Dictionary _dropTargetBanksByName = new Dictionary(); private readonly Dictionary _bumpersByComponent = new Dictionary(); - private readonly Dictionary _flippersByComponent = 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(); private readonly Dictionary _gatesByComponent = new Dictionary(); private readonly Dictionary _hitTargetsByComponent = new Dictionary(); private readonly Dictionary _kickersByComponent = new Dictionary(); private readonly Dictionary _lightsByComponent = new Dictionary(); private readonly Dictionary _lightGroupsByComponent = new Dictionary(); private readonly Dictionary _plungersByComponent = new Dictionary(); + private readonly Dictionary _primitivesByComponent = new Dictionary(); private readonly Dictionary _rampsByComponent = new Dictionary(); private readonly Dictionary _rubbersByComponent = new Dictionary(); private readonly Dictionary _spinnersByComponent = new Dictionary(); private readonly Dictionary _surfacesByComponent = new Dictionary(); + private readonly Dictionary _teleportersByComponent = new Dictionary(); private readonly Dictionary _triggersByComponent = new Dictionary(); private readonly Dictionary _troughsByComponent = new Dictionary(); - private readonly Dictionary _primitivesByComponent = new Dictionary(); - private readonly Dictionary _cannonsByComponent = new Dictionary(); - private readonly Dictionary _dropTargetBanksByComponent = new Dictionary(); #endregion @@ -242,46 +246,52 @@ 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(FlipperApi)) return _flippersByName 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; if (t == typeof(GateApi)) return _gatesByName as Dictionary; if (t == typeof(HitTargetApi)) return _hitTargetsByName as Dictionary; if (t == typeof(KickerApi)) return _kickersByName as Dictionary; if (t == typeof(LightApi)) return _lightsByName as Dictionary; if (t == typeof(LightGroupApi)) return _lightGroupsByName as Dictionary; if (t == typeof(PlungerApi)) return _plungersByName as Dictionary; + if (t == typeof(PrimitiveApi)) return _primitivesByName as Dictionary; + if (t == typeof(PrimitiveApi)) return _primitivesByName as Dictionary; 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(SurfaceApi)) return _surfacesByName as Dictionary; + if (t == typeof(TeleporterApi)) return _teleportersByName as Dictionary; if (t == typeof(TriggerApi)) return _triggersByName as Dictionary; if (t == typeof(TroughApi)) return _troughsByName as Dictionary; - if (t == typeof(PrimitiveApi)) return _primitivesByName as Dictionary; - if (t == typeof(CannonApi)) return _cannonsByName as Dictionary; - if (t == typeof(DropTargetBankApi)) return _dropTargetBanksByName as Dictionary; throw new ArgumentException($"Unknown API type {t}."); } private Dictionary GetComponentDictionary(Type t) where T : IApi { if (t == typeof(BumperApi)) return _bumpersByComponent as Dictionary; - if (t == typeof(FlipperApi)) return _flippersByComponent 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; if (t == typeof(GateApi)) return _gatesByComponent as Dictionary; if (t == typeof(HitTargetApi)) return _hitTargetsByComponent as Dictionary; if (t == typeof(KickerApi)) return _kickersByComponent as Dictionary; if (t == typeof(LightApi)) return _lightsByComponent as Dictionary; if (t == typeof(LightGroupApi)) return _lightGroupsByComponent as Dictionary; if (t == typeof(PlungerApi)) return _plungersByComponent as Dictionary; + if (t == typeof(PrimitiveApi)) return _primitivesByComponent as Dictionary; + if (t == typeof(PrimitiveApi)) return _primitivesByComponent as Dictionary; 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(SurfaceApi)) return _surfacesByComponent as Dictionary; + if (t == typeof(TeleporterApi)) return _teleportersByComponent as Dictionary; if (t == typeof(TriggerApi)) return _triggersByComponent as Dictionary; if (t == typeof(TroughApi)) return _troughsByComponent as Dictionary; - if (t == typeof(PrimitiveApi)) return _primitivesByComponent as Dictionary; - if (t == typeof(CannonApi)) return _cannonsByComponent as Dictionary; - if (t == typeof(DropTargetBankApi)) return _dropTargetBanksByComponent as Dictionary; throw new ArgumentException($"Unknown API type {t}."); } diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Teleporter.meta b/VisualPinball.Unity/VisualPinball.Unity/VPT/Teleporter.meta new file mode 100644 index 000000000..f4319c4f5 --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Teleporter.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ce0e4c62b28a8974398843e1b0b4d79a +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Teleporter/TeleporterApi.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Teleporter/TeleporterApi.cs new file mode 100644 index 000000000..c56dd538a --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Teleporter/TeleporterApi.cs @@ -0,0 +1,104 @@ +// 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 ConvertIfStatementToSwitchStatement + +using System; +using Logger = NLog.Logger; +using NLog; +using Unity.Entities; +using Unity.Mathematics; +using UnityEngine; + +namespace VisualPinball.Unity +{ + public class TeleporterApi : IApi, IApiCoilDevice + { + private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); + + private readonly TeleporterComponent _component; + private readonly Player _player; + + private DeviceCoil _teleporterCoil; + private KickerApi _fromKicker; + private KickerApi _toKicker; + private readonly VisualPinballSimulationSystemGroup _simulationSystemGroup; + + public event EventHandler Init; + + internal TeleporterApi(GameObject go, Player player) + { + _component = go.GetComponentInChildren(); + _player = player; + _simulationSystemGroup = World.DefaultGameObjectInjectionWorld.GetOrCreateSystem(); + } + + void IApi.OnInit(BallManager ballManager) + { + _teleporterCoil = new DeviceCoil(OnTeleport); + _fromKicker = _player.TableApi.Kicker(_component.FromKicker); + _toKicker = _player.TableApi.Kicker(_component.ToKicker); + + Init?.Invoke(this, EventArgs.Empty); + } + + IApiCoil IApiCoilDevice.Coil(string _) => _teleporterCoil; + + private void OnTeleport() + { + if (_toKicker == null || _fromKicker == null) { + Logger.Warn($"[teleporter {_component.name}] Cannot teleport due to missing kicker configuration."); + return; + } + + var ballInSrc = _fromKicker.HasBall(); + var ballInDst = _toKicker.HasBall(); + if (!ballInSrc || ballInDst) { + // duh, do nothing. + return; + } + + var ballData = _fromKicker.GetBallData(); + _fromKicker.DestroyBall(); + _toKicker.CreateSizedBallWithMass(ballData.Radius, ballData.Mass); + + // if no eject, we're done here. + if (!_component.EjectAfterTeleportation) { + return; + } + + if (_component.EjectDelay > 0) { + _simulationSystemGroup.ScheduleAction((int)math.round(_component.EjectDelay * 1000f), Eject); + + } else { + Eject(); + } + } + + private void Eject() + { + if (!string.IsNullOrEmpty(_component.ToKickerItem)) { + var kickerCoil = (_toKicker as IApiCoilDevice).Coil(_component.ToKickerItem); + kickerCoil.OnCoil(true); + } + } + + void IApi.OnDestroy() + { + } + } +} + diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Teleporter/TeleporterApi.cs.meta b/VisualPinball.Unity/VisualPinball.Unity/VPT/Teleporter/TeleporterApi.cs.meta new file mode 100644 index 000000000..71a09f5da --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Teleporter/TeleporterApi.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4a0a07c989322cf429cf5f8bc775f906 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Teleporter/TeleporterComponent.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Teleporter/TeleporterComponent.cs new file mode 100644 index 000000000..706681aa5 --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Teleporter/TeleporterComponent.cs @@ -0,0 +1,88 @@ +// 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 UnityEngine; +using VisualPinball.Engine.Game.Engines; +using Logger = NLog.Logger; +using NLog; + +namespace VisualPinball.Unity +{ + [AddComponentMenu("Visual Pinball/Game Item/Teleporter")] + [HelpURL("https://docs.visualpinball.org/creators-guide/manual/mechanisms/teleporters.html")] + public class TeleporterComponent : MonoBehaviour, ICoilDeviceComponent + { + #region Data + + [Tooltip("If set, the ball is automatically popped out of the destination kicker upon arrival.")] + public bool EjectAfterTeleportation = true; + + [Min(0)] + [Tooltip("The time in seconds between the ball arriving at the destination kicker and being popped out of the kicker.")] + public float EjectDelay = 0.5f; + + [Tooltip("The kicker where the ball is teleported from.")] + public KickerComponent FromKicker; + + [Tooltip("The kicker where the ball is teleported into, and which coil should be used to pop the ball out.")] + [TypeRestriction(typeof(KickerComponent), PickerLabel = "Kickers", DeviceItem = nameof(ToKickerItem), DeviceType = typeof(ICoilDeviceComponent))] + public KickerComponent ToKicker; + public string ToKickerItem = string.Empty; + + #endregion + + #region Overrides and Constants + + public const string CoilItem = "teleport"; + + private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); + + #endregion + + #region Wiring + + IEnumerable IDeviceComponent.AvailableDeviceItems => AvailableCoils; + IEnumerable IWireableComponent.AvailableWireDestinations => AvailableCoils; + IEnumerable IDeviceComponent.AvailableDeviceItems => AvailableCoils; + + public IEnumerable AvailableCoils => new[] { + new GamelogicEngineCoil(CoilItem) { + Description = "Teleport Ball" + } + }; + + #endregion + + #region Runtime + + private void Awake() + { + var player = GetComponentInParent(); + if (player == null) + { + Logger.Error($"Cannot find player for cannon {name}."); + return; + } + + player.RegisterTeleporter(this); + } + + #endregion + } +} diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Teleporter/TeleporterComponent.cs.meta b/VisualPinball.Unity/VisualPinball.Unity/VPT/Teleporter/TeleporterComponent.cs.meta new file mode 100644 index 000000000..d7769dbae --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Teleporter/TeleporterComponent.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 14a789bd4f52b574a926b9b3282627b2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 57668c3df120da245975f2022cbf0551, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Trigger/TriggerComponent.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Trigger/TriggerComponent.cs index 7798d3cf6..ec7a03048 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Trigger/TriggerComponent.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Trigger/TriggerComponent.cs @@ -174,7 +174,7 @@ public override IEnumerable SetData(TriggerData data) public override IEnumerable SetReferencedData(TriggerData data, Table table, IMaterialProvider materialProvider, ITextureProvider textureProvider, Dictionary components) { - Surface = FindComponent(components, data.Surface); + Surface = FindComponent(components, data.Surface); // mesh var meshComponent = GetComponent();