Selaa lähdekoodia

Added toolbar UI and hilightable objects

James Peret 2 vuotta sitten
vanhempi
commit
3a9cd08a03

+ 8 - 0
Assets.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: f282b295f9f531346a66019d586815fe
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

BIN
Assets/example-icon.png


+ 108 - 0
Assets/example-icon.png.meta

@@ -0,0 +1,108 @@
+fileFormatVersion: 2
+guid: 6be36c1261c2311459843308896e54f7
+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: 1
+    aniso: 1
+    mipBias: 0
+    wrapU: 1
+    wrapV: 1
+    wrapW: 0
+  nPOTScale: 0
+  lightmap: 0
+  compressionQuality: 50
+  spriteMode: 1
+  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
+  platformSettings:
+  - serializedVersion: 3
+    buildTarget: DefaultTexturePlatform
+    maxTextureSize: 2048
+    resizeAlgorithm: 0
+    textureFormat: -1
+    textureCompression: 1
+    compressionQuality: 50
+    crunchedCompression: 0
+    allowsAlphaSplitting: 0
+    overridden: 0
+    androidETC2FallbackOverride: 0
+    forceMaximumCompressionQuality_BC6H_BC7: 0
+  - serializedVersion: 3
+    buildTarget: Standalone
+    maxTextureSize: 2048
+    resizeAlgorithm: 0
+    textureFormat: -1
+    textureCompression: 1
+    compressionQuality: 50
+    crunchedCompression: 0
+    allowsAlphaSplitting: 0
+    overridden: 0
+    androidETC2FallbackOverride: 0
+    forceMaximumCompressionQuality_BC6H_BC7: 0
+  spriteSheet:
+    serializedVersion: 2
+    sprites: []
+    outline: []
+    physicsShape: []
+    bones: []
+    spriteID: 5e97eb03825dee720800000000000000
+    internalID: 0
+    vertices: []
+    indices: 
+    edges: []
+    weights: []
+    secondaryTextures: []
+  spritePackingTag: 
+  pSDRemoveMatte: 0
+  pSDShowRemoveMatteOption: 0
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 337 - 0
Prefabs/toolbar-buttom.prefab

@@ -0,0 +1,337 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!1 &5688569224772868132
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 6586644472835995700}
+  - component: {fileID: 8006313975334461860}
+  - component: {fileID: 4220003689899752190}
+  - component: {fileID: 6314178462932340981}
+  - component: {fileID: 1561439600470150519}
+  - component: {fileID: 7259677648838948615}
+  - component: {fileID: 2975460526922245037}
+  - component: {fileID: 2937517381633121408}
+  - component: {fileID: 484204583646978093}
+  - component: {fileID: 2447170661494834483}
+  m_Layer: 0
+  m_Name: toolbar-buttom
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!224 &6586644472835995700
+RectTransform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 5688569224772868132}
+  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: 7004099387514113920}
+  m_Father: {fileID: 0}
+  m_RootOrder: 0
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+  m_AnchorMin: {x: 0, y: 0}
+  m_AnchorMax: {x: 0, y: 0}
+  m_AnchoredPosition: {x: 0, y: 0}
+  m_SizeDelta: {x: 0, y: 0}
+  m_Pivot: {x: 0.5, y: 0.5}
+--- !u!222 &8006313975334461860
+CanvasRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 5688569224772868132}
+  m_CullTransparentMesh: 1
+--- !u!114 &4220003689899752190
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 5688569224772868132}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_Material: {fileID: 0}
+  m_Color: {r: 1, g: 1, b: 1, 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: 21300000, guid: 09d958a2dd49892409cae61293913a0f, type: 3}
+  m_Type: 1
+  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!114 &6314178462932340981
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 5688569224772868132}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_Navigation:
+    m_Mode: 0
+    m_WrapAround: 0
+    m_SelectOnUp: {fileID: 0}
+    m_SelectOnDown: {fileID: 0}
+    m_SelectOnLeft: {fileID: 0}
+    m_SelectOnRight: {fileID: 0}
+  m_Transition: 2
+  m_Colors:
+    m_NormalColor: {r: 1, g: 1, b: 1, a: 1}
+    m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
+    m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1}
+    m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
+    m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608}
+    m_ColorMultiplier: 1
+    m_FadeDuration: 0.1
+  m_SpriteState:
+    m_HighlightedSprite: {fileID: 21300000, guid: 151dded6c4510f74291cd8ce9ebfebae, type: 3}
+    m_PressedSprite: {fileID: 21300000, guid: a61c56481268fb749998efa8aef0c72e, type: 3}
+    m_SelectedSprite: {fileID: 21300000, guid: 7c07987884e204b428123addcda05e88, type: 3}
+    m_DisabledSprite: {fileID: 21300000, guid: 8eb64a9caded62e4f87634df9bbe2417, type: 3}
+  m_AnimationTriggers:
+    m_NormalTrigger: Normal
+    m_HighlightedTrigger: Highlighted
+    m_PressedTrigger: Pressed
+    m_SelectedTrigger: Selected
+    m_DisabledTrigger: Disabled
+  m_Interactable: 1
+  m_TargetGraphic: {fileID: 4220003689899752190}
+  m_OnClick:
+    m_PersistentCalls:
+      m_Calls:
+      - m_Target: {fileID: 1561439600470150519}
+        m_TargetAssemblyTypeName: KairoEngine.UI.InteractionHandler.ClickHandler,
+          KairoEngine.UI
+        m_MethodName: OnClick
+        m_Mode: 1
+        m_Arguments:
+          m_ObjectArgument: {fileID: 0}
+          m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine
+          m_IntArgument: 0
+          m_FloatArgument: 0
+          m_StringArgument: 
+          m_BoolArgument: 0
+        m_CallState: 2
+      - m_Target: {fileID: 2937517381633121408}
+        m_TargetAssemblyTypeName: KairoEngine.UI.SFX.ButtonSFX, KairoEngine.UI.SFX
+        m_MethodName: OnClick
+        m_Mode: 1
+        m_Arguments:
+          m_ObjectArgument: {fileID: 0}
+          m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine
+          m_IntArgument: 0
+          m_FloatArgument: 0
+          m_StringArgument: 
+          m_BoolArgument: 0
+        m_CallState: 2
+--- !u!114 &1561439600470150519
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 5688569224772868132}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: b7f39340cf67bdf43b12a74681b8b05a, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  title: 
+--- !u!114 &7259677648838948615
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 5688569224772868132}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: aba906f73151edb44ad3e23a912a4c55, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  headerComponent: {fileID: 0}
+  graphicComponent: {fileID: 599714692793360528}
+--- !u!114 &2975460526922245037
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 5688569224772868132}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 460bbea74d2a0b1459abb106bd7882d4, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  header: 
+  content: 
+  tooltipType: 
+--- !u!114 &2937517381633121408
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 5688569224772868132}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 449a91b8c6475094d8210735aa4a9220, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  button: {fileID: 0}
+  onPointerEnterSFX: {fileID: 11400000, guid: d96c6513dccd6354f996ace202f21899, type: 2}
+  onPointerExitSFX: {fileID: 11400000, guid: a0fa2ea362b1ca843a23b149bbb2d48a, type: 2}
+  onPointerDownSFX: {fileID: 0}
+  onPointerUpSFX: {fileID: 0}
+  onClickSFX: {fileID: 11400000, guid: ad7a5d97b4579c64289a7869e2576ea1, type: 2}
+--- !u!114 &484204583646978093
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 5688569224772868132}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 66a1c1c2f9d49af44a83c1caf9195d26, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  objectToAnimate: {fileID: 0}
+  objectToDisable: {fileID: 0}
+  animationTime: 0.5
+  animateOnEnable: 0
+  animateOnDisable: 0
+  delay: 0
+  disableDelay: 0
+  disableObjectOnEnd: 1
+  childUiAnimators: []
+  animateScale: 1
+  scaleDuration: 0.3
+  sacelFrom: {x: 0, y: 0, z: 0}
+  scaleTo: {x: 0, y: 0, z: 0}
+  animateAlpha: 1
+  alphaDuration: 0.1
+  alphaFrom: 0
+  alphaTo: 1
+--- !u!114 &2447170661494834483
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 5688569224772868132}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 66ba0f68b995e094cab7a691e94f83bc, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  image: {fileID: 4220003689899752190}
+  button: {fileID: 6314178462932340981}
+  selected: 0
+  defaultSprite: {fileID: 21300000, guid: 09d958a2dd49892409cae61293913a0f, type: 3}
+  selectedSprite: {fileID: 21300000, guid: 7c07987884e204b428123addcda05e88, type: 3}
+  disabledSprite: {fileID: 21300000, guid: 8eb64a9caded62e4f87634df9bbe2417, type: 3}
+  isInteractable: 1
+--- !u!1 &7227444478654724498
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 7004099387514113920}
+  - component: {fileID: 1215374720516887934}
+  - component: {fileID: 599714692793360528}
+  m_Layer: 0
+  m_Name: Image
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!224 &7004099387514113920
+RectTransform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 7227444478654724498}
+  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: 6586644472835995700}
+  m_RootOrder: 0
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+  m_AnchorMin: {x: 0, y: 0}
+  m_AnchorMax: {x: 1, y: 1}
+  m_AnchoredPosition: {x: 0, y: 1}
+  m_SizeDelta: {x: -12, y: -14}
+  m_Pivot: {x: 0.5, y: 0.5}
+--- !u!222 &1215374720516887934
+CanvasRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 7227444478654724498}
+  m_CullTransparentMesh: 1
+--- !u!114 &599714692793360528
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 7227444478654724498}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_Material: {fileID: 0}
+  m_Color: {r: 1, g: 1, b: 1, 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: 21300000, guid: 6be36c1261c2311459843308896e54f7, type: 3}
+  m_Type: 0
+  m_PreserveAspect: 1
+  m_FillCenter: 1
+  m_FillMethod: 4
+  m_FillAmount: 1
+  m_FillClockwise: 1
+  m_FillOrigin: 0
+  m_UseSpriteMesh: 0
+  m_PixelsPerUnitMultiplier: 1

+ 7 - 0
Prefabs/toolbar-buttom.prefab.meta

@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 1501a8af0034f3b41b3bc477495bc787
+PrefabImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 2 - 0
Runtime/InteractionTools/IInteractionTool.cs

@@ -8,5 +8,7 @@ namespace KairoEngine.GameTools.InteractionTools
     {
         void EnableTool();
         void DisableTool();
+
+        Sprite GetIcon();
     }
 }

+ 9 - 2
Runtime/InteractionTools/InteractionToolsManager.cs

@@ -12,8 +12,9 @@ namespace KairoEngine.GameTools.InteractionTools
     {
         public static InteractionToolsManager instance;
         [ReadOnly] public int currentTools = 0;
+        public bool showDebug = false;
         public List<GameObject> tools = new List<GameObject>();
-        private List<IInteractionTool> toolInterfaces = new List<IInteractionTool>();
+        [HideInInspector] public List<IInteractionTool> toolInterfaces = new List<IInteractionTool>();
 
         private void Awake()
         {
@@ -34,13 +35,19 @@ namespace KairoEngine.GameTools.InteractionTools
             {
                 IInteractionTool toolInterface = tools[i].GetComponent<IInteractionTool>();
                 if(toolInterface == null) toolInterface = tools[i].GetComponentInChildren<IInteractionTool>();
-                if(toolInterface != null) toolInterfaces.Add(toolInterface);
+                if(toolInterface != null) 
+                {
+                    if(showDebug) Debug.Log($"Registered tool: {tools[i].name} ({i})");
+                    toolInterfaces.Add(toolInterface);
+                }
                 else Debug.LogError($"No Interaction tool interface found in components on \"{tools[i].name}\"", tools[i]);
             }
         }
 
         public void ChangeTool(int toolIndex)
         {
+            if(toolIndex == currentTools) return;
+            if(showDebug) Debug.Log($"Changing tool to {tools[toolIndex].name} ({toolIndex})");
             currentTools = toolIndex;
             for (int i = 0; i < toolInterfaces.Count; i++)
             {

+ 3 - 1
Runtime/KairoEngine.GameTools.asmdef

@@ -1,11 +1,13 @@
 {
     "name": "KairoEngine.GameTools",
+    "rootNamespace": "",
     "references": [
         "GUID:7e5ae6a38d1532248b4c890eca668b06",
         "GUID:b5398ac4f2218bd4ba186b0baff7fb21",
         "GUID:142285d3db5e7e849b02ea3a75bc2de7",
         "GUID:5f03fc37b95cb644599751ca563336b2",
-        "GUID:ed7bf2f4272e1b74a98086f77f3ae14c"
+        "GUID:ed7bf2f4272e1b74a98086f77f3ae14c",
+        "GUID:560b04d1a97f54a4e82edc0cbbb69285"
     ],
     "includePlatforms": [],
     "excludePlatforms": [],

+ 16 - 0
Runtime/SelectableObjects/IHighlightableObject.cs

@@ -0,0 +1,16 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+
+namespace KairoEngine.GameTools.Selectables
+{
+    /// <summary>
+    /// An interface that represents and object that can be selected and has actions.
+    /// </summary>
+    public interface IHighlightableObject
+    {
+        Color GetHighlightColor();
+        bool ShowOutline();
+    }
+}
+

+ 11 - 0
Runtime/SelectableObjects/IHighlightableObject.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: fe9b6237ff9cc294e8bb9f94494eadc2
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 9 - 2
Runtime/SelectableObjects/SelectableObjectTool.cs

@@ -2,20 +2,22 @@
 using System.Collections.Generic;
 using UnityEngine;
 using KairoEngine.GameTools.InteractionTools;
-using Sirenix.OdinInspector;
 using KairoEngine.UI;
+using Sirenix.OdinInspector;
 
 namespace KairoEngine.GameTools.Selectables
 {
     /// <summary>
     /// The selectableObject tools controls input for selecting objects in the game and visualizing its properties and actions.
     /// </summary>
-    public class SelectableObjectTool : MonoBehaviour, IInteractionTool
+    public class SelectableObjectTool : MonoBehaviour, IInteractionTool, IHighlightableObject
     {
         public bool allowMultiSelection = true;
         public KeyCode multiSelectionKey = KeyCode.LeftControl;
         public LayerMask layerMask;
         public bool selectableObjectToolEnabled = true;
+        public Sprite icon;
+        public Color selectionColor = Color.white;
 
         [ShowInInspector, ReadOnly] public List<SelectableObjectTrigger> selectedObjects = new List<SelectableObjectTrigger>();
 
@@ -34,6 +36,11 @@ namespace KairoEngine.GameTools.Selectables
             selectableObjectToolEnabled = true;
         }
 
+        public Sprite GetIcon() => icon;
+
+        public Color GetHighlightColor() => selectionColor;
+        public bool ShowOutline() => true;
+
         private void SelectObjects()
         {
             actionListChanged = false;

+ 6 - 10
Runtime/SelectableObjects/SelectableObjectTrigger.cs

@@ -34,6 +34,7 @@ namespace KairoEngine.GameTools.Selectables
 
         public void Select()
         {
+            if(isSelected) return;
             if(MouseInputUIBlocker.BlockedByUI) return;
             isSelected = true;
             ShowOutline();
@@ -41,6 +42,7 @@ namespace KairoEngine.GameTools.Selectables
 
         public void Deselect() 
         {
+            if(!isSelected) return;
             isSelected = false;
             HideOutline();
         }
@@ -55,18 +57,12 @@ namespace KairoEngine.GameTools.Selectables
 
         private void ShowOutline()
         {
-            bool hasTool = toolsManager.currentTools == 0 || toolsManager.currentTools == 2;
-            if(hasTool && !MouseInputUIBlocker.BlockedByUI)
+            var highlightInterface = toolsManager.toolInterfaces[toolsManager.currentTools] as IHighlightableObject;
+            bool hasTool = highlightInterface != null;
+            if(hasTool && !MouseInputUIBlocker.BlockedByUI && highlightInterface.ShowOutline())
             {
                 outlinable.enabled = true;
-                if(toolsManager.currentTools == 2)
-                {
-                    outlinable.OutlineParameters.Color = Color.red;
-                }
-                else
-                {
-                    outlinable.OutlineParameters.Color = Color.white;
-                }
+                outlinable.OutlineParameters.Color = highlightInterface.GetHighlightColor();
             }
         }
 

+ 8 - 0
Runtime/UI.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 2601553e6f3901342992d7faac698ff8
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 84 - 0
Runtime/UI/ToolbarUi.cs

@@ -0,0 +1,84 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using UnityEngine.UI;
+using KairoEngine.UI;
+using KairoEngine.UI.InteractionHandler;
+using KairoEngine.GameTools.InteractionTools;
+using Sirenix.OdinInspector;
+using KairoEngine.Core;
+using UniRx;
+
+namespace KairoEngine.GameTools.UI
+{
+    public class ToolbarUi : MonoBehaviour, IClickHandler
+    {
+        public InteractionToolsManager interactionToolsManager;
+        public MenuUI menuUi;
+        private List<SelectedButton> selectButtons = new List<SelectedButton>();
+        private int toolIndex;
+
+        void Start()
+        {
+            CreateMenu();
+            toolIndex = interactionToolsManager.currentTools;
+        }
+
+        void Update()
+        {
+            if(interactionToolsManager.currentTools != toolIndex)
+            {
+                toolIndex = interactionToolsManager.currentTools;
+                for (int i = 0; i < interactionToolsManager.tools.Count; i++)
+                {
+                    //if(selectButtons[i] == null) selectButtons[i] = menuUi.buttons[i].button.gameObject.GetComponent<SelectedButton>();
+                    if(toolIndex == i && selectButtons[i] != null) selectButtons[i].Select();
+                    else if(selectButtons[i] != null) selectButtons[i].Deselect();
+                }
+            }
+        }
+
+        public void OnClick(string title)
+        {
+            for (int i = 0; i < interactionToolsManager.tools.Count; i++)
+            {
+                if(interactionToolsManager.tools[i].name == title)
+                {
+                    if(selectButtons[i] != null) selectButtons[i].Select();
+                    interactionToolsManager.ChangeTool(i);
+                }
+                else selectButtons[i].Deselect();
+            }
+        }
+
+        [Button("Create")]
+        public void CreateMenu()
+        {
+            if(interactionToolsManager == null) return;
+            menuUi.DestroyMenu();
+            selectButtons.Clear();
+            List<MenuButtomData> menuData = new List<MenuButtomData>();
+            for (int i = 0; i < interactionToolsManager.tools.Count; i++)
+            {
+                MenuButtomData data = new MenuButtomData();
+                data.title = interactionToolsManager.tools[i].gameObject.name;
+                data.showTooltip = false;
+                data.subMenuParent = true;
+                data.action = interactionToolsManager.tools[i].gameObject.name;
+                data.graphic = interactionToolsManager.tools[i].GetComponent<IInteractionTool>().GetIcon();
+                menuData.Add(data);
+            }
+            menuUi.buttons = menuData;
+            menuUi.CreateMenu();
+            Timer.ExecuteRealTime(100, () => {
+                for (int i = 0; i < interactionToolsManager.tools.Count; i++)
+                {
+                    selectButtons.Add(menuUi.buttons[i].button.gameObject.GetComponent<SelectedButton>());
+                }
+                selectButtons[interactionToolsManager.currentTools].Select();
+            });
+            
+        }
+        
+    }
+}

+ 11 - 0
Runtime/UI/ToolbarUi.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 9ce1527f118993b438a875e6fa5f51ae
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: