diff --git a/Assets/Prefabs/MineableBlock.prefab b/Assets/Prefabs/MineableBlock.prefab index 127fc5a..17105fc 100644 --- a/Assets/Prefabs/MineableBlock.prefab +++ b/Assets/Prefabs/MineableBlock.prefab @@ -14,6 +14,7 @@ GameObject: - component: {fileID: 3086293200253757409} - component: {fileID: 7528764990365051674} - component: {fileID: 3421159559893464927} + - component: {fileID: -6050457801577222831} m_Layer: 12 m_Name: MineableBlock m_TagString: Untagged @@ -127,7 +128,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: d5a57f767e5e46a458fc5d3c628d0cbb, type: 3} m_Name: m_EditorClassIdentifier: Unity.Netcode.Runtime::Unity.Netcode.NetworkObject - GlobalObjectIdHash: 3286197765 + GlobalObjectIdHash: 3862515551 InScenePlacedSourceGlobalObjectIdHash: 3862515551 DeferredDespawnTick: 0 Ownership: 1 @@ -154,4 +155,23 @@ MonoBehaviour: m_EditorClassIdentifier: Assembly-CSharp::MineableBlock ShowTopMostFoldoutHeaderGroup: 1 maxHp: 100 - breakEffectPrefab: {fileID: 0} + shakeDuration: 0.1 + shakeMagnitude: 0.1 +--- !u!114 &-6050457801577222831 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 989066657509100432} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5fea29bb7c508c244a1f805a5fd3fc4d, type: 3} + m_Name: + m_EditorClassIdentifier: Assembly-CSharp::Outline + outlineMode: 0 + outlineColor: {r: 1, g: 1, b: 1, a: 1} + outlineWidth: 5 + precomputeOutline: 0 + bakeKeys: [] + bakeValues: [] diff --git a/Assets/Prefabs/Player.prefab b/Assets/Prefabs/Player.prefab index c6d2334..817c403 100644 --- a/Assets/Prefabs/Player.prefab +++ b/Assets/Prefabs/Player.prefab @@ -8,6 +8,14 @@ PrefabInstance: serializedVersion: 3 m_TransformParent: {fileID: 0} m_Modifications: + - target: {fileID: -9217289772674400175, guid: ffaf1ddb2ff58d2448ccfdd357387f63, type: 3} + propertyPath: m_Layer + value: 9 + objectReference: {fileID: 0} + - target: {fileID: -8749280752073934791, guid: ffaf1ddb2ff58d2448ccfdd357387f63, type: 3} + propertyPath: m_Layer + value: 9 + objectReference: {fileID: 0} - target: {fileID: -8679921383154817045, guid: ffaf1ddb2ff58d2448ccfdd357387f63, type: 3} propertyPath: m_LocalPosition.x value: 0 @@ -48,6 +56,74 @@ PrefabInstance: propertyPath: m_LocalEulerAnglesHint.z value: 0 objectReference: {fileID: 0} + - target: {fileID: -8629495297202134608, guid: ffaf1ddb2ff58d2448ccfdd357387f63, type: 3} + propertyPath: m_Layer + value: 9 + objectReference: {fileID: 0} + - target: {fileID: -8343894014087287100, guid: ffaf1ddb2ff58d2448ccfdd357387f63, type: 3} + propertyPath: m_Layer + value: 9 + objectReference: {fileID: 0} + - target: {fileID: -7440837640338354081, guid: ffaf1ddb2ff58d2448ccfdd357387f63, type: 3} + propertyPath: m_Layer + value: 9 + objectReference: {fileID: 0} + - target: {fileID: -6645333679261498596, guid: ffaf1ddb2ff58d2448ccfdd357387f63, type: 3} + propertyPath: m_Layer + value: 9 + objectReference: {fileID: 0} + - target: {fileID: -6415790494268509736, guid: ffaf1ddb2ff58d2448ccfdd357387f63, type: 3} + propertyPath: m_Layer + value: 9 + objectReference: {fileID: 0} + - target: {fileID: -5821640607724269708, guid: ffaf1ddb2ff58d2448ccfdd357387f63, type: 3} + propertyPath: m_Layer + value: 9 + objectReference: {fileID: 0} + - target: {fileID: -5489203338784653783, guid: ffaf1ddb2ff58d2448ccfdd357387f63, type: 3} + propertyPath: m_Layer + value: 9 + objectReference: {fileID: 0} + - target: {fileID: -5235451391474362517, guid: ffaf1ddb2ff58d2448ccfdd357387f63, type: 3} + propertyPath: m_Layer + value: 9 + objectReference: {fileID: 0} + - target: {fileID: -3771971891951071861, guid: ffaf1ddb2ff58d2448ccfdd357387f63, type: 3} + propertyPath: m_Layer + value: 9 + objectReference: {fileID: 0} + - target: {fileID: -3230676936149971385, guid: ffaf1ddb2ff58d2448ccfdd357387f63, type: 3} + propertyPath: m_Layer + value: 9 + objectReference: {fileID: 0} + - target: {fileID: -3087093466631822622, guid: ffaf1ddb2ff58d2448ccfdd357387f63, type: 3} + propertyPath: m_Layer + value: 9 + objectReference: {fileID: 0} + - target: {fileID: -2565563256467093774, guid: ffaf1ddb2ff58d2448ccfdd357387f63, type: 3} + propertyPath: m_Layer + value: 9 + objectReference: {fileID: 0} + - target: {fileID: -2268532608001192311, guid: ffaf1ddb2ff58d2448ccfdd357387f63, type: 3} + propertyPath: m_Layer + value: 9 + objectReference: {fileID: 0} + - target: {fileID: -787705004876472881, guid: ffaf1ddb2ff58d2448ccfdd357387f63, type: 3} + propertyPath: m_Layer + value: 9 + objectReference: {fileID: 0} + - target: {fileID: -129758803659467788, guid: ffaf1ddb2ff58d2448ccfdd357387f63, type: 3} + propertyPath: m_Layer + value: 9 + objectReference: {fileID: 0} + - target: {fileID: 58325350010635884, guid: ffaf1ddb2ff58d2448ccfdd357387f63, type: 3} + propertyPath: m_Layer + value: 9 + objectReference: {fileID: 0} + - target: {fileID: 316027028415609013, guid: ffaf1ddb2ff58d2448ccfdd357387f63, type: 3} + propertyPath: m_Layer + value: 9 + objectReference: {fileID: 0} - target: {fileID: 919132149155446097, guid: ffaf1ddb2ff58d2448ccfdd357387f63, type: 3} propertyPath: m_Name value: Player @@ -60,6 +136,58 @@ PrefabInstance: propertyPath: m_TagString value: Player objectReference: {fileID: 0} + - target: {fileID: 2071513765411332684, guid: ffaf1ddb2ff58d2448ccfdd357387f63, type: 3} + propertyPath: m_Layer + value: 9 + objectReference: {fileID: 0} + - target: {fileID: 2870523794981691266, guid: ffaf1ddb2ff58d2448ccfdd357387f63, type: 3} + propertyPath: m_Layer + value: 9 + objectReference: {fileID: 0} + - target: {fileID: 3424958915229829536, guid: ffaf1ddb2ff58d2448ccfdd357387f63, type: 3} + propertyPath: m_Layer + value: 9 + objectReference: {fileID: 0} + - target: {fileID: 4260319478689324092, guid: ffaf1ddb2ff58d2448ccfdd357387f63, type: 3} + propertyPath: m_Layer + value: 9 + objectReference: {fileID: 0} + - target: {fileID: 4700718891997078985, guid: ffaf1ddb2ff58d2448ccfdd357387f63, type: 3} + propertyPath: m_Layer + value: 9 + objectReference: {fileID: 0} + - target: {fileID: 4902866164562761394, guid: ffaf1ddb2ff58d2448ccfdd357387f63, type: 3} + propertyPath: m_Layer + value: 9 + objectReference: {fileID: 0} + - target: {fileID: 6026115103549348504, guid: ffaf1ddb2ff58d2448ccfdd357387f63, type: 3} + propertyPath: m_Layer + value: 9 + objectReference: {fileID: 0} + - target: {fileID: 6041330210177057777, guid: ffaf1ddb2ff58d2448ccfdd357387f63, type: 3} + propertyPath: m_Layer + value: 9 + objectReference: {fileID: 0} + - target: {fileID: 7116785954168059035, guid: ffaf1ddb2ff58d2448ccfdd357387f63, type: 3} + propertyPath: m_Layer + value: 9 + objectReference: {fileID: 0} + - target: {fileID: 7354008096416770832, guid: ffaf1ddb2ff58d2448ccfdd357387f63, type: 3} + propertyPath: m_Layer + value: 9 + objectReference: {fileID: 0} + - target: {fileID: 8498165350272959449, guid: ffaf1ddb2ff58d2448ccfdd357387f63, type: 3} + propertyPath: m_Layer + value: 9 + objectReference: {fileID: 0} + - target: {fileID: 8674666463418728774, guid: ffaf1ddb2ff58d2448ccfdd357387f63, type: 3} + propertyPath: m_Layer + value: 9 + objectReference: {fileID: 0} + - target: {fileID: 9179509530285530577, guid: ffaf1ddb2ff58d2448ccfdd357387f63, type: 3} + propertyPath: m_Layer + value: 9 + objectReference: {fileID: 0} m_RemovedComponents: [] m_RemovedGameObjects: [] m_AddedGameObjects: @@ -213,10 +341,18 @@ MonoBehaviour: m_Bits: 256 buildSpeedMultiplier: 2 attackRange: 5 + aimRadius: 0.5 miningDamage: 25 mineableLayer: serializedVersion: 2 m_Bits: 4096 + ignoreDuringAim: + serializedVersion: 2 + m_Bits: 640 + crosshairScreenRadius: 200 + crosshairUI: {fileID: 0} + idleCrosshair: {fileID: 2628378444897590106, guid: 174f7cb20aaa6d4409b788a700a925ad, type: 3} + targetCrosshair: {fileID: -5662625722731528258, guid: 7652364ca249c3144813de7eb3d1b129, type: 3} --- !u!114 &106528027568436521 MonoBehaviour: m_ObjectHideFlags: 0 @@ -356,6 +492,10 @@ PrefabInstance: propertyPath: m_Name value: Bat objectReference: {fileID: 0} + - target: {fileID: 919132149155446097, guid: b27a875d1f1770c47ad339508a336e15, type: 3} + propertyPath: m_Layer + value: 9 + objectReference: {fileID: 0} m_RemovedComponents: [] m_RemovedGameObjects: [] m_AddedGameObjects: [] @@ -418,6 +558,10 @@ PrefabInstance: propertyPath: m_Name value: Bat objectReference: {fileID: 0} + - target: {fileID: 919132149155446097, guid: b27a875d1f1770c47ad339508a336e15, type: 3} + propertyPath: m_Layer + value: 9 + objectReference: {fileID: 0} m_RemovedComponents: [] m_RemovedGameObjects: [] m_AddedGameObjects: [] diff --git a/Assets/Prefabs/ResourceBlock.prefab b/Assets/Prefabs/ResourceBlock.prefab index 002abc3..8532851 100644 --- a/Assets/Prefabs/ResourceBlock.prefab +++ b/Assets/Prefabs/ResourceBlock.prefab @@ -14,6 +14,7 @@ GameObject: - component: {fileID: 3086293200253757409} - component: {fileID: 7528764990365051674} - component: {fileID: 3421159559893464927} + - component: {fileID: -8077891763218709486} m_Layer: 12 m_Name: ResourceBlock m_TagString: Untagged @@ -154,4 +155,23 @@ MonoBehaviour: m_EditorClassIdentifier: Assembly-CSharp::MineableBlock ShowTopMostFoldoutHeaderGroup: 1 maxHp: 100 - breakEffectPrefab: {fileID: 0} + shakeDuration: 0.1 + shakeMagnitude: 0.1 +--- !u!114 &-8077891763218709486 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 989066657509100432} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5fea29bb7c508c244a1f805a5fd3fc4d, type: 3} + m_Name: + m_EditorClassIdentifier: Assembly-CSharp::Outline + outlineMode: 0 + outlineColor: {r: 1, g: 1, b: 1, a: 1} + outlineWidth: 5 + precomputeOutline: 0 + bakeKeys: [] + bakeValues: [] diff --git a/Assets/QuickOutline.meta b/Assets/QuickOutline.meta new file mode 100644 index 0000000..875dc8b --- /dev/null +++ b/Assets/QuickOutline.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b3746f64adf554a4686d8e6f43b1af27 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/QuickOutline/Readme.txt b/Assets/QuickOutline/Readme.txt new file mode 100644 index 0000000..183ae24 --- /dev/null +++ b/Assets/QuickOutline/Readme.txt @@ -0,0 +1,37 @@ +Quick Outline +============= + +Developed by Chris Nolet (c) 2018 + + +Instructions +------------ + +To add an outline to an object, drag-and-drop the Outline.cs +script onto the object. The outline materials will be loaded +at runtime. + +You can also add outlines programmatically with: + + var outline = gameObject.AddComponent(); + + outline.OutlineMode = Outline.Mode.OutlineAll; + outline.OutlineColor = Color.yellow; + outline.OutlineWidth = 5f; + +The outline script does a small amount of work in Awake(). +For best results, use outline.enabled to toggle the outline. +Avoid removing and re-adding the component if possible. + +For large meshes, you may also like to enable 'Precompute +Outline' in the editor. This will reduce the amount of work +performed in Awake(). + + +Troubleshooting +--------------- + +If the outline appears off-center, please try the following: + +1. Set 'Read/Write Enabled' on each model's import settings. +2. Disable 'Optimize Mesh Data' in the player settings. diff --git a/Assets/QuickOutline/Readme.txt.meta b/Assets/QuickOutline/Readme.txt.meta new file mode 100644 index 0000000..c3f61b9 --- /dev/null +++ b/Assets/QuickOutline/Readme.txt.meta @@ -0,0 +1,16 @@ +fileFormatVersion: 2 +guid: 5933bfd39d7a5b843a0ed821f85bca19 +timeCreated: 1522619008 +licenseType: Store +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 115488 + packageName: Quick Outline + packageVersion: 1.1 + assetPath: Assets/QuickOutline/Readme.txt + uploadId: 485303 diff --git a/Assets/QuickOutline/Resources.meta b/Assets/QuickOutline/Resources.meta new file mode 100644 index 0000000..6135a95 --- /dev/null +++ b/Assets/QuickOutline/Resources.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 70fd40674751a8042a8b9b2e8d9f915f +folderAsset: yes +timeCreated: 1522559128 +licenseType: Store +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/QuickOutline/Resources/Materials.meta b/Assets/QuickOutline/Resources/Materials.meta new file mode 100644 index 0000000..2508b0f --- /dev/null +++ b/Assets/QuickOutline/Resources/Materials.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 80ac8e52d3c31a94babd161e86bc6b97 +folderAsset: yes +timeCreated: 1522559139 +licenseType: Store +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/QuickOutline/Resources/Materials/OutlineFill.mat b/Assets/QuickOutline/Resources/Materials/OutlineFill.mat new file mode 100644 index 0000000..cb02164 --- /dev/null +++ b/Assets/QuickOutline/Resources/Materials/OutlineFill.mat @@ -0,0 +1,25 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 6 + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_Name: OutlineFill + m_Shader: {fileID: 4800000, guid: 4e76d4023d7e0411297c670f878973e2, type: 3} + m_ShaderKeywords: + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: {} + disabledShaderPasses: [] + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: [] + m_Floats: + - _OutlineWidth: 2 + - _ZTest: 8 + m_Colors: + - _OutlineColor: {r: 1, g: 1, b: 1, a: 1} diff --git a/Assets/QuickOutline/Resources/Materials/OutlineFill.mat.meta b/Assets/QuickOutline/Resources/Materials/OutlineFill.mat.meta new file mode 100644 index 0000000..5576b45 --- /dev/null +++ b/Assets/QuickOutline/Resources/Materials/OutlineFill.mat.meta @@ -0,0 +1,17 @@ +fileFormatVersion: 2 +guid: 311313efa011949e98b6761d652ad13c +timeCreated: 1520576285 +licenseType: Store +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 115488 + packageName: Quick Outline + packageVersion: 1.1 + assetPath: Assets/QuickOutline/Resources/Materials/OutlineFill.mat + uploadId: 485303 diff --git a/Assets/QuickOutline/Resources/Materials/OutlineMask.mat b/Assets/QuickOutline/Resources/Materials/OutlineMask.mat new file mode 100644 index 0000000..80d49fa --- /dev/null +++ b/Assets/QuickOutline/Resources/Materials/OutlineMask.mat @@ -0,0 +1,23 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 6 + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_Name: OutlineMask + m_Shader: {fileID: 4800000, guid: 341b058cd7dee4f5cba5cc59a513619e, type: 3} + m_ShaderKeywords: + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: {} + disabledShaderPasses: [] + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: [] + m_Floats: + - _ZTest: 8 + m_Colors: [] diff --git a/Assets/QuickOutline/Resources/Materials/OutlineMask.mat.meta b/Assets/QuickOutline/Resources/Materials/OutlineMask.mat.meta new file mode 100644 index 0000000..8ad0794 --- /dev/null +++ b/Assets/QuickOutline/Resources/Materials/OutlineMask.mat.meta @@ -0,0 +1,17 @@ +fileFormatVersion: 2 +guid: 106f3ff43a17d4967a2b64c7a92e49ec +timeCreated: 1520576276 +licenseType: Store +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 115488 + packageName: Quick Outline + packageVersion: 1.1 + assetPath: Assets/QuickOutline/Resources/Materials/OutlineMask.mat + uploadId: 485303 diff --git a/Assets/QuickOutline/Resources/Shaders.meta b/Assets/QuickOutline/Resources/Shaders.meta new file mode 100644 index 0000000..91118d5 --- /dev/null +++ b/Assets/QuickOutline/Resources/Shaders.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 6a63caa2b0e993043a42c11f35ff2d1a +folderAsset: yes +timeCreated: 1522559134 +licenseType: Store +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/QuickOutline/Resources/Shaders/OutlineFill.shader b/Assets/QuickOutline/Resources/Shaders/OutlineFill.shader new file mode 100644 index 0000000..f546473 --- /dev/null +++ b/Assets/QuickOutline/Resources/Shaders/OutlineFill.shader @@ -0,0 +1,81 @@ +// +// OutlineFill.shader +// QuickOutline +// +// Created by Chris Nolet on 2/21/18. +// Copyright © 2018 Chris Nolet. All rights reserved. +// + +Shader "Custom/Outline Fill" { + Properties { + [Enum(UnityEngine.Rendering.CompareFunction)] _ZTest("ZTest", Float) = 0 + + _OutlineColor("Outline Color", Color) = (1, 1, 1, 1) + _OutlineWidth("Outline Width", Range(0, 10)) = 2 + } + + SubShader { + Tags { + "Queue" = "Transparent+110" + "RenderType" = "Transparent" + "DisableBatching" = "True" + } + + Pass { + Name "Fill" + Cull Off + ZTest [_ZTest] + ZWrite Off + Blend SrcAlpha OneMinusSrcAlpha + ColorMask RGB + + Stencil { + Ref 1 + Comp NotEqual + } + + CGPROGRAM + #include "UnityCG.cginc" + + #pragma vertex vert + #pragma fragment frag + + struct appdata { + float4 vertex : POSITION; + float3 normal : NORMAL; + float3 smoothNormal : TEXCOORD3; + UNITY_VERTEX_INPUT_INSTANCE_ID + }; + + struct v2f { + float4 position : SV_POSITION; + fixed4 color : COLOR; + UNITY_VERTEX_OUTPUT_STEREO + }; + + uniform fixed4 _OutlineColor; + uniform float _OutlineWidth; + + v2f vert(appdata input) { + v2f output; + + UNITY_SETUP_INSTANCE_ID(input); + UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output); + + float3 normal = any(input.smoothNormal) ? input.smoothNormal : input.normal; + float3 viewPosition = UnityObjectToViewPos(input.vertex); + float3 viewNormal = normalize(mul((float3x3)UNITY_MATRIX_IT_MV, normal)); + + output.position = UnityViewToClipPos(viewPosition + viewNormal * -viewPosition.z * _OutlineWidth / 1000.0); + output.color = _OutlineColor; + + return output; + } + + fixed4 frag(v2f input) : SV_Target { + return input.color; + } + ENDCG + } + } +} diff --git a/Assets/QuickOutline/Resources/Shaders/OutlineFill.shader.meta b/Assets/QuickOutline/Resources/Shaders/OutlineFill.shader.meta new file mode 100644 index 0000000..b982c4e --- /dev/null +++ b/Assets/QuickOutline/Resources/Shaders/OutlineFill.shader.meta @@ -0,0 +1,17 @@ +fileFormatVersion: 2 +guid: 4e76d4023d7e0411297c670f878973e2 +timeCreated: 1520575782 +licenseType: Store +ShaderImporter: + externalObjects: {} + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 115488 + packageName: Quick Outline + packageVersion: 1.1 + assetPath: Assets/QuickOutline/Resources/Shaders/OutlineFill.shader + uploadId: 485303 diff --git a/Assets/QuickOutline/Resources/Shaders/OutlineMask.shader b/Assets/QuickOutline/Resources/Shaders/OutlineMask.shader new file mode 100644 index 0000000..530d8c0 --- /dev/null +++ b/Assets/QuickOutline/Resources/Shaders/OutlineMask.shader @@ -0,0 +1,33 @@ +// +// OutlineMask.shader +// QuickOutline +// +// Created by Chris Nolet on 2/21/18. +// Copyright © 2018 Chris Nolet. All rights reserved. +// + +Shader "Custom/Outline Mask" { + Properties { + [Enum(UnityEngine.Rendering.CompareFunction)] _ZTest("ZTest", Float) = 0 + } + + SubShader { + Tags { + "Queue" = "Transparent+100" + "RenderType" = "Transparent" + } + + Pass { + Name "Mask" + Cull Off + ZTest [_ZTest] + ZWrite Off + ColorMask 0 + + Stencil { + Ref 1 + Pass Replace + } + } + } +} diff --git a/Assets/QuickOutline/Resources/Shaders/OutlineMask.shader.meta b/Assets/QuickOutline/Resources/Shaders/OutlineMask.shader.meta new file mode 100644 index 0000000..a20bfde --- /dev/null +++ b/Assets/QuickOutline/Resources/Shaders/OutlineMask.shader.meta @@ -0,0 +1,17 @@ +fileFormatVersion: 2 +guid: 341b058cd7dee4f5cba5cc59a513619e +timeCreated: 1520575773 +licenseType: Store +ShaderImporter: + externalObjects: {} + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 115488 + packageName: Quick Outline + packageVersion: 1.1 + assetPath: Assets/QuickOutline/Resources/Shaders/OutlineMask.shader + uploadId: 485303 diff --git a/Assets/QuickOutline/Samples.meta b/Assets/QuickOutline/Samples.meta new file mode 100644 index 0000000..7d6c23d --- /dev/null +++ b/Assets/QuickOutline/Samples.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 932f8193e5396db4babac4756c406dee +folderAsset: yes +timeCreated: 1522559213 +licenseType: Store +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/QuickOutline/Samples/Materials.meta b/Assets/QuickOutline/Samples/Materials.meta new file mode 100644 index 0000000..cb14819 --- /dev/null +++ b/Assets/QuickOutline/Samples/Materials.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 2b0040b0ed7fbd64693e9195d13d25f9 +folderAsset: yes +timeCreated: 1522615600 +licenseType: Store +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/QuickOutline/Samples/Materials/Plane.mat b/Assets/QuickOutline/Samples/Materials/Plane.mat new file mode 100644 index 0000000..06fa1aa --- /dev/null +++ b/Assets/QuickOutline/Samples/Materials/Plane.mat @@ -0,0 +1,76 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 6 + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_Name: Plane + m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} + m_ShaderKeywords: + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: {} + disabledShaderPasses: [] + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Floats: + - _BumpScale: 1 + - _Cutoff: 0.5 + - _DetailNormalMapScale: 1 + - _DstBlend: 0 + - _GlossMapScale: 1 + - _Glossiness: 0.5 + - _GlossyReflections: 1 + - _Metallic: 1 + - _Mode: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 1 + - _SrcBlend: 1 + - _UVSec: 0 + - _ZWrite: 1 + m_Colors: + - _Color: {r: 0.2509804, g: 0.2509804, b: 0.5019608, a: 1} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} diff --git a/Assets/QuickOutline/Samples/Materials/Plane.mat.meta b/Assets/QuickOutline/Samples/Materials/Plane.mat.meta new file mode 100644 index 0000000..64e3c3c --- /dev/null +++ b/Assets/QuickOutline/Samples/Materials/Plane.mat.meta @@ -0,0 +1,17 @@ +fileFormatVersion: 2 +guid: f58cf65ea995c4b45be95713bdea8134 +timeCreated: 1522540975 +licenseType: Store +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 115488 + packageName: Quick Outline + packageVersion: 1.1 + assetPath: Assets/QuickOutline/Samples/Materials/Plane.mat + uploadId: 485303 diff --git a/Assets/QuickOutline/Samples/Scenes.meta b/Assets/QuickOutline/Samples/Scenes.meta new file mode 100644 index 0000000..7f5c774 --- /dev/null +++ b/Assets/QuickOutline/Samples/Scenes.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 3916faa55c6a94248959031ee0ad499f +folderAsset: yes +timeCreated: 1522615614 +licenseType: Store +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/QuickOutline/Samples/Scenes/QuickOutline.unity b/Assets/QuickOutline/Samples/Scenes/QuickOutline.unity new file mode 100644 index 0000000..33911b7 --- /dev/null +++ b/Assets/QuickOutline/Samples/Scenes/QuickOutline.unity @@ -0,0 +1,778 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 8 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} + m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} + m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 0 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 0 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 820273532} + m_IndirectSpecularColor: {r: 0.18028383, g: 0.22571409, b: 0.30692282, a: 1} +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 9 + m_GIWorkflowMode: 0 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_TemporalCoherenceThreshold: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 1 + m_EnableRealtimeLightmaps: 1 + m_LightmapEditorSettings: + serializedVersion: 8 + m_Resolution: 2 + m_BakeResolution: 40 + m_TextureWidth: 1024 + m_TextureHeight: 1024 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 1 + m_FinalGather: 0 + m_FinalGatherFiltering: 1 + m_FinalGatherRayCount: 256 + m_ReflectionCompression: 2 + m_MixedBakeMode: 3 + m_BakeBackend: 0 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 500 + m_PVRBounces: 2 + m_PVRFiltering: 0 + m_PVRFilteringMode: 1 + m_PVRCulling: 1 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 5 + m_PVRFilteringGaussRadiusAO: 2 + m_PVRFilteringAtrousColorSigma: 1 + m_PVRFilteringAtrousNormalSigma: 1 + m_PVRFilteringAtrousPositionSigma: 1 + m_LightingDataAsset: {fileID: 0} + m_ShadowMaskMode: 2 +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 2 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + accuratePlacement: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &122269556 +GameObject: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + serializedVersion: 5 + m_Component: + - component: {fileID: 122269561} + - component: {fileID: 122269560} + - component: {fileID: 122269558} + - component: {fileID: 122269557} + m_Layer: 0 + m_Name: Main Camera + m_TagString: MainCamera + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!81 &122269557 +AudioListener: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 122269556} + m_Enabled: 1 +--- !u!124 &122269558 +Behaviour: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 122269556} + m_Enabled: 1 +--- !u!20 &122269560 +Camera: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 122269556} + m_Enabled: 1 + serializedVersion: 2 + m_ClearFlags: 1 + m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0} + m_NormalizedViewPortRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + near clip plane: 0.3 + far clip plane: 1000 + field of view: 60 + orthographic: 0 + orthographic size: 5 + m_Depth: -1 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingPath: -1 + m_TargetTexture: {fileID: 0} + m_TargetDisplay: 0 + m_TargetEye: 3 + m_HDR: 1 + m_AllowMSAA: 1 + m_ForceIntoRT: 0 + m_OcclusionCulling: 1 + m_StereoConvergence: 10 + m_StereoSeparation: 0.022 + m_StereoMirrorMode: 0 +--- !u!4 &122269561 +Transform: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 122269556} + m_LocalRotation: {x: 0.3420201, y: 0, z: 0, w: 0.9396927} + m_LocalPosition: {x: 0, y: 3, z: -4} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 40, y: 0, z: 0} +--- !u!1 &124162633 +GameObject: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + serializedVersion: 5 + m_Component: + - component: {fileID: 124162634} + - component: {fileID: 124162638} + - component: {fileID: 124162636} + - component: {fileID: 124162635} + m_Layer: 0 + m_Name: Outline Hidden + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &124162634 +Transform: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 124162633} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: -2, y: 0, z: 0} + m_LocalScale: {x: 1, y: 0.5, z: 1} + m_Children: [] + m_Father: {fileID: 935070115} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &124162635 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 124162633} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5fea29bb7c508c244a1f805a5fd3fc4d, type: 3} + m_Name: + m_EditorClassIdentifier: + outlineMode: 2 + outlineColor: {r: 1, g: 0.2509804, b: 0.2509804, a: 1} + outlineWidth: 6 +--- !u!23 &124162636 +MeshRenderer: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 124162633} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_Materials: + - {fileID: 10303, guid: 0000000000000000f000000000000000, type: 0} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_PreserveUVs: 1 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!33 &124162638 +MeshFilter: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 124162633} + m_Mesh: {fileID: 10206, guid: 0000000000000000e000000000000000, type: 0} +--- !u!1 &796971894 +GameObject: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + serializedVersion: 5 + m_Component: + - component: {fileID: 796971895} + - component: {fileID: 796971899} + - component: {fileID: 796971897} + - component: {fileID: 796971896} + m_Layer: 0 + m_Name: Outline And Silhouette + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &796971895 +Transform: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 796971894} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 2, y: 0, z: 0} + m_LocalScale: {x: 1, y: 0.5, z: 1} + m_Children: [] + m_Father: {fileID: 935070115} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &796971896 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 796971894} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5fea29bb7c508c244a1f805a5fd3fc4d, type: 3} + m_Name: + m_EditorClassIdentifier: + outlineMode: 3 + outlineColor: {r: 0.2509804, g: 1, b: 1, a: 1} + outlineWidth: 6 +--- !u!23 &796971897 +MeshRenderer: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 796971894} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_Materials: + - {fileID: 10303, guid: 0000000000000000f000000000000000, type: 0} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_PreserveUVs: 1 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!33 &796971899 +MeshFilter: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 796971894} + m_Mesh: {fileID: 10206, guid: 0000000000000000e000000000000000, type: 0} +--- !u!1 &820273531 +GameObject: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + serializedVersion: 5 + m_Component: + - component: {fileID: 820273533} + - component: {fileID: 820273532} + m_Layer: 0 + m_Name: Directional Light + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!108 &820273532 +Light: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 820273531} + m_Enabled: 1 + serializedVersion: 8 + m_Type: 1 + m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1} + m_Intensity: 1 + m_Range: 10 + m_SpotAngle: 30 + m_CookieSize: 10 + m_Shadows: + m_Type: 2 + m_Resolution: -1 + m_CustomResolution: -1 + m_Strength: 1 + m_Bias: 0.05 + m_NormalBias: 0.4 + m_NearPlane: 0.2 + m_Cookie: {fileID: 0} + m_DrawHalo: 0 + m_Flare: {fileID: 0} + m_RenderMode: 0 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_Lightmapping: 4 + m_AreaSize: {x: 1, y: 1} + m_BounceIntensity: 1 + m_ColorTemperature: 6570 + m_UseColorTemperature: 0 + m_ShadowRadius: 0 + m_ShadowAngle: 0 +--- !u!4 &820273533 +Transform: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 820273531} + m_LocalRotation: {x: 0.40821788, y: 0.23456976, z: -0.10938167, w: 0.8754261} + m_LocalPosition: {x: 0, y: 3, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 50, y: 30, z: 0} +--- !u!1 &935070114 +GameObject: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + serializedVersion: 5 + m_Component: + - component: {fileID: 935070115} + m_Layer: 0 + m_Name: Outlined Objects + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &935070115 +Transform: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 935070114} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1781008194} + - {fileID: 124162634} + - {fileID: 1346396411} + - {fileID: 796971895} + - {fileID: 1083549395} + m_Father: {fileID: 0} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1083549394 +GameObject: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + serializedVersion: 5 + m_Component: + - component: {fileID: 1083549395} + - component: {fileID: 1083549399} + - component: {fileID: 1083549397} + - component: {fileID: 1083549396} + m_Layer: 0 + m_Name: Outline Visible + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1083549395 +Transform: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 1083549394} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 4, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 935070115} + m_RootOrder: 4 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &1083549396 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 1083549394} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5fea29bb7c508c244a1f805a5fd3fc4d, type: 3} + m_Name: + m_EditorClassIdentifier: + outlineMode: 1 + outlineColor: {r: 0.2509804, g: 1, b: 0.2509804, a: 1} + outlineWidth: 6 +--- !u!23 &1083549397 +MeshRenderer: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 1083549394} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_Materials: + - {fileID: 10303, guid: 0000000000000000f000000000000000, type: 0} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_PreserveUVs: 1 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!33 &1083549399 +MeshFilter: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 1083549394} + m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0} +--- !u!1 &1346396410 +GameObject: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + serializedVersion: 5 + m_Component: + - component: {fileID: 1346396411} + - component: {fileID: 1346396415} + - component: {fileID: 1346396413} + - component: {fileID: 1346396412} + m_Layer: 0 + m_Name: Outline All + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1346396411 +Transform: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 1346396410} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 935070115} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &1346396412 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 1346396410} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5fea29bb7c508c244a1f805a5fd3fc4d, type: 3} + m_Name: + m_EditorClassIdentifier: + outlineMode: 0 + outlineColor: {r: 1, g: 1, b: 0.2509804, a: 1} + outlineWidth: 6 +--- !u!23 &1346396413 +MeshRenderer: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 1346396410} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_Materials: + - {fileID: 10303, guid: 0000000000000000f000000000000000, type: 0} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_PreserveUVs: 1 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!33 &1346396415 +MeshFilter: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 1346396410} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!1 &1580478821 +GameObject: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + serializedVersion: 5 + m_Component: + - component: {fileID: 1580478825} + - component: {fileID: 1580478824} + - component: {fileID: 1580478822} + m_Layer: 0 + m_Name: Plane + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!23 &1580478822 +MeshRenderer: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 1580478821} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_Materials: + - {fileID: 2100000, guid: f58cf65ea995c4b45be95713bdea8134, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_PreserveUVs: 1 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!33 &1580478824 +MeshFilter: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 1580478821} + m_Mesh: {fileID: 10209, guid: 0000000000000000e000000000000000, type: 0} +--- !u!4 &1580478825 +Transform: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 1580478821} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 10, y: 1, z: 10} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1781008193 +GameObject: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + serializedVersion: 5 + m_Component: + - component: {fileID: 1781008194} + - component: {fileID: 1781008198} + - component: {fileID: 1781008196} + - component: {fileID: 1781008195} + m_Layer: 0 + m_Name: Silhouette Only + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1781008194 +Transform: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 1781008193} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: -4, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 935070115} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &1781008195 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 1781008193} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5fea29bb7c508c244a1f805a5fd3fc4d, type: 3} + m_Name: + m_EditorClassIdentifier: + outlineMode: 4 + outlineColor: {r: 1, g: 1, b: 1, a: 1} + outlineWidth: 6 +--- !u!23 &1781008196 +MeshRenderer: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 1781008193} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_Materials: + - {fileID: 10303, guid: 0000000000000000f000000000000000, type: 0} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_PreserveUVs: 1 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!33 &1781008198 +MeshFilter: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 1781008193} + m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0} diff --git a/Assets/QuickOutline/Samples/Scenes/QuickOutline.unity.meta b/Assets/QuickOutline/Samples/Scenes/QuickOutline.unity.meta new file mode 100644 index 0000000..f1107a5 --- /dev/null +++ b/Assets/QuickOutline/Samples/Scenes/QuickOutline.unity.meta @@ -0,0 +1,16 @@ +fileFormatVersion: 2 +guid: f23712c79adc910408e872b127e825cf +timeCreated: 1522615825 +licenseType: Store +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 115488 + packageName: Quick Outline + packageVersion: 1.1 + assetPath: Assets/QuickOutline/Samples/Scenes/QuickOutline.unity + uploadId: 485303 diff --git a/Assets/QuickOutline/Scripts.meta b/Assets/QuickOutline/Scripts.meta new file mode 100644 index 0000000..2f7793d --- /dev/null +++ b/Assets/QuickOutline/Scripts.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 3ddbd65d69a9f0b48bab4fe96a1fe099 +folderAsset: yes +timeCreated: 1522559122 +licenseType: Store +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/QuickOutline/Scripts/Outline.cs b/Assets/QuickOutline/Scripts/Outline.cs new file mode 100644 index 0000000..26d8788 --- /dev/null +++ b/Assets/QuickOutline/Scripts/Outline.cs @@ -0,0 +1,309 @@ +// +// Outline.cs +// QuickOutline +// +// Created by Chris Nolet on 3/30/18. +// Copyright © 2018 Chris Nolet. All rights reserved. +// + +using System; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; + +[DisallowMultipleComponent] + +public class Outline : MonoBehaviour { + private static HashSet registeredMeshes = new HashSet(); + + public enum Mode { + OutlineAll, + OutlineVisible, + OutlineHidden, + OutlineAndSilhouette, + SilhouetteOnly + } + + public Mode OutlineMode { + get { return outlineMode; } + set { + outlineMode = value; + needsUpdate = true; + } + } + + public Color OutlineColor { + get { return outlineColor; } + set { + outlineColor = value; + needsUpdate = true; + } + } + + public float OutlineWidth { + get { return outlineWidth; } + set { + outlineWidth = value; + needsUpdate = true; + } + } + + [Serializable] + private class ListVector3 { + public List data; + } + + [SerializeField] + private Mode outlineMode; + + [SerializeField] + private Color outlineColor = Color.white; + + [SerializeField, Range(0f, 10f)] + private float outlineWidth = 2f; + + [Header("Optional")] + + [SerializeField, Tooltip("Precompute enabled: Per-vertex calculations are performed in the editor and serialized with the object. " + + "Precompute disabled: Per-vertex calculations are performed at runtime in Awake(). This may cause a pause for large meshes.")] + private bool precomputeOutline; + + [SerializeField, HideInInspector] + private List bakeKeys = new List(); + + [SerializeField, HideInInspector] + private List bakeValues = new List(); + + private Renderer[] renderers; + private Material outlineMaskMaterial; + private Material outlineFillMaterial; + + private bool needsUpdate; + + void Awake() { + + // Cache renderers + renderers = GetComponentsInChildren(); + + // Instantiate outline materials + outlineMaskMaterial = Instantiate(Resources.Load(@"Materials/OutlineMask")); + outlineFillMaterial = Instantiate(Resources.Load(@"Materials/OutlineFill")); + + outlineMaskMaterial.name = "OutlineMask (Instance)"; + outlineFillMaterial.name = "OutlineFill (Instance)"; + + // Retrieve or generate smooth normals + LoadSmoothNormals(); + + // Apply material properties immediately + needsUpdate = true; + } + + void OnEnable() { + foreach (var renderer in renderers) { + + // Append outline shaders + var materials = renderer.sharedMaterials.ToList(); + + materials.Add(outlineMaskMaterial); + materials.Add(outlineFillMaterial); + + renderer.materials = materials.ToArray(); + } + } + + void OnValidate() { + + // Update material properties + needsUpdate = true; + + // Clear cache when baking is disabled or corrupted + if (!precomputeOutline && bakeKeys.Count != 0 || bakeKeys.Count != bakeValues.Count) { + bakeKeys.Clear(); + bakeValues.Clear(); + } + + // Generate smooth normals when baking is enabled + if (precomputeOutline && bakeKeys.Count == 0) { + Bake(); + } + } + + void Update() { + if (needsUpdate) { + needsUpdate = false; + + UpdateMaterialProperties(); + } + } + + void OnDisable() { + foreach (var renderer in renderers) { + + // Remove outline shaders + var materials = renderer.sharedMaterials.ToList(); + + materials.Remove(outlineMaskMaterial); + materials.Remove(outlineFillMaterial); + + renderer.materials = materials.ToArray(); + } + } + + void OnDestroy() { + + // Destroy material instances + Destroy(outlineMaskMaterial); + Destroy(outlineFillMaterial); + } + + void Bake() { + + // Generate smooth normals for each mesh + var bakedMeshes = new HashSet(); + + foreach (var meshFilter in GetComponentsInChildren()) { + + // Skip duplicates + if (!bakedMeshes.Add(meshFilter.sharedMesh)) { + continue; + } + + // Serialize smooth normals + var smoothNormals = SmoothNormals(meshFilter.sharedMesh); + + bakeKeys.Add(meshFilter.sharedMesh); + bakeValues.Add(new ListVector3() { data = smoothNormals }); + } + } + + void LoadSmoothNormals() { + + // Retrieve or generate smooth normals + foreach (var meshFilter in GetComponentsInChildren()) { + + // Skip if smooth normals have already been adopted + if (!registeredMeshes.Add(meshFilter.sharedMesh)) { + continue; + } + + // Retrieve or generate smooth normals + var index = bakeKeys.IndexOf(meshFilter.sharedMesh); + var smoothNormals = (index >= 0) ? bakeValues[index].data : SmoothNormals(meshFilter.sharedMesh); + + // Store smooth normals in UV3 + meshFilter.sharedMesh.SetUVs(3, smoothNormals); + + // Combine submeshes + var renderer = meshFilter.GetComponent(); + + if (renderer != null) { + CombineSubmeshes(meshFilter.sharedMesh, renderer.sharedMaterials); + } + } + + // Clear UV3 on skinned mesh renderers + foreach (var skinnedMeshRenderer in GetComponentsInChildren()) { + + // Skip if UV3 has already been reset + if (!registeredMeshes.Add(skinnedMeshRenderer.sharedMesh)) { + continue; + } + + // Clear UV3 + skinnedMeshRenderer.sharedMesh.uv4 = new Vector2[skinnedMeshRenderer.sharedMesh.vertexCount]; + + // Combine submeshes + CombineSubmeshes(skinnedMeshRenderer.sharedMesh, skinnedMeshRenderer.sharedMaterials); + } + } + + List SmoothNormals(Mesh mesh) { + + // Group vertices by location + var groups = mesh.vertices.Select((vertex, index) => new KeyValuePair(vertex, index)).GroupBy(pair => pair.Key); + + // Copy normals to a new list + var smoothNormals = new List(mesh.normals); + + // Average normals for grouped vertices + foreach (var group in groups) { + + // Skip single vertices + if (group.Count() == 1) { + continue; + } + + // Calculate the average normal + var smoothNormal = Vector3.zero; + + foreach (var pair in group) { + smoothNormal += smoothNormals[pair.Value]; + } + + smoothNormal.Normalize(); + + // Assign smooth normal to each vertex + foreach (var pair in group) { + smoothNormals[pair.Value] = smoothNormal; + } + } + + return smoothNormals; + } + + void CombineSubmeshes(Mesh mesh, Material[] materials) { + + // Skip meshes with a single submesh + if (mesh.subMeshCount == 1) { + return; + } + + // Skip if submesh count exceeds material count + if (mesh.subMeshCount > materials.Length) { + return; + } + + // Append combined submesh + mesh.subMeshCount++; + mesh.SetTriangles(mesh.triangles, mesh.subMeshCount - 1); + } + + void UpdateMaterialProperties() { + + // Apply properties according to mode + outlineFillMaterial.SetColor("_OutlineColor", outlineColor); + + switch (outlineMode) { + case Mode.OutlineAll: + outlineMaskMaterial.SetFloat("_ZTest", (float)UnityEngine.Rendering.CompareFunction.Always); + outlineFillMaterial.SetFloat("_ZTest", (float)UnityEngine.Rendering.CompareFunction.Always); + outlineFillMaterial.SetFloat("_OutlineWidth", outlineWidth); + break; + + case Mode.OutlineVisible: + outlineMaskMaterial.SetFloat("_ZTest", (float)UnityEngine.Rendering.CompareFunction.Always); + outlineFillMaterial.SetFloat("_ZTest", (float)UnityEngine.Rendering.CompareFunction.LessEqual); + outlineFillMaterial.SetFloat("_OutlineWidth", outlineWidth); + break; + + case Mode.OutlineHidden: + outlineMaskMaterial.SetFloat("_ZTest", (float)UnityEngine.Rendering.CompareFunction.Always); + outlineFillMaterial.SetFloat("_ZTest", (float)UnityEngine.Rendering.CompareFunction.Greater); + outlineFillMaterial.SetFloat("_OutlineWidth", outlineWidth); + break; + + case Mode.OutlineAndSilhouette: + outlineMaskMaterial.SetFloat("_ZTest", (float)UnityEngine.Rendering.CompareFunction.LessEqual); + outlineFillMaterial.SetFloat("_ZTest", (float)UnityEngine.Rendering.CompareFunction.Always); + outlineFillMaterial.SetFloat("_OutlineWidth", outlineWidth); + break; + + case Mode.SilhouetteOnly: + outlineMaskMaterial.SetFloat("_ZTest", (float)UnityEngine.Rendering.CompareFunction.LessEqual); + outlineFillMaterial.SetFloat("_ZTest", (float)UnityEngine.Rendering.CompareFunction.Greater); + outlineFillMaterial.SetFloat("_OutlineWidth", 0f); + break; + } + } +} diff --git a/Assets/QuickOutline/Scripts/Outline.cs.meta b/Assets/QuickOutline/Scripts/Outline.cs.meta new file mode 100644 index 0000000..3c3932c --- /dev/null +++ b/Assets/QuickOutline/Scripts/Outline.cs.meta @@ -0,0 +1,20 @@ +fileFormatVersion: 2 +guid: 5fea29bb7c508c244a1f805a5fd3fc4d +timeCreated: 1522369084 +licenseType: Store +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 115488 + packageName: Quick Outline + packageVersion: 1.1 + assetPath: Assets/QuickOutline/Scripts/Outline.cs + uploadId: 485303 diff --git a/Assets/Scenes/DefenceScene.unity b/Assets/Scenes/DefenceScene.unity index a2a9836..d8c7ce2 100644 --- a/Assets/Scenes/DefenceScene.unity +++ b/Assets/Scenes/DefenceScene.unity @@ -128,7 +128,7 @@ GameObject: serializedVersion: 6 m_Component: - component: {fileID: 14847856} - m_Layer: 0 + m_Layer: 7 m_Name: Wall m_TagString: Untagged m_Icon: {fileID: 0} @@ -143,7 +143,7 @@ Transform: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 14847855} serializedVersion: 2 - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 @@ -154,7 +154,7 @@ Transform: - {fileID: 1044242051} - {fileID: 1365372345} - {fileID: 1095978103} - m_Father: {fileID: 0} + m_Father: {fileID: 743367988} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &59717880 GameObject: @@ -781,6 +781,37 @@ MonoBehaviour: AutoObjectParentSync: 1 SyncOwnerTransformWhenParented: 1 AllowOwnerToParent: 0 +--- !u!1 &437093201 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 437093202} + m_Layer: 0 + m_Name: GameObject + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &437093202 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 437093201} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 674.5743, y: -0.00002, z: 317.503} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &445606021 stripped GameObject: m_CorrespondingSourceObject: {fileID: 6403733529880835406, guid: 443aa97110814434cb36b26656f1884c, type: 3} @@ -942,7 +973,7 @@ Transform: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 556982642} serializedVersion: 2 - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 10} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 @@ -972,7 +1003,7 @@ MonoBehaviour: m_DisconnectTimeoutMS: 30000 ConnectionData: Address: 127.0.0.1 - Port: 7774 + Port: 7793 ServerListenAddress: 127.0.0.1 ClientBindPort: 0 DebugSimulator: @@ -1295,7 +1326,7 @@ GameObject: - component: {fileID: 707831777} - component: {fileID: 707831776} - component: {fileID: 707831775} - m_Layer: 0 + m_Layer: 7 m_Name: Wall2 (1) m_TagString: Untagged m_Icon: {fileID: 0} @@ -1430,6 +1461,7 @@ Transform: - {fileID: 2084947170} - {fileID: 1564162731} - {fileID: 545458833} + - {fileID: 14847856} m_Father: {fileID: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &789135791 @@ -1444,7 +1476,7 @@ GameObject: - component: {fileID: 789135795} - component: {fileID: 789135794} - component: {fileID: 789135793} - m_Layer: 0 + m_Layer: 7 m_Name: Wall1 m_TagString: Untagged m_Icon: {fileID: 0} @@ -1632,7 +1664,7 @@ GameObject: - component: {fileID: 1044242054} - component: {fileID: 1044242053} - component: {fileID: 1044242052} - m_Layer: 0 + m_Layer: 7 m_Name: Wall2 (2) m_TagString: Untagged m_Icon: {fileID: 0} @@ -1809,7 +1841,7 @@ GameObject: - component: {fileID: 1095978106} - component: {fileID: 1095978105} - component: {fileID: 1095978104} - m_Layer: 0 + m_Layer: 7 m_Name: "\uBC14\uB2E5" m_TagString: Untagged m_Icon: {fileID: 0} @@ -1909,6 +1941,81 @@ MeshFilter: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 1095978102} m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!1 &1202322935 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1202322936} + - component: {fileID: 1202322938} + - component: {fileID: 1202322937} + m_Layer: 5 + m_Name: Crosshair + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1202322936 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1202322935} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1409253547} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 50, y: 50} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1202322937 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1202322935} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.Image + m_Material: {fileID: 0} + m_Color: {r: 1, g: 0, b: 0, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 0} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1202322938 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1202322935} + m_CullTransparentMesh: 1 --- !u!1001 &1242393178 PrefabInstance: m_ObjectHideFlags: 0 @@ -2082,7 +2189,7 @@ GameObject: - component: {fileID: 1365372348} - component: {fileID: 1365372347} - component: {fileID: 1365372346} - m_Layer: 0 + m_Layer: 7 m_Name: "\uCC9C\uC7A5" m_TagString: Untagged m_Icon: {fileID: 0} @@ -2277,6 +2384,7 @@ RectTransform: m_ConstrainProportionsScale: 0 m_Children: - {fileID: 280147083} + - {fileID: 1202322936} m_Father: {fileID: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} @@ -2284,6 +2392,71 @@ RectTransform: m_AnchoredPosition: {x: 0, y: 0} m_SizeDelta: {x: 0, y: 0} m_Pivot: {x: 0, y: 0} +--- !u!1001 &1489230404 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + serializedVersion: 3 + m_TransformParent: {fileID: 0} + m_Modifications: + - target: {fileID: 989066657509100432, guid: 17532917e1ada23469c573abf64905f0, type: 3} + propertyPath: m_Name + value: ResourceBlock + objectReference: {fileID: 0} + - target: {fileID: 5902598773338262147, guid: 17532917e1ada23469c573abf64905f0, type: 3} + propertyPath: m_LocalPosition.x + value: -1.9 + objectReference: {fileID: 0} + - target: {fileID: 5902598773338262147, guid: 17532917e1ada23469c573abf64905f0, type: 3} + propertyPath: m_LocalPosition.y + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 5902598773338262147, guid: 17532917e1ada23469c573abf64905f0, type: 3} + propertyPath: m_LocalPosition.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5902598773338262147, guid: 17532917e1ada23469c573abf64905f0, type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 5902598773338262147, guid: 17532917e1ada23469c573abf64905f0, type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5902598773338262147, guid: 17532917e1ada23469c573abf64905f0, type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5902598773338262147, guid: 17532917e1ada23469c573abf64905f0, type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5902598773338262147, guid: 17532917e1ada23469c573abf64905f0, type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5902598773338262147, guid: 17532917e1ada23469c573abf64905f0, type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 5902598773338262147, guid: 17532917e1ada23469c573abf64905f0, type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7528764990365051674, guid: 17532917e1ada23469c573abf64905f0, type: 3} + propertyPath: GlobalObjectIdHash + value: 822699884 + objectReference: {fileID: 0} + - target: {fileID: 7528764990365051674, guid: 17532917e1ada23469c573abf64905f0, type: 3} + propertyPath: InScenePlacedSourceGlobalObjectIdHash + value: 1191681468 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_RemovedGameObjects: [] + m_AddedGameObjects: [] + m_AddedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: 17532917e1ada23469c573abf64905f0, type: 3} --- !u!1 &1558135260 GameObject: m_ObjectHideFlags: 0 @@ -2788,7 +2961,7 @@ GameObject: - component: {fileID: 1901817365} - component: {fileID: 1901817364} - component: {fileID: 1901817363} - m_Layer: 0 + m_Layer: 7 m_Name: Wall2 m_TagString: Untagged m_Icon: {fileID: 0} @@ -3158,6 +3331,50 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 2060458427} m_CullTransparentMesh: 1 +--- !u!1 &2067098342 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2067098344} + - component: {fileID: 2067098343} + m_Layer: 0 + m_Name: AutoHost + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &2067098343 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2067098342} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 158afddc7f1d50a42831c73d5e8dc87b, type: 3} + m_Name: + m_EditorClassIdentifier: Assembly-CSharp::AutoHost +--- !u!4 &2067098344 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2067098342} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 2.62671, y: -0.47193, z: -4} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!4 &2084947170 stripped Transform: m_CorrespondingSourceObject: {fileID: 2338240775821095493, guid: 1955bdf7dd2940f44aa117fbcf6eb626, type: 3} @@ -3284,6 +3501,8 @@ SceneRoots: - {fileID: 743367988} - {fileID: 670724422} - {fileID: 1409253547} - - {fileID: 14847856} - - {fileID: 556982644} - {fileID: 1634635645} + - {fileID: 437093202} + - {fileID: 1489230404} + - {fileID: 556982644} + - {fileID: 2067098344} diff --git a/Assets/Scripts/GameBase/AutoHost.cs b/Assets/Scripts/GameBase/AutoHost.cs new file mode 100644 index 0000000..8f51ca7 --- /dev/null +++ b/Assets/Scripts/GameBase/AutoHost.cs @@ -0,0 +1,26 @@ +using UnityEngine; +using Unity.Netcode; + +public class AutoHost : MonoBehaviour +{ + // 에디터에서만 작동하도록 설정 + void Start() + { +#if UNITY_EDITOR + // 1. NetworkManager가 씬에 존재하는지 확인 + if (NetworkManager.Singleton != null) + { + // 2. 이미 서버나 클라이언트가 실행 중이 아닐 때만 실행 + if (!NetworkManager.Singleton.IsServer && !NetworkManager.Singleton.IsClient) + { + NetworkManager.Singleton.StartHost(); + Debug.Log("[AutoHost] 에디터 전용 호스트 자동 시작됨"); + } + } + else + { + Debug.LogError("[AutoHost] NetworkManager를 찾을 수 없습니다!"); + } +#endif + } +} \ No newline at end of file diff --git a/Assets/Scripts/GameBase/AutoHost.cs.meta b/Assets/Scripts/GameBase/AutoHost.cs.meta new file mode 100644 index 0000000..6c88a2e --- /dev/null +++ b/Assets/Scripts/GameBase/AutoHost.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 158afddc7f1d50a42831c73d5e8dc87b \ No newline at end of file diff --git a/Assets/Scripts/MineableBlock.cs b/Assets/Scripts/MineableBlock.cs index 4c38a67..1378238 100644 --- a/Assets/Scripts/MineableBlock.cs +++ b/Assets/Scripts/MineableBlock.cs @@ -1,5 +1,6 @@ -using UnityEngine; using Unity.Netcode; +using UnityEngine; +using System.Collections; public class MineableBlock : NetworkBehaviour { @@ -8,8 +9,32 @@ public class MineableBlock : NetworkBehaviour // [동기화] 모든 플레이어가 동일한 블록 체력을 보게 함 private NetworkVariable _currentHp = new NetworkVariable(); + [Header("Visuals")] - [SerializeField] private GameObject breakEffectPrefab; // 파괴 시 파티클 + private Outline _outline; + private Vector3 _originalPos; + + [Header("Shake Settings")] + [SerializeField] private float shakeDuration = 0.15f; // 흔들리는 시간 + [SerializeField] private float shakeMagnitude = 0.1f; // 흔들리는 강도 + private Coroutine _shakeCoroutine; + + void Awake() + { + // 해당 오브젝트 혹은 자식에게서 Outline 컴포넌트를 찾습니다. + _outline = GetComponentInChildren(); + _originalPos = transform.localPosition; // 로컬 위치 저장 + + if (_outline != null) + { + // 게임 시작 시 하이라이트는 꺼둡니다. + _outline.enabled = false; + } + else + { + Debug.LogWarning($"{gameObject.name}: QuickOutline 에셋의 Outline 컴포넌트를 찾을 수 없습니다."); + } + } public override void OnNetworkSpawn() { @@ -35,19 +60,45 @@ public class MineableBlock : NetworkBehaviour private void DestroyBlock() { - // 1. 모든 클라이언트에게 파괴 이펙트 재생 요청 - PlayBreakEffectRpc(); - // 2. 서버에서 네트워크 오브젝트 제거 (모든 클라이언트에서 사라짐) GetComponent().Despawn(); } - [Rpc(SendTo.Everyone)] - private void PlayBreakEffectRpc() + // 하이라이트 상태를 설정하는 공개 메서드 + public void SetHighlight(bool isOn) { - if (breakEffectPrefab != null) + if (_outline == null) return; + + // 외곽선 컴포넌트 활성화/비활성화 + _outline.enabled = isOn; + } + + // 서버에서 호출하여 모든 클라이언트에게 흔들림 지시 + [ClientRpc] + public void PlayHitEffectClientRpc() + { + if (_shakeCoroutine != null) StopCoroutine(_shakeCoroutine); + _shakeCoroutine = StartCoroutine(ShakeRoutine()); + } + + private IEnumerator ShakeRoutine() + { + float elapsed = 0.0f; + Debug.Log("흔들림 코루틴 시작"); // 시작 확인 + + while (elapsed < shakeDuration) { - Instantiate(breakEffectPrefab, transform.position, Quaternion.identity); + Vector3 randomOffset = Random.insideUnitSphere * shakeMagnitude; + transform.localPosition = _originalPos + randomOffset; + + // 좌표가 실제로 바뀌고 있는지 로그 출력 + // Debug.Log($"현재 좌표: {transform.localPosition}"); + + elapsed += Time.deltaTime; + yield return null; } + + transform.localPosition = _originalPos; + Debug.Log("흔들림 코루틴 종료 및 위치 복구"); } } \ No newline at end of file diff --git a/Assets/Scripts/Player/PlayerNetworkController.cs b/Assets/Scripts/Player/PlayerNetworkController.cs index afb6d2f..2eec55f 100644 --- a/Assets/Scripts/Player/PlayerNetworkController.cs +++ b/Assets/Scripts/Player/PlayerNetworkController.cs @@ -21,9 +21,19 @@ public class PlayerNetworkController : NetworkBehaviour [SerializeField] private float buildSpeedMultiplier = 2f; [Header("Mining Settings")] - [SerializeField] private float attackRange = 1.5f; - [SerializeField] private int miningDamage = 25; + [SerializeField] private float attackRange = 3.5f; + [SerializeField] private float aimRadius = 0.5f; + [SerializeField] private int miningDamage = 50; [SerializeField] private LayerMask mineableLayer; + [SerializeField] private LayerMask ignoreDuringAim; // 반드시 'Player' 레이어를 포함하세요! + + [Header("Visual Feedback")] + [SerializeField] private float crosshairScreenRadius = 200f; + [SerializeField] private UnityEngine.UI.Image crosshairUI; + [SerializeField] private Sprite idleCrosshair; + [SerializeField] private Sprite targetCrosshair; + private RectTransform _crosshairRect; + private MineableBlock _currentTargetBlock; // 현재 강조 중인 블록 저장 private CharacterController _controller; private PlayerInputActions _inputActions; @@ -36,6 +46,12 @@ public class PlayerNetworkController : NetworkBehaviour private bool _isGrounded; private bool _isHoldingInteract = false; + // 디버그 변수 + private Vector3 _debugOrigin; + private Vector3 _debugDir; + private bool _debugHit; + private float _debugDist; + // NGO 초기화 public override void OnNetworkSpawn() { @@ -53,9 +69,19 @@ public class PlayerNetworkController : NetworkBehaviour Debug.Log("[Camera] 로컬 플레이어에게 카메라가 연결되었습니다."); } + // 씬의 Canvas 안에 있는 "Crosshair"라는 이름의 오브젝트를 찾습니다. + GameObject crosshairObj = GameObject.Find("Crosshair"); + if (crosshairObj != null) + { + _crosshairRect = crosshairObj.GetComponent(); + crosshairUI = crosshairObj.GetComponent(); + // 초기 스프라이트 설정 + crosshairUI.sprite = idleCrosshair; + } + _inputActions = new PlayerInputActions(); _inputActions.Player.Jump.performed += ctx => OnJump(); - _inputActions.Player.Attack.performed += ctx => OnAttackServerRpc(); + _inputActions.Player.Attack.performed += ctx => OnAttackInput(); _inputActions.Player.Interact.performed += ctx => OnInteractTap(); // 탭 상호작용 _inputActions.Player.Interact.started += ctx => _isHoldingInteract = true; @@ -80,6 +106,9 @@ public class PlayerNetworkController : NetworkBehaviour HandleMovement(); if (_isHoldingInteract) PerformConstructionSupport(); + + UpdateCrosshairPosition(); // 이 안에서 움직여야 합니다. + UpdateTargetFeedback(); } // --- 이동 관련 로직 (기존 유지) --- @@ -119,16 +148,52 @@ public class PlayerNetworkController : NetworkBehaviour if (_isGrounded) _velocity.y = Mathf.Sqrt(jumpHeight * -2f * gravity); } - // --- 채광 로직 (기존 유지) --- - [Rpc(SendTo.Server, InvokePermission = RpcInvokePermission.Owner)] - private void OnAttackServerRpc() + private void OnAttackInput() { - OnAttackClientRpc(); - Collider[] hitBlocks = Physics.OverlapSphere(transform.position + transform.forward, attackRange, mineableLayer); - foreach (var col in hitBlocks) + if (!IsOwner) return; + + // 1. 마우스가 가리키는 월드상의 위치를 먼저 찾습니다. + Ray mouseRay = Camera.main.ScreenPointToRay(Mouse.current.position.ReadValue()); + Vector3 worldAimPoint; + + // 아주 멀리까지 레이를 쏴서 조준 방향을 결정합니다. + if (Physics.Raycast(mouseRay, out RaycastHit mouseHit, 1000f, ~ignoreDuringAim)) + worldAimPoint = mouseHit.point; + else + worldAimPoint = mouseRay.GetPoint(100f); + + // 2. 캐릭터 가슴 높이에서 조준점을 향하는 방향 계산 + Vector3 origin = transform.position + Vector3.up * 1.2f; + Vector3 direction = (worldAimPoint - origin).normalized; + + // 3. 캐릭터에서 해당 방향으로 SphereCast를 쏴서 가장 가까운 블록 하나를 찾습니다. + // SphereCast는 가장 먼저 닿는 오브젝트 하나만 hit에 담습니다. + if (Physics.SphereCast(origin, aimRadius, direction, out RaycastHit blockHit, attackRange, mineableLayer)) { - MineableBlock block = col.GetComponentInParent(); - if (block != null) block.TakeDamageRpc(miningDamage); + if (blockHit.collider.TryGetComponent(out var netObj)) + { + // 서버에 대미지 요청 + ApplyMiningDamageServerRpc(netObj.NetworkObjectId); + } + } + + _animator.SetTrigger("Attack"); + } + + [Rpc(SendTo.Server)] + private void ApplyMiningDamageServerRpc(ulong targetId) + { + if (NetworkManager.Singleton.SpawnManager.SpawnedObjects.TryGetValue(targetId, out var target)) + { + if (target.TryGetComponent(out var block)) + { + // 서버에서 최종 거리 검증 후 대미지 적용 + if (Vector3.Distance(transform.position, target.transform.position) <= attackRange + 1.0f) + { + block.TakeDamageRpc(miningDamage); + block.PlayHitEffectClientRpc(); + } + } } } @@ -186,4 +251,132 @@ public class PlayerNetworkController : NetworkBehaviour { if (IsOwner && _inputActions != null) _inputActions.Disable(); } + + private void UpdateCrosshairPosition() + { + // 1. 변수 할당 확인 (할당이 안 되어 있으면 여기서 찾음) + if (_crosshairRect == null) + { + GameObject go = GameObject.Find("Crosshair"); + if (go != null) _crosshairRect = go.GetComponent(); + else return; // 여전히 없으면 중단 + } + + // 2. 마우스 입력 읽기 (New Input System) + Vector2 mousePos = Mouse.current.position.ReadValue(); + Vector2 screenCenter = new Vector2(Screen.width / 2f, Screen.height / 2f); + + // 3. 중앙으로부터의 거리 계산 + Vector2 offset = mousePos - screenCenter; + + // 4. [중요] 반지름 제한 확인 (crosshairScreenRadius가 0이면 이동하지 않음) + if (crosshairScreenRadius > 0) + { + // 내적과 크기 계산을 통해 원형 제한 적용 + if (offset.magnitude > crosshairScreenRadius) + { + offset = offset.normalized * crosshairScreenRadius; + } + } + + // 5. UI 좌표 적용 (Screen Space - Overlay 기준) + _crosshairRect.position = screenCenter + offset; + } + private void UpdateTargetFeedback() + { + if (!IsOwner || _crosshairRect == null) return; + + // 1. [조준점 확보] 카메라 레이로 마우스가 가리키는 '실제 지점'을 찾습니다. + Ray cameraRay = Camera.main.ScreenPointToRay(_crosshairRect.position); + RaycastHit cameraHit; + + // 지형이나 블록을 모두 검사하여 조준점을 잡습니다. + bool hitSomething = Physics.Raycast(cameraRay, out cameraHit, 150f, ~ignoreDuringAim); + Vector3 worldAimPoint = hitSomething ? cameraHit.point : cameraRay.GetPoint(100f); + + // 2. [거리 및 방향 계산] 캐릭터 가슴에서 그 지점까지의 벡터를 구합니다. + Vector3 origin = transform.position + Vector3.up * 1.2f; + Vector3 toTarget = worldAimPoint - origin; + float distToTarget = toTarget.magnitude; + Vector3 direction = toTarget.normalized; + + // 3. [대상 우선 판정] + // 만약 카메라 레이가 '채광 가능한 블록'을 직접 때렸고, 그게 사거리 이내라면? -> 바로 타겟팅! + bool isDirectHit = hitSomething && ((1 << cameraHit.collider.gameObject.layer) & mineableLayer) != 0; + + RaycastHit finalHit; + bool hasValidTarget = false; + + if (isDirectHit && distToTarget <= attackRange) + { + // 마우스가 직접 블록을 가리키고 사거리 내에 있는 경우 + finalHit = cameraHit; + hasValidTarget = true; + } + else + { + // 마우스가 허공을 보거나 너무 먼 곳을 볼 때만 '범위 탐색(SphereCast)'을 수행합니다. + float searchDist = Mathf.Min(distToTarget, attackRange); + Vector3 rayStart = origin + direction * 0.4f; + hasValidTarget = Physics.SphereCast(rayStart, aimRadius, direction, out finalHit, searchDist - 0.4f, mineableLayer); + } + + // 4. 디버그 및 시각화 업데이트 + _debugOrigin = origin; + _debugDir = direction; + _debugHit = hasValidTarget; + _debugDist = hasValidTarget ? Vector3.Distance(origin, finalHit.point) : Mathf.Min(distToTarget, attackRange); + + UpdateBlockVisuals(hasValidTarget, finalHit); + } + + private void UpdateBlockVisuals(bool hasTarget, RaycastHit hit) + { + MineableBlock newTarget = null; + + if (hasTarget) + { + // 부모나 자신에게서 MineableBlock 컴포넌트를 찾습니다. + newTarget = hit.collider.GetComponentInParent(); + } + + // 대상이 바뀌었을 때만 실행 (최적화) + if (_currentTargetBlock != newTarget) + { + // 1. 이전 타겟 하이라이트 해제 + if (_currentTargetBlock != null) + { + _currentTargetBlock.SetHighlight(false); + } + + // 2. 새로운 타겟 하이라이트 적용 + if (newTarget != null) + { + newTarget.SetHighlight(true); + } + + _currentTargetBlock = newTarget; + } + + // 3. 크로스헤어 상태 업데이트 + if (crosshairUI != null) + { + crosshairUI.sprite = hasTarget ? targetCrosshair : idleCrosshair; + crosshairUI.color = hasTarget ? Color.green : Color.white; + } + } + + private void OnDrawGizmos() + { + if (!Application.isPlaying || !IsOwner) return; + + // 실제 채굴 탐색 궤적을 씬 뷰에 표시 + Gizmos.color = _debugHit ? Color.red : Color.green; + + // 광선 표시 + Gizmos.DrawLine(_debugOrigin, _debugOrigin + _debugDir * _debugDist); + + // 탐색 영역(구체) 표시 + Gizmos.DrawWireSphere(_debugOrigin + _debugDir * _debugDist, aimRadius); + } } \ No newline at end of file diff --git a/Assets/crosshair145 1.png b/Assets/crosshair145 1.png new file mode 100644 index 0000000..c304607 Binary files /dev/null and b/Assets/crosshair145 1.png differ diff --git a/Assets/crosshair145 1.png.meta b/Assets/crosshair145 1.png.meta new file mode 100644 index 0000000..a839f1f --- /dev/null +++ b/Assets/crosshair145 1.png.meta @@ -0,0 +1,188 @@ +fileFormatVersion: 2 +guid: 174f7cb20aaa6d4409b788a700a925ad +TextureImporter: + internalIDToNameTable: + - first: + 213: 2628378444897590106 + second: crosshair145 1_0 + - first: + 213: -5777380809452016309 + second: crosshair145 1_1 + - first: + 213: 1953246644506807983 + second: crosshair145 1_2 + - first: + 213: 4818422223148679014 + second: crosshair145 1_3 + - first: + 213: 2895722212991460851 + second: crosshair145 1_4 + - first: + 213: -4547391801089170338 + second: crosshair145 1_5 + - first: + 213: -4117766800263195258 + second: crosshair145 1_6 + - first: + 213: -2205877514133103665 + second: crosshair145 1_7 + externalObjects: {} + serializedVersion: 13 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 2 + 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: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 4 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: + - serializedVersion: 2 + name: crosshair145 1_0 + rect: + serializedVersion: 2 + x: 6 + y: 6 + width: 60 + height: 60 + alignment: 0 + pivot: {x: 0.5, y: 0.5} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: 0 + bones: [] + spriteID: 232770f77d05e424893b97f732059b5c + internalID: 2628378444897590106 + vertices: [] + indices: + edges: [] + weights: [] + outline: [] + customData: + physicsShape: [] + bones: [] + spriteID: 214d92988a10e5c458a6fb8eae5479f8 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spriteCustomMetadata: + entries: + - key: SpriteEditor.SliceOnImport + value: False + - key: SpriteEditor.SliceSettings + value: '{"sliceOnImport":false,"gridCellCount":{"x":1.0,"y":1.0},"gridSpriteSize":{"x":64.0,"y":64.0},"gridSpriteOffset":{"x":0.0,"y":0.0},"gridSpritePadding":{"x":0.0,"y":0.0},"pivot":{"x":0.5,"y":0.5},"pivotPixels":{"x":0.0,"y":0.0},"autoSlicingMethod":0,"spriteAlignment":0,"pivotUnitMode":0,"slicingType":0,"keepEmptyRects":false,"isAlternate":false}' + nameFileIdTable: + crosshair145 1_0: 2628378444897590106 + crosshair145 1_1: -5777380809452016309 + crosshair145 1_2: 1953246644506807983 + crosshair145 1_3: 4818422223148679014 + crosshair145 1_4: 2895722212991460851 + crosshair145 1_5: -4547391801089170338 + crosshair145 1_6: -4117766800263195258 + crosshair145 1_7: -2205877514133103665 + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/crosshair146.png b/Assets/crosshair146.png new file mode 100644 index 0000000..dd2180a Binary files /dev/null and b/Assets/crosshair146.png differ diff --git a/Assets/crosshair146.png.meta b/Assets/crosshair146.png.meta new file mode 100644 index 0000000..96916c0 --- /dev/null +++ b/Assets/crosshair146.png.meta @@ -0,0 +1,168 @@ +fileFormatVersion: 2 +guid: 7652364ca249c3144813de7eb3d1b129 +TextureImporter: + internalIDToNameTable: + - first: + 213: -3655418175180962541 + second: crosshair146_0 + - first: + 213: 3362118682429653659 + second: crosshair146_1 + - first: + 213: 5586891055607624698 + second: crosshair146_2 + - first: + 213: -5662625722731528258 + second: crosshair146_3 + externalObjects: {} + serializedVersion: 13 + 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 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 2 + 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: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 4 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: + - serializedVersion: 2 + name: crosshair146_3 + rect: + serializedVersion: 2 + x: 15 + y: 15 + width: 42 + height: 42 + alignment: 0 + pivot: {x: 0.5, y: 0.5} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: ebff89438ef4a61b0800000000000000 + internalID: -5662625722731528258 + vertices: [] + indices: + edges: [] + weights: [] + outline: [] + customData: + physicsShape: [] + bones: [] + spriteID: 1d19aae810763694b91ae89089839d4d + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spriteCustomMetadata: + entries: [] + nameFileIdTable: + crosshair146_0: -3655418175180962541 + crosshair146_1: 3362118682429653659 + crosshair146_2: 5586891055607624698 + crosshair146_3: -5662625722731528258 + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: