├── .gitignore ├── AdaptiveGrid ├── AdaptiveGrid.cs ├── Demo │ ├── 01.jpg │ ├── 02.jpg │ ├── 03.jpg │ ├── 04.jpg │ ├── 05.jpg │ ├── 06.jpg │ ├── 07.jpg │ ├── 08.jpg │ ├── 09.jpg │ ├── 10.jpg │ ├── 11.jpg │ └── AdaptiveGrid Demo.unity ├── LayoutTools.cs ├── MaxRects │ ├── BinRect.cs │ ├── MaxRectsBinPack.cs │ └── RectSize.cs ├── Preset.cs └── Presets │ ├── ArrangeFill.cs │ ├── ArrangeGrid.cs │ ├── ArrangePack.cs │ ├── ScaleFit.cs │ └── ScaleStretch.cs ├── LICENSE.md └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | # This .gitignore file should be placed at the root of your Unity project directory 2 | # 3 | # Get latest from https://github.com/github/gitignore/blob/master/Unity.gitignore 4 | # 5 | 6 | /[Ll]ibrary/ 7 | /[Tt]emp/ 8 | /[Oo]bj/ 9 | /[Bb]uild/ 10 | /[Bb]uilds/ 11 | /[Ll]ogs/ 12 | /[Mm]emoryCaptures/ 13 | 14 | 15 | 16 | # Asset meta data should only be ignored when the corresponding asset is also ignored 17 | !/[Aa]ssets/**/*.meta 18 | *.meta 19 | 20 | # Uncomment this line if you wish to ignore the asset store tools plugin 21 | # /[Aa]ssets/AssetStoreTools* 22 | /[Aa]ssets/Unsorted 23 | 24 | # Autogenerated Jetbrains Rider plugin 25 | [Aa]ssets/Plugins/Editor/JetBrains* 26 | 27 | # Visual Studio cache directory 28 | .vs/ 29 | 30 | # Gradle cache directory 31 | .gradle/ 32 | 33 | # Autogenerated VS/MD/Consulo solution and project files 34 | ExportedObj/ 35 | .consulo/ 36 | *.csproj 37 | *.unityproj 38 | *.sln 39 | *.suo 40 | *.tmp 41 | *.user 42 | *.userprefs 43 | *.pidb 44 | *.booproj 45 | *.svd 46 | *.pdb 47 | *.mdb 48 | *.opendb 49 | *.VC.db 50 | 51 | # Unity3D generated meta files 52 | *.pidb.meta 53 | *.pdb.meta 54 | *.mdb.meta 55 | 56 | # Unity3D generated file on crash reports 57 | sysinfo.txt 58 | 59 | # Builds 60 | *.apk 61 | *.unitypackage 62 | 63 | # Crashlytics generated file 64 | crashlytics-build.properties 65 | 66 | -------------------------------------------------------------------------------- /AdaptiveGrid/AdaptiveGrid.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | using UnityEngine.EventSystems; 5 | 6 | namespace AdaptiveGrid 7 | { 8 | [ExecuteInEditMode] 9 | public class AdaptiveGrid : UIBehaviour 10 | { 11 | private Vector2 _cellSize; 12 | private RectTransform _gridRect; 13 | private List _gridChildList = new List(); 14 | 15 | [Header("Grid settings")] 16 | [SerializeField] private ArrangeLayout _arrangeLayout; 17 | [SerializeField] [SerializeReference] private AdaptivePreset _arrangePreset; 18 | [SerializeField] Offset _gridMargin; 19 | 20 | 21 | [Header("Cell content")] 22 | [SerializeField] private ScaleMethod _scaleMethod; 23 | [SerializeField] [SerializeReference] private AdaptivePreset _scalePreset; 24 | [SerializeField] Offset _cellPadding; 25 | 26 | private event Action ArrangePresetChanged; 27 | private event Action ScalePresetChanged; 28 | 29 | private void AdjustElements() 30 | { 31 | _arrangePreset.Apply(_gridChildList, _gridRect, _gridMargin, _cellPadding); 32 | _scalePreset.Apply(_gridChildList, _gridRect, _gridMargin, _cellPadding); 33 | } 34 | private bool ApproptiatePresetKey(AdaptivePreset preset, System.Enum keyValue) 35 | { 36 | if (preset == null) 37 | { 38 | return false; 39 | } 40 | return preset.SelectorInInspector.Equals(keyValue); 41 | } 42 | 43 | private void CollectElements() 44 | { 45 | _gridChildList.Clear(); 46 | foreach (RectTransform child in transform) 47 | { 48 | _gridChildList.Add(child); 49 | } 50 | } 51 | private void OnArrangePresetChanged() 52 | { 53 | AdaptivePreset.ChangeValue(ref _arrangePreset, _arrangeLayout); 54 | } 55 | 56 | private void OnScalePresetChanged() 57 | { 58 | AdaptivePreset.ChangeValue(ref _scalePreset, _scaleMethod); 59 | } 60 | 61 | protected override void Awake() 62 | { 63 | base.Awake(); 64 | 65 | _gridRect = GetComponent(); 66 | CollectElements(); 67 | 68 | ArrangePresetChanged += OnArrangePresetChanged; 69 | ScalePresetChanged += OnScalePresetChanged; 70 | } 71 | 72 | protected override void OnDestroy() 73 | { 74 | ArrangePresetChanged -= OnArrangePresetChanged; 75 | ScalePresetChanged -= OnScalePresetChanged; 76 | } 77 | 78 | protected override void OnRectTransformDimensionsChange() 79 | { 80 | AdjustElements(); 81 | } 82 | 83 | protected override void Start() 84 | { 85 | base.Start(); 86 | AdjustElements(); 87 | } 88 | 89 | public void OnTransformChildrenChanged() 90 | { 91 | CollectElements(); 92 | AdjustElements(); 93 | } 94 | 95 | public void SetArrangePreset(ArrangeLayout newArrangeLayout) 96 | { 97 | if (newArrangeLayout == _arrangeLayout) 98 | { 99 | return; 100 | } 101 | _arrangeLayout = newArrangeLayout; 102 | ArrangePresetChanged?.Invoke(); 103 | } 104 | 105 | public void SetScalePreset(ScaleMethod newScaleMethod) 106 | { 107 | if (newScaleMethod == _scaleMethod) 108 | { 109 | return; 110 | } 111 | _scaleMethod = newScaleMethod; 112 | ScalePresetChanged?.Invoke(); 113 | } 114 | 115 | /* Grid arrange and margins*/ 116 | public enum ArrangeLayout { Fill = 0, Grid = 1, PackByImage = 2 } 117 | 118 | /* Cell content scaling, padding and spacing */ 119 | public enum ScaleMethod { FitImage = 0, None = 1 } 120 | 121 | #if UNITY_EDITOR 122 | //Safe initialization in editor mode & runtime both 123 | protected override void OnCanvasHierarchyChanged() 124 | { 125 | _gridRect = GetComponent(); 126 | CollectElements(); 127 | } 128 | #endif 129 | 130 | 131 | #if UNITY_EDITOR 132 | protected override void OnValidate() 133 | { 134 | base.OnValidate(); 135 | 136 | CollectElements(); 137 | if (!ApproptiatePresetKey(_arrangePreset, _arrangeLayout)) 138 | { 139 | OnArrangePresetChanged(); 140 | } 141 | if (!ApproptiatePresetKey(_scalePreset, _scaleMethod)) 142 | { 143 | OnScalePresetChanged(); 144 | } 145 | 146 | // Fixes the warning 147 | // "SendMessage cannot be called during Awake, CheckConsistency, or OnValidate" 148 | UnityEditor.EditorApplication.delayCall += OnValidateCallback; 149 | } 150 | private void OnValidateCallback() 151 | { 152 | UnityEditor.EditorApplication.delayCall -= OnValidateCallback; 153 | AdjustElements(); 154 | } 155 | #endif 156 | 157 | } 158 | } -------------------------------------------------------------------------------- /AdaptiveGrid/Demo/01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cyberaslan/UnityAdaptiveGrid/bb613b6069c337c7aba755cc3f13d5ced4aa9b26/AdaptiveGrid/Demo/01.jpg -------------------------------------------------------------------------------- /AdaptiveGrid/Demo/02.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cyberaslan/UnityAdaptiveGrid/bb613b6069c337c7aba755cc3f13d5ced4aa9b26/AdaptiveGrid/Demo/02.jpg -------------------------------------------------------------------------------- /AdaptiveGrid/Demo/03.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cyberaslan/UnityAdaptiveGrid/bb613b6069c337c7aba755cc3f13d5ced4aa9b26/AdaptiveGrid/Demo/03.jpg -------------------------------------------------------------------------------- /AdaptiveGrid/Demo/04.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cyberaslan/UnityAdaptiveGrid/bb613b6069c337c7aba755cc3f13d5ced4aa9b26/AdaptiveGrid/Demo/04.jpg -------------------------------------------------------------------------------- /AdaptiveGrid/Demo/05.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cyberaslan/UnityAdaptiveGrid/bb613b6069c337c7aba755cc3f13d5ced4aa9b26/AdaptiveGrid/Demo/05.jpg -------------------------------------------------------------------------------- /AdaptiveGrid/Demo/06.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cyberaslan/UnityAdaptiveGrid/bb613b6069c337c7aba755cc3f13d5ced4aa9b26/AdaptiveGrid/Demo/06.jpg -------------------------------------------------------------------------------- /AdaptiveGrid/Demo/07.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cyberaslan/UnityAdaptiveGrid/bb613b6069c337c7aba755cc3f13d5ced4aa9b26/AdaptiveGrid/Demo/07.jpg -------------------------------------------------------------------------------- /AdaptiveGrid/Demo/08.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cyberaslan/UnityAdaptiveGrid/bb613b6069c337c7aba755cc3f13d5ced4aa9b26/AdaptiveGrid/Demo/08.jpg -------------------------------------------------------------------------------- /AdaptiveGrid/Demo/09.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cyberaslan/UnityAdaptiveGrid/bb613b6069c337c7aba755cc3f13d5ced4aa9b26/AdaptiveGrid/Demo/09.jpg -------------------------------------------------------------------------------- /AdaptiveGrid/Demo/10.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cyberaslan/UnityAdaptiveGrid/bb613b6069c337c7aba755cc3f13d5ced4aa9b26/AdaptiveGrid/Demo/10.jpg -------------------------------------------------------------------------------- /AdaptiveGrid/Demo/11.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cyberaslan/UnityAdaptiveGrid/bb613b6069c337c7aba755cc3f13d5ced4aa9b26/AdaptiveGrid/Demo/11.jpg -------------------------------------------------------------------------------- /AdaptiveGrid/Demo/AdaptiveGrid Demo.unity: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!29 &1 4 | OcclusionCullingSettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 2 7 | m_OcclusionBakeSettings: 8 | smallestOccluder: 5 9 | smallestHole: 0.25 10 | backfaceThreshold: 100 11 | m_SceneGUID: 00000000000000000000000000000000 12 | m_OcclusionCullingData: {fileID: 0} 13 | --- !u!104 &2 14 | RenderSettings: 15 | m_ObjectHideFlags: 0 16 | serializedVersion: 9 17 | m_Fog: 0 18 | m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} 19 | m_FogMode: 3 20 | m_FogDensity: 0.01 21 | m_LinearFogStart: 0 22 | m_LinearFogEnd: 300 23 | m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} 24 | m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} 25 | m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} 26 | m_AmbientIntensity: 1 27 | m_AmbientMode: 3 28 | m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} 29 | m_SkyboxMaterial: {fileID: 0} 30 | m_HaloStrength: 0.5 31 | m_FlareStrength: 1 32 | m_FlareFadeSpeed: 3 33 | m_HaloTexture: {fileID: 0} 34 | m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} 35 | m_DefaultReflectionMode: 0 36 | m_DefaultReflectionResolution: 128 37 | m_ReflectionBounces: 1 38 | m_ReflectionIntensity: 1 39 | m_CustomReflection: {fileID: 0} 40 | m_Sun: {fileID: 0} 41 | m_IndirectSpecularColor: {r: 0, g: 0, b: 0, a: 1} 42 | m_UseRadianceAmbientProbe: 0 43 | --- !u!157 &3 44 | LightmapSettings: 45 | m_ObjectHideFlags: 0 46 | serializedVersion: 12 47 | m_GIWorkflowMode: 1 48 | m_GISettings: 49 | serializedVersion: 2 50 | m_BounceScale: 1 51 | m_IndirectOutputScale: 1 52 | m_AlbedoBoost: 1 53 | m_EnvironmentLightingMode: 0 54 | m_EnableBakedLightmaps: 0 55 | m_EnableRealtimeLightmaps: 0 56 | m_LightmapEditorSettings: 57 | serializedVersion: 12 58 | m_Resolution: 2 59 | m_BakeResolution: 40 60 | m_AtlasSize: 1024 61 | m_AO: 0 62 | m_AOMaxDistance: 1 63 | m_CompAOExponent: 1 64 | m_CompAOExponentDirect: 0 65 | m_ExtractAmbientOcclusion: 0 66 | m_Padding: 2 67 | m_LightmapParameters: {fileID: 0} 68 | m_LightmapsBakeMode: 1 69 | m_TextureCompression: 1 70 | m_FinalGather: 0 71 | m_FinalGatherFiltering: 1 72 | m_FinalGatherRayCount: 256 73 | m_ReflectionCompression: 2 74 | m_MixedBakeMode: 2 75 | m_BakeBackend: 0 76 | m_PVRSampling: 1 77 | m_PVRDirectSampleCount: 32 78 | m_PVRSampleCount: 500 79 | m_PVRBounces: 2 80 | m_PVREnvironmentSampleCount: 500 81 | m_PVREnvironmentReferencePointCount: 2048 82 | m_PVRFilteringMode: 2 83 | m_PVRDenoiserTypeDirect: 0 84 | m_PVRDenoiserTypeIndirect: 0 85 | m_PVRDenoiserTypeAO: 0 86 | m_PVRFilterTypeDirect: 0 87 | m_PVRFilterTypeIndirect: 0 88 | m_PVRFilterTypeAO: 0 89 | m_PVREnvironmentMIS: 0 90 | m_PVRCulling: 1 91 | m_PVRFilteringGaussRadiusDirect: 1 92 | m_PVRFilteringGaussRadiusIndirect: 5 93 | m_PVRFilteringGaussRadiusAO: 2 94 | m_PVRFilteringAtrousPositionSigmaDirect: 0.5 95 | m_PVRFilteringAtrousPositionSigmaIndirect: 2 96 | m_PVRFilteringAtrousPositionSigmaAO: 1 97 | m_ExportTrainingData: 0 98 | m_TrainingDataDestination: TrainingData 99 | m_LightProbeSampleCountMultiplier: 4 100 | m_LightingDataAsset: {fileID: 0} 101 | m_LightingSettings: {fileID: 0} 102 | --- !u!196 &4 103 | NavMeshSettings: 104 | serializedVersion: 2 105 | m_ObjectHideFlags: 0 106 | m_BuildSettings: 107 | serializedVersion: 2 108 | agentTypeID: 0 109 | agentRadius: 0.5 110 | agentHeight: 2 111 | agentSlope: 45 112 | agentClimb: 0.4 113 | ledgeDropHeight: 0 114 | maxJumpAcrossDistance: 0 115 | minRegionArea: 2 116 | manualCellSize: 0 117 | cellSize: 0.16666667 118 | manualTileSize: 0 119 | tileSize: 256 120 | accuratePlacement: 0 121 | maxJobWorkers: 0 122 | preserveTilesOutsideBounds: 0 123 | debug: 124 | m_Flags: 0 125 | m_NavMeshData: {fileID: 0} 126 | --- !u!1 &77265281 127 | GameObject: 128 | m_ObjectHideFlags: 0 129 | m_CorrespondingSourceObject: {fileID: 0} 130 | m_PrefabInstance: {fileID: 0} 131 | m_PrefabAsset: {fileID: 0} 132 | serializedVersion: 6 133 | m_Component: 134 | - component: {fileID: 77265287} 135 | - component: {fileID: 77265286} 136 | - component: {fileID: 77265285} 137 | - component: {fileID: 77265284} 138 | - component: {fileID: 77265283} 139 | - component: {fileID: 77265282} 140 | - component: {fileID: 77265288} 141 | m_Layer: 5 142 | m_Name: Background 143 | m_TagString: Untagged 144 | m_Icon: {fileID: 0} 145 | m_NavMeshLayer: 0 146 | m_StaticEditorFlags: 0 147 | m_IsActive: 1 148 | --- !u!114 &77265282 149 | MonoBehaviour: 150 | m_ObjectHideFlags: 0 151 | m_CorrespondingSourceObject: {fileID: 0} 152 | m_PrefabInstance: {fileID: 0} 153 | m_PrefabAsset: {fileID: 0} 154 | m_GameObject: {fileID: 77265281} 155 | m_Enabled: 0 156 | m_EditorHideFlags: 0 157 | m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} 158 | m_Name: 159 | m_EditorClassIdentifier: 160 | m_Material: {fileID: 0} 161 | m_Color: {r: 0.5772517, g: 0.80607915, b: 0.8679245, a: 1} 162 | m_RaycastTarget: 1 163 | m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} 164 | m_Maskable: 1 165 | m_OnCullStateChanged: 166 | m_PersistentCalls: 167 | m_Calls: [] 168 | m_Sprite: {fileID: 0} 169 | m_Type: 0 170 | m_PreserveAspect: 0 171 | m_FillCenter: 1 172 | m_FillMethod: 4 173 | m_FillAmount: 1 174 | m_FillClockwise: 1 175 | m_FillOrigin: 0 176 | m_UseSpriteMesh: 0 177 | m_PixelsPerUnitMultiplier: 1 178 | --- !u!222 &77265283 179 | CanvasRenderer: 180 | m_ObjectHideFlags: 0 181 | m_CorrespondingSourceObject: {fileID: 0} 182 | m_PrefabInstance: {fileID: 0} 183 | m_PrefabAsset: {fileID: 0} 184 | m_GameObject: {fileID: 77265281} 185 | m_CullTransparentMesh: 1 186 | --- !u!114 &77265284 187 | MonoBehaviour: 188 | m_ObjectHideFlags: 0 189 | m_CorrespondingSourceObject: {fileID: 0} 190 | m_PrefabInstance: {fileID: 0} 191 | m_PrefabAsset: {fileID: 0} 192 | m_GameObject: {fileID: 77265281} 193 | m_Enabled: 1 194 | m_EditorHideFlags: 0 195 | m_Script: {fileID: 11500000, guid: dc42784cf147c0c48a680349fa168899, type: 3} 196 | m_Name: 197 | m_EditorClassIdentifier: 198 | m_IgnoreReversedGraphics: 1 199 | m_BlockingObjects: 0 200 | m_BlockingMask: 201 | serializedVersion: 2 202 | m_Bits: 4294967295 203 | --- !u!114 &77265285 204 | MonoBehaviour: 205 | m_ObjectHideFlags: 0 206 | m_CorrespondingSourceObject: {fileID: 0} 207 | m_PrefabInstance: {fileID: 0} 208 | m_PrefabAsset: {fileID: 0} 209 | m_GameObject: {fileID: 77265281} 210 | m_Enabled: 1 211 | m_EditorHideFlags: 0 212 | m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3} 213 | m_Name: 214 | m_EditorClassIdentifier: 215 | m_UiScaleMode: 1 216 | m_ReferencePixelsPerUnit: 100 217 | m_ScaleFactor: 1 218 | m_ReferenceResolution: {x: 1280, y: 720} 219 | m_ScreenMatchMode: 0 220 | m_MatchWidthOrHeight: 0 221 | m_PhysicalUnit: 3 222 | m_FallbackScreenDPI: 96 223 | m_DefaultSpriteDPI: 96 224 | m_DynamicPixelsPerUnit: 1 225 | m_PresetInfoIsWorld: 0 226 | --- !u!223 &77265286 227 | Canvas: 228 | m_ObjectHideFlags: 0 229 | m_CorrespondingSourceObject: {fileID: 0} 230 | m_PrefabInstance: {fileID: 0} 231 | m_PrefabAsset: {fileID: 0} 232 | m_GameObject: {fileID: 77265281} 233 | m_Enabled: 1 234 | serializedVersion: 3 235 | m_RenderMode: 0 236 | m_Camera: {fileID: 0} 237 | m_PlaneDistance: 100 238 | m_PixelPerfect: 0 239 | m_ReceivesEvents: 1 240 | m_OverrideSorting: 0 241 | m_OverridePixelPerfect: 0 242 | m_SortingBucketNormalizedSize: 0 243 | m_AdditionalShaderChannelsFlag: 25 244 | m_SortingLayerID: 0 245 | m_SortingOrder: 50 246 | m_TargetDisplay: 0 247 | --- !u!224 &77265287 248 | RectTransform: 249 | m_ObjectHideFlags: 0 250 | m_CorrespondingSourceObject: {fileID: 0} 251 | m_PrefabInstance: {fileID: 0} 252 | m_PrefabAsset: {fileID: 0} 253 | m_GameObject: {fileID: 77265281} 254 | m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} 255 | m_LocalPosition: {x: 0, y: 0, z: 0} 256 | m_LocalScale: {x: 1, y: 1, z: 1} 257 | m_ConstrainProportionsScale: 0 258 | m_Children: 259 | - {fileID: 679253774} 260 | - {fileID: 608654056} 261 | - {fileID: 2094810104} 262 | m_Father: {fileID: 1277999139} 263 | m_RootOrder: 0 264 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 265 | m_AnchorMin: {x: 0, y: 0} 266 | m_AnchorMax: {x: 0, y: 0} 267 | m_AnchoredPosition: {x: 640, y: 360} 268 | m_SizeDelta: {x: 1280, y: 720} 269 | m_Pivot: {x: 0.5, y: 0.5} 270 | --- !u!114 &77265288 271 | MonoBehaviour: 272 | m_ObjectHideFlags: 0 273 | m_CorrespondingSourceObject: {fileID: 0} 274 | m_PrefabInstance: {fileID: 0} 275 | m_PrefabAsset: {fileID: 0} 276 | m_GameObject: {fileID: 77265281} 277 | m_Enabled: 1 278 | m_EditorHideFlags: 0 279 | m_Script: {fileID: 11500000, guid: 03c7b875c5fbb9644b52a00799e95ad2, type: 3} 280 | m_Name: 281 | m_EditorClassIdentifier: 282 | _arrangeLayout: 1 283 | _arrangePreset: 284 | rid: 2461680133902434317 285 | _gridMargin: 286 | Horizontal: 0 287 | Vertical: 0 288 | _scaleMethod: 0 289 | _scalePreset: 290 | rid: 2461680133902434316 291 | _cellPadding: 292 | Horizontal: 0 293 | Vertical: 0 294 | references: 295 | version: 2 296 | RefIds: 297 | - rid: 2461680133902434316 298 | type: {class: ScaleFit, ns: AdaptiveGrid, asm: Assembly-CSharp} 299 | - rid: 2461680133902434317 300 | type: {class: ArrangeGrid, ns: AdaptiveGrid, asm: Assembly-CSharp} 301 | data: 302 | _gridSize: 303 | Rows: 2 304 | Cols: 2 305 | --- !u!1 &229239537 306 | GameObject: 307 | m_ObjectHideFlags: 0 308 | m_CorrespondingSourceObject: {fileID: 0} 309 | m_PrefabInstance: {fileID: 0} 310 | m_PrefabAsset: {fileID: 0} 311 | serializedVersion: 6 312 | m_Component: 313 | - component: {fileID: 229239538} 314 | - component: {fileID: 229239540} 315 | - component: {fileID: 229239539} 316 | m_Layer: 5 317 | m_Name: Content #3 sword 318 | m_TagString: Untagged 319 | m_Icon: {fileID: 0} 320 | m_NavMeshLayer: 0 321 | m_StaticEditorFlags: 0 322 | m_IsActive: 1 323 | --- !u!224 &229239538 324 | RectTransform: 325 | m_ObjectHideFlags: 0 326 | m_CorrespondingSourceObject: {fileID: 0} 327 | m_PrefabInstance: {fileID: 0} 328 | m_PrefabAsset: {fileID: 0} 329 | m_GameObject: {fileID: 229239537} 330 | m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} 331 | m_LocalPosition: {x: 0, y: 0, z: 0} 332 | m_LocalScale: {x: 1, y: 1, z: 1} 333 | m_ConstrainProportionsScale: 0 334 | m_Children: [] 335 | m_Father: {fileID: 531171049} 336 | m_RootOrder: 2 337 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 338 | m_AnchorMin: {x: 0.5, y: 0.5} 339 | m_AnchorMax: {x: 0.5, y: 0.5} 340 | m_AnchoredPosition: {x: -321.34885, y: -172.4835} 341 | m_SizeDelta: {x: 399.95325, y: 314.87546} 342 | m_Pivot: {x: 0.5, y: 0.5} 343 | --- !u!114 &229239539 344 | MonoBehaviour: 345 | m_ObjectHideFlags: 0 346 | m_CorrespondingSourceObject: {fileID: 0} 347 | m_PrefabInstance: {fileID: 0} 348 | m_PrefabAsset: {fileID: 0} 349 | m_GameObject: {fileID: 229239537} 350 | m_Enabled: 1 351 | m_EditorHideFlags: 0 352 | m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} 353 | m_Name: 354 | m_EditorClassIdentifier: 355 | m_Material: {fileID: 0} 356 | m_Color: {r: 1, g: 1, b: 1, a: 1} 357 | m_RaycastTarget: 1 358 | m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} 359 | m_Maskable: 1 360 | m_OnCullStateChanged: 361 | m_PersistentCalls: 362 | m_Calls: [] 363 | m_Sprite: {fileID: 21300000, guid: 9fb23a2eb93ce9d41bba8362a5a229e2, type: 3} 364 | m_Type: 0 365 | m_PreserveAspect: 0 366 | m_FillCenter: 1 367 | m_FillMethod: 4 368 | m_FillAmount: 1 369 | m_FillClockwise: 1 370 | m_FillOrigin: 0 371 | m_UseSpriteMesh: 0 372 | m_PixelsPerUnitMultiplier: 1 373 | --- !u!222 &229239540 374 | CanvasRenderer: 375 | m_ObjectHideFlags: 0 376 | m_CorrespondingSourceObject: {fileID: 0} 377 | m_PrefabInstance: {fileID: 0} 378 | m_PrefabAsset: {fileID: 0} 379 | m_GameObject: {fileID: 229239537} 380 | m_CullTransparentMesh: 1 381 | --- !u!1 &323702428 382 | GameObject: 383 | m_ObjectHideFlags: 0 384 | m_CorrespondingSourceObject: {fileID: 0} 385 | m_PrefabInstance: {fileID: 0} 386 | m_PrefabAsset: {fileID: 0} 387 | serializedVersion: 6 388 | m_Component: 389 | - component: {fileID: 323702429} 390 | - component: {fileID: 323702431} 391 | - component: {fileID: 323702430} 392 | m_Layer: 5 393 | m_Name: Content #6 hammer 394 | m_TagString: Untagged 395 | m_Icon: {fileID: 0} 396 | m_NavMeshLayer: 0 397 | m_StaticEditorFlags: 0 398 | m_IsActive: 1 399 | --- !u!224 &323702429 400 | RectTransform: 401 | m_ObjectHideFlags: 0 402 | m_CorrespondingSourceObject: {fileID: 0} 403 | m_PrefabInstance: {fileID: 0} 404 | m_PrefabAsset: {fileID: 0} 405 | m_GameObject: {fileID: 323702428} 406 | m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} 407 | m_LocalPosition: {x: 0, y: 0, z: 0} 408 | m_LocalScale: {x: 1, y: 1, z: 1} 409 | m_ConstrainProportionsScale: 0 410 | m_Children: [] 411 | m_Father: {fileID: 531171049} 412 | m_RootOrder: 5 413 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 414 | m_AnchorMin: {x: 0.5, y: 0.5} 415 | m_AnchorMax: {x: 0.5, y: 0.5} 416 | m_AnchoredPosition: {x: 321.38284, y: -517.407} 417 | m_SizeDelta: {x: 375.17078, y: 314.87546} 418 | m_Pivot: {x: 0.5, y: 0.5} 419 | --- !u!114 &323702430 420 | MonoBehaviour: 421 | m_ObjectHideFlags: 0 422 | m_CorrespondingSourceObject: {fileID: 0} 423 | m_PrefabInstance: {fileID: 0} 424 | m_PrefabAsset: {fileID: 0} 425 | m_GameObject: {fileID: 323702428} 426 | m_Enabled: 1 427 | m_EditorHideFlags: 0 428 | m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} 429 | m_Name: 430 | m_EditorClassIdentifier: 431 | m_Material: {fileID: 0} 432 | m_Color: {r: 1, g: 1, b: 1, a: 1} 433 | m_RaycastTarget: 1 434 | m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} 435 | m_Maskable: 1 436 | m_OnCullStateChanged: 437 | m_PersistentCalls: 438 | m_Calls: [] 439 | m_Sprite: {fileID: 21300000, guid: 57a15dbce30f4664aa9f57dcb99f7024, type: 3} 440 | m_Type: 0 441 | m_PreserveAspect: 0 442 | m_FillCenter: 1 443 | m_FillMethod: 4 444 | m_FillAmount: 1 445 | m_FillClockwise: 1 446 | m_FillOrigin: 0 447 | m_UseSpriteMesh: 0 448 | m_PixelsPerUnitMultiplier: 1 449 | --- !u!222 &323702431 450 | CanvasRenderer: 451 | m_ObjectHideFlags: 0 452 | m_CorrespondingSourceObject: {fileID: 0} 453 | m_PrefabInstance: {fileID: 0} 454 | m_PrefabAsset: {fileID: 0} 455 | m_GameObject: {fileID: 323702428} 456 | m_CullTransparentMesh: 1 457 | --- !u!1 &531171048 458 | GameObject: 459 | m_ObjectHideFlags: 0 460 | m_CorrespondingSourceObject: {fileID: 0} 461 | m_PrefabInstance: {fileID: 0} 462 | m_PrefabAsset: {fileID: 0} 463 | serializedVersion: 6 464 | m_Component: 465 | - component: {fileID: 531171049} 466 | - component: {fileID: 531171051} 467 | - component: {fileID: 531171053} 468 | - component: {fileID: 531171052} 469 | m_Layer: 5 470 | m_Name: Adaptive Grid 471 | m_TagString: Untagged 472 | m_Icon: {fileID: 0} 473 | m_NavMeshLayer: 0 474 | m_StaticEditorFlags: 0 475 | m_IsActive: 1 476 | --- !u!224 &531171049 477 | RectTransform: 478 | m_ObjectHideFlags: 0 479 | m_CorrespondingSourceObject: {fileID: 0} 480 | m_PrefabInstance: {fileID: 0} 481 | m_PrefabAsset: {fileID: 0} 482 | m_GameObject: {fileID: 531171048} 483 | m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} 484 | m_LocalPosition: {x: 0, y: 0, z: 0} 485 | m_LocalScale: {x: 1, y: 1, z: 1} 486 | m_ConstrainProportionsScale: 1 487 | m_Children: 488 | - {fileID: 693137559} 489 | - {fileID: 1147107959} 490 | - {fileID: 229239538} 491 | - {fileID: 755964473} 492 | - {fileID: 2015537180} 493 | - {fileID: 323702429} 494 | - {fileID: 1440656156} 495 | - {fileID: 1809307107} 496 | - {fileID: 1096037099} 497 | - {fileID: 715240613} 498 | m_Father: {fileID: 1277999139} 499 | m_RootOrder: 2 500 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 501 | m_AnchorMin: {x: 0, y: 0} 502 | m_AnchorMax: {x: 1, y: 1} 503 | m_AnchoredPosition: {x: 21.8925, y: 0} 504 | m_SizeDelta: {x: 43.7852, y: 0} 505 | m_Pivot: {x: 0.5, y: 0.5} 506 | --- !u!114 &531171051 507 | MonoBehaviour: 508 | m_ObjectHideFlags: 0 509 | m_CorrespondingSourceObject: {fileID: 0} 510 | m_PrefabInstance: {fileID: 0} 511 | m_PrefabAsset: {fileID: 0} 512 | m_GameObject: {fileID: 531171048} 513 | m_Enabled: 1 514 | m_EditorHideFlags: 0 515 | m_Script: {fileID: 11500000, guid: 03c7b875c5fbb9644b52a00799e95ad2, type: 3} 516 | m_Name: 517 | m_EditorClassIdentifier: 518 | _arrangeLayout: 1 519 | _arrangePreset: 520 | rid: 2461680133902434321 521 | _gridMargin: 522 | Horizontal: 0.029 523 | Vertical: 0.042 524 | _scaleMethod: 0 525 | _scalePreset: 526 | rid: 2461680133902434305 527 | _cellPadding: 528 | Horizontal: 0.068 529 | Vertical: 0.087 530 | references: 531 | version: 2 532 | RefIds: 533 | - rid: 2461680133902434305 534 | type: {class: ScaleFit, ns: AdaptiveGrid, asm: Assembly-CSharp} 535 | - rid: 2461680133902434321 536 | type: {class: ArrangeGrid, ns: AdaptiveGrid, asm: Assembly-CSharp} 537 | data: 538 | _gridSize: 539 | Rows: 2 540 | Cols: 2 541 | --- !u!114 &531171052 542 | MonoBehaviour: 543 | m_ObjectHideFlags: 0 544 | m_CorrespondingSourceObject: {fileID: 0} 545 | m_PrefabInstance: {fileID: 0} 546 | m_PrefabAsset: {fileID: 0} 547 | m_GameObject: {fileID: 531171048} 548 | m_Enabled: 1 549 | m_EditorHideFlags: 0 550 | m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} 551 | m_Name: 552 | m_EditorClassIdentifier: 553 | m_Material: {fileID: 0} 554 | m_Color: {r: 1, g: 1, b: 1, a: 1} 555 | m_RaycastTarget: 1 556 | m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} 557 | m_Maskable: 1 558 | m_OnCullStateChanged: 559 | m_PersistentCalls: 560 | m_Calls: [] 561 | m_Sprite: {fileID: 0} 562 | m_Type: 0 563 | m_PreserveAspect: 0 564 | m_FillCenter: 1 565 | m_FillMethod: 4 566 | m_FillAmount: 1 567 | m_FillClockwise: 1 568 | m_FillOrigin: 0 569 | m_UseSpriteMesh: 0 570 | m_PixelsPerUnitMultiplier: 1 571 | --- !u!222 &531171053 572 | CanvasRenderer: 573 | m_ObjectHideFlags: 0 574 | m_CorrespondingSourceObject: {fileID: 0} 575 | m_PrefabInstance: {fileID: 0} 576 | m_PrefabAsset: {fileID: 0} 577 | m_GameObject: {fileID: 531171048} 578 | m_CullTransparentMesh: 1 579 | --- !u!1 &608654055 580 | GameObject: 581 | m_ObjectHideFlags: 0 582 | m_CorrespondingSourceObject: {fileID: 0} 583 | m_PrefabInstance: {fileID: 0} 584 | m_PrefabAsset: {fileID: 0} 585 | serializedVersion: 6 586 | m_Component: 587 | - component: {fileID: 608654056} 588 | - component: {fileID: 608654058} 589 | - component: {fileID: 608654057} 590 | m_Layer: 5 591 | m_Name: Title 592 | m_TagString: Untagged 593 | m_Icon: {fileID: 0} 594 | m_NavMeshLayer: 0 595 | m_StaticEditorFlags: 0 596 | m_IsActive: 1 597 | --- !u!224 &608654056 598 | RectTransform: 599 | m_ObjectHideFlags: 0 600 | m_CorrespondingSourceObject: {fileID: 0} 601 | m_PrefabInstance: {fileID: 0} 602 | m_PrefabAsset: {fileID: 0} 603 | m_GameObject: {fileID: 608654055} 604 | m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} 605 | m_LocalPosition: {x: 0, y: 0, z: 0} 606 | m_LocalScale: {x: 1, y: 1, z: 1} 607 | m_ConstrainProportionsScale: 0 608 | m_Children: [] 609 | m_Father: {fileID: 77265287} 610 | m_RootOrder: 1 611 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 612 | m_AnchorMin: {x: 0.5, y: 0.5} 613 | m_AnchorMax: {x: 0.5, y: 0.5} 614 | m_AnchoredPosition: {x: 320, y: 180} 615 | m_SizeDelta: {x: 640, y: 360} 616 | m_Pivot: {x: 0.5, y: 0.5} 617 | --- !u!114 &608654057 618 | MonoBehaviour: 619 | m_ObjectHideFlags: 0 620 | m_CorrespondingSourceObject: {fileID: 0} 621 | m_PrefabInstance: {fileID: 0} 622 | m_PrefabAsset: {fileID: 0} 623 | m_GameObject: {fileID: 608654055} 624 | m_Enabled: 1 625 | m_EditorHideFlags: 0 626 | m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} 627 | m_Name: 628 | m_EditorClassIdentifier: 629 | m_Material: {fileID: 0} 630 | m_Color: {r: 0.2, g: 0.2, b: 0.2, a: 1} 631 | m_RaycastTarget: 1 632 | m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} 633 | m_Maskable: 1 634 | m_OnCullStateChanged: 635 | m_PersistentCalls: 636 | m_Calls: [] 637 | m_FontData: 638 | m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} 639 | m_FontSize: 30 640 | m_FontStyle: 0 641 | m_BestFit: 0 642 | m_MinSize: 0 643 | m_MaxSize: 60 644 | m_Alignment: 6 645 | m_AlignByGeometry: 0 646 | m_RichText: 1 647 | m_HorizontalOverflow: 0 648 | m_VerticalOverflow: 0 649 | m_LineSpacing: 1 650 | m_Text: Screenspace 651 | --- !u!222 &608654058 652 | CanvasRenderer: 653 | m_ObjectHideFlags: 0 654 | m_CorrespondingSourceObject: {fileID: 0} 655 | m_PrefabInstance: {fileID: 0} 656 | m_PrefabAsset: {fileID: 0} 657 | m_GameObject: {fileID: 608654055} 658 | m_CullTransparentMesh: 1 659 | --- !u!1 &679253773 660 | GameObject: 661 | m_ObjectHideFlags: 0 662 | m_CorrespondingSourceObject: {fileID: 0} 663 | m_PrefabInstance: {fileID: 0} 664 | m_PrefabAsset: {fileID: 0} 665 | serializedVersion: 6 666 | m_Component: 667 | - component: {fileID: 679253774} 668 | - component: {fileID: 679253776} 669 | - component: {fileID: 679253775} 670 | m_Layer: 5 671 | m_Name: Adaptive Grid (1) 672 | m_TagString: Untagged 673 | m_Icon: {fileID: 0} 674 | m_NavMeshLayer: 0 675 | m_StaticEditorFlags: 0 676 | m_IsActive: 0 677 | --- !u!224 &679253774 678 | RectTransform: 679 | m_ObjectHideFlags: 0 680 | m_CorrespondingSourceObject: {fileID: 0} 681 | m_PrefabInstance: {fileID: 0} 682 | m_PrefabAsset: {fileID: 0} 683 | m_GameObject: {fileID: 679253773} 684 | m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} 685 | m_LocalPosition: {x: 0, y: 0, z: 0} 686 | m_LocalScale: {x: 1, y: 1, z: 1} 687 | m_ConstrainProportionsScale: 1 688 | m_Children: [] 689 | m_Father: {fileID: 77265287} 690 | m_RootOrder: 0 691 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 692 | m_AnchorMin: {x: 0.5, y: 0.5} 693 | m_AnchorMax: {x: 0.5, y: 0.5} 694 | m_AnchoredPosition: {x: -320, y: 180} 695 | m_SizeDelta: {x: 640, y: 360} 696 | m_Pivot: {x: 0.5, y: 0.5} 697 | --- !u!114 &679253775 698 | MonoBehaviour: 699 | m_ObjectHideFlags: 0 700 | m_CorrespondingSourceObject: {fileID: 0} 701 | m_PrefabInstance: {fileID: 0} 702 | m_PrefabAsset: {fileID: 0} 703 | m_GameObject: {fileID: 679253773} 704 | m_Enabled: 1 705 | m_EditorHideFlags: 0 706 | m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} 707 | m_Name: 708 | m_EditorClassIdentifier: 709 | m_Material: {fileID: 0} 710 | m_Color: {r: 1, g: 1, b: 1, a: 1} 711 | m_RaycastTarget: 1 712 | m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} 713 | m_Maskable: 1 714 | m_OnCullStateChanged: 715 | m_PersistentCalls: 716 | m_Calls: [] 717 | m_Sprite: {fileID: 0} 718 | m_Type: 0 719 | m_PreserveAspect: 0 720 | m_FillCenter: 1 721 | m_FillMethod: 4 722 | m_FillAmount: 1 723 | m_FillClockwise: 1 724 | m_FillOrigin: 0 725 | m_UseSpriteMesh: 0 726 | m_PixelsPerUnitMultiplier: 1 727 | --- !u!222 &679253776 728 | CanvasRenderer: 729 | m_ObjectHideFlags: 0 730 | m_CorrespondingSourceObject: {fileID: 0} 731 | m_PrefabInstance: {fileID: 0} 732 | m_PrefabAsset: {fileID: 0} 733 | m_GameObject: {fileID: 679253773} 734 | m_CullTransparentMesh: 1 735 | --- !u!1 &693137558 736 | GameObject: 737 | m_ObjectHideFlags: 0 738 | m_CorrespondingSourceObject: {fileID: 0} 739 | m_PrefabInstance: {fileID: 0} 740 | m_PrefabAsset: {fileID: 0} 741 | serializedVersion: 6 742 | m_Component: 743 | - component: {fileID: 693137559} 744 | - component: {fileID: 693137561} 745 | - component: {fileID: 693137560} 746 | m_Layer: 5 747 | m_Name: Content #1 sword 748 | m_TagString: Untagged 749 | m_Icon: {fileID: 0} 750 | m_NavMeshLayer: 0 751 | m_StaticEditorFlags: 0 752 | m_IsActive: 1 753 | --- !u!224 &693137559 754 | RectTransform: 755 | m_ObjectHideFlags: 0 756 | m_CorrespondingSourceObject: {fileID: 0} 757 | m_PrefabInstance: {fileID: 0} 758 | m_PrefabAsset: {fileID: 0} 759 | m_GameObject: {fileID: 693137558} 760 | m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} 761 | m_LocalPosition: {x: 0, y: 0, z: 0} 762 | m_LocalScale: {x: 1, y: 1, z: 1} 763 | m_ConstrainProportionsScale: 0 764 | m_Children: [] 765 | m_Father: {fileID: 531171049} 766 | m_RootOrder: 0 767 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 768 | m_AnchorMin: {x: 0.5, y: 0.5} 769 | m_AnchorMax: {x: 0.5, y: 0.5} 770 | m_AnchoredPosition: {x: -321.34885, y: 172.44} 771 | m_SizeDelta: {x: 409.96606, y: 314.87546} 772 | m_Pivot: {x: 0.5, y: 0.5} 773 | --- !u!114 &693137560 774 | MonoBehaviour: 775 | m_ObjectHideFlags: 0 776 | m_CorrespondingSourceObject: {fileID: 0} 777 | m_PrefabInstance: {fileID: 0} 778 | m_PrefabAsset: {fileID: 0} 779 | m_GameObject: {fileID: 693137558} 780 | m_Enabled: 1 781 | m_EditorHideFlags: 0 782 | m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} 783 | m_Name: 784 | m_EditorClassIdentifier: 785 | m_Material: {fileID: 0} 786 | m_Color: {r: 1, g: 1, b: 1, a: 1} 787 | m_RaycastTarget: 1 788 | m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} 789 | m_Maskable: 1 790 | m_OnCullStateChanged: 791 | m_PersistentCalls: 792 | m_Calls: [] 793 | m_Sprite: {fileID: 21300000, guid: 61d09ce1089b0e742ac90e4e668a747f, type: 3} 794 | m_Type: 0 795 | m_PreserveAspect: 0 796 | m_FillCenter: 1 797 | m_FillMethod: 4 798 | m_FillAmount: 1 799 | m_FillClockwise: 1 800 | m_FillOrigin: 0 801 | m_UseSpriteMesh: 0 802 | m_PixelsPerUnitMultiplier: 1 803 | --- !u!222 &693137561 804 | CanvasRenderer: 805 | m_ObjectHideFlags: 0 806 | m_CorrespondingSourceObject: {fileID: 0} 807 | m_PrefabInstance: {fileID: 0} 808 | m_PrefabAsset: {fileID: 0} 809 | m_GameObject: {fileID: 693137558} 810 | m_CullTransparentMesh: 1 811 | --- !u!1 &715240612 812 | GameObject: 813 | m_ObjectHideFlags: 0 814 | m_CorrespondingSourceObject: {fileID: 0} 815 | m_PrefabInstance: {fileID: 0} 816 | m_PrefabAsset: {fileID: 0} 817 | serializedVersion: 6 818 | m_Component: 819 | - component: {fileID: 715240613} 820 | - component: {fileID: 715240615} 821 | - component: {fileID: 715240614} 822 | m_Layer: 5 823 | m_Name: Content #10 helmet 824 | m_TagString: Untagged 825 | m_Icon: {fileID: 0} 826 | m_NavMeshLayer: 0 827 | m_StaticEditorFlags: 0 828 | m_IsActive: 1 829 | --- !u!224 &715240613 830 | RectTransform: 831 | m_ObjectHideFlags: 0 832 | m_CorrespondingSourceObject: {fileID: 0} 833 | m_PrefabInstance: {fileID: 0} 834 | m_PrefabAsset: {fileID: 0} 835 | m_GameObject: {fileID: 715240612} 836 | m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} 837 | m_LocalPosition: {x: 0, y: 0, z: 0} 838 | m_LocalScale: {x: 1, y: 1, z: 1} 839 | m_ConstrainProportionsScale: 0 840 | m_Children: [] 841 | m_Father: {fileID: 531171049} 842 | m_RootOrder: 9 843 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 844 | m_AnchorMin: {x: 0.5, y: 0.5} 845 | m_AnchorMax: {x: 0.5, y: 0.5} 846 | m_AnchoredPosition: {x: 321.38284, y: -1207.254} 847 | m_SizeDelta: {x: 211.3788, y: 314.87546} 848 | m_Pivot: {x: 0.5, y: 0.5} 849 | --- !u!114 &715240614 850 | MonoBehaviour: 851 | m_ObjectHideFlags: 0 852 | m_CorrespondingSourceObject: {fileID: 0} 853 | m_PrefabInstance: {fileID: 0} 854 | m_PrefabAsset: {fileID: 0} 855 | m_GameObject: {fileID: 715240612} 856 | m_Enabled: 1 857 | m_EditorHideFlags: 0 858 | m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} 859 | m_Name: 860 | m_EditorClassIdentifier: 861 | m_Material: {fileID: 0} 862 | m_Color: {r: 1, g: 1, b: 1, a: 1} 863 | m_RaycastTarget: 1 864 | m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} 865 | m_Maskable: 1 866 | m_OnCullStateChanged: 867 | m_PersistentCalls: 868 | m_Calls: [] 869 | m_Sprite: {fileID: 21300000, guid: 7d74ddbb2c5f8584e8a04c79d8ad75bf, type: 3} 870 | m_Type: 0 871 | m_PreserveAspect: 0 872 | m_FillCenter: 1 873 | m_FillMethod: 4 874 | m_FillAmount: 1 875 | m_FillClockwise: 1 876 | m_FillOrigin: 0 877 | m_UseSpriteMesh: 0 878 | m_PixelsPerUnitMultiplier: 1 879 | --- !u!222 &715240615 880 | CanvasRenderer: 881 | m_ObjectHideFlags: 0 882 | m_CorrespondingSourceObject: {fileID: 0} 883 | m_PrefabInstance: {fileID: 0} 884 | m_PrefabAsset: {fileID: 0} 885 | m_GameObject: {fileID: 715240612} 886 | m_CullTransparentMesh: 1 887 | --- !u!1 &755964472 888 | GameObject: 889 | m_ObjectHideFlags: 0 890 | m_CorrespondingSourceObject: {fileID: 0} 891 | m_PrefabInstance: {fileID: 0} 892 | m_PrefabAsset: {fileID: 0} 893 | serializedVersion: 6 894 | m_Component: 895 | - component: {fileID: 755964473} 896 | - component: {fileID: 755964475} 897 | - component: {fileID: 755964474} 898 | m_Layer: 5 899 | m_Name: Content #4 sword 900 | m_TagString: Untagged 901 | m_Icon: {fileID: 0} 902 | m_NavMeshLayer: 0 903 | m_StaticEditorFlags: 0 904 | m_IsActive: 1 905 | --- !u!224 &755964473 906 | RectTransform: 907 | m_ObjectHideFlags: 0 908 | m_CorrespondingSourceObject: {fileID: 0} 909 | m_PrefabInstance: {fileID: 0} 910 | m_PrefabAsset: {fileID: 0} 911 | m_GameObject: {fileID: 755964472} 912 | m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} 913 | m_LocalPosition: {x: 0, y: 0, z: 0} 914 | m_LocalScale: {x: 1, y: 1, z: 1} 915 | m_ConstrainProportionsScale: 0 916 | m_Children: [] 917 | m_Father: {fileID: 531171049} 918 | m_RootOrder: 3 919 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 920 | m_AnchorMin: {x: 0.5, y: 0.5} 921 | m_AnchorMax: {x: 0.5, y: 0.5} 922 | m_AnchoredPosition: {x: 321.38284, y: -172.4835} 923 | m_SizeDelta: {x: 386.5479, y: 314.87546} 924 | m_Pivot: {x: 0.5, y: 0.5} 925 | --- !u!114 &755964474 926 | MonoBehaviour: 927 | m_ObjectHideFlags: 0 928 | m_CorrespondingSourceObject: {fileID: 0} 929 | m_PrefabInstance: {fileID: 0} 930 | m_PrefabAsset: {fileID: 0} 931 | m_GameObject: {fileID: 755964472} 932 | m_Enabled: 1 933 | m_EditorHideFlags: 0 934 | m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} 935 | m_Name: 936 | m_EditorClassIdentifier: 937 | m_Material: {fileID: 0} 938 | m_Color: {r: 1, g: 1, b: 1, a: 1} 939 | m_RaycastTarget: 1 940 | m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} 941 | m_Maskable: 1 942 | m_OnCullStateChanged: 943 | m_PersistentCalls: 944 | m_Calls: [] 945 | m_Sprite: {fileID: 21300000, guid: 2a3ec684c0f15a34fa31648033956745, type: 3} 946 | m_Type: 0 947 | m_PreserveAspect: 0 948 | m_FillCenter: 1 949 | m_FillMethod: 4 950 | m_FillAmount: 1 951 | m_FillClockwise: 1 952 | m_FillOrigin: 0 953 | m_UseSpriteMesh: 0 954 | m_PixelsPerUnitMultiplier: 1 955 | --- !u!222 &755964475 956 | CanvasRenderer: 957 | m_ObjectHideFlags: 0 958 | m_CorrespondingSourceObject: {fileID: 0} 959 | m_PrefabInstance: {fileID: 0} 960 | m_PrefabAsset: {fileID: 0} 961 | m_GameObject: {fileID: 755964472} 962 | m_CullTransparentMesh: 1 963 | --- !u!1 &1096037098 964 | GameObject: 965 | m_ObjectHideFlags: 0 966 | m_CorrespondingSourceObject: {fileID: 0} 967 | m_PrefabInstance: {fileID: 0} 968 | m_PrefabAsset: {fileID: 0} 969 | serializedVersion: 6 970 | m_Component: 971 | - component: {fileID: 1096037099} 972 | - component: {fileID: 1096037101} 973 | - component: {fileID: 1096037100} 974 | m_Layer: 5 975 | m_Name: Content #9 sword (1 976 | m_TagString: Untagged 977 | m_Icon: {fileID: 0} 978 | m_NavMeshLayer: 0 979 | m_StaticEditorFlags: 0 980 | m_IsActive: 1 981 | --- !u!224 &1096037099 982 | RectTransform: 983 | m_ObjectHideFlags: 0 984 | m_CorrespondingSourceObject: {fileID: 0} 985 | m_PrefabInstance: {fileID: 0} 986 | m_PrefabAsset: {fileID: 0} 987 | m_GameObject: {fileID: 1096037098} 988 | m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} 989 | m_LocalPosition: {x: 0, y: 0, z: 0} 990 | m_LocalScale: {x: 1, y: 1, z: 1} 991 | m_ConstrainProportionsScale: 0 992 | m_Children: [] 993 | m_Father: {fileID: 531171049} 994 | m_RootOrder: 8 995 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 996 | m_AnchorMin: {x: 0.5, y: 0.5} 997 | m_AnchorMax: {x: 0.5, y: 0.5} 998 | m_AnchoredPosition: {x: -321.34885, y: -1207.254} 999 | m_SizeDelta: {x: 393.17783, y: 314.87546} 1000 | m_Pivot: {x: 0.5, y: 0.5} 1001 | --- !u!114 &1096037100 1002 | MonoBehaviour: 1003 | m_ObjectHideFlags: 0 1004 | m_CorrespondingSourceObject: {fileID: 0} 1005 | m_PrefabInstance: {fileID: 0} 1006 | m_PrefabAsset: {fileID: 0} 1007 | m_GameObject: {fileID: 1096037098} 1008 | m_Enabled: 1 1009 | m_EditorHideFlags: 0 1010 | m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} 1011 | m_Name: 1012 | m_EditorClassIdentifier: 1013 | m_Material: {fileID: 0} 1014 | m_Color: {r: 1, g: 1, b: 1, a: 1} 1015 | m_RaycastTarget: 1 1016 | m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} 1017 | m_Maskable: 1 1018 | m_OnCullStateChanged: 1019 | m_PersistentCalls: 1020 | m_Calls: [] 1021 | m_Sprite: {fileID: 21300000, guid: 5b9f83babe8e4084587b595e026ef9e2, type: 3} 1022 | m_Type: 0 1023 | m_PreserveAspect: 0 1024 | m_FillCenter: 1 1025 | m_FillMethod: 4 1026 | m_FillAmount: 1 1027 | m_FillClockwise: 1 1028 | m_FillOrigin: 0 1029 | m_UseSpriteMesh: 0 1030 | m_PixelsPerUnitMultiplier: 1 1031 | --- !u!222 &1096037101 1032 | CanvasRenderer: 1033 | m_ObjectHideFlags: 0 1034 | m_CorrespondingSourceObject: {fileID: 0} 1035 | m_PrefabInstance: {fileID: 0} 1036 | m_PrefabAsset: {fileID: 0} 1037 | m_GameObject: {fileID: 1096037098} 1038 | m_CullTransparentMesh: 1 1039 | --- !u!1 &1147107958 1040 | GameObject: 1041 | m_ObjectHideFlags: 0 1042 | m_CorrespondingSourceObject: {fileID: 0} 1043 | m_PrefabInstance: {fileID: 0} 1044 | m_PrefabAsset: {fileID: 0} 1045 | serializedVersion: 6 1046 | m_Component: 1047 | - component: {fileID: 1147107959} 1048 | - component: {fileID: 1147107961} 1049 | - component: {fileID: 1147107960} 1050 | m_Layer: 5 1051 | m_Name: Content #2 drum 1052 | m_TagString: Untagged 1053 | m_Icon: {fileID: 0} 1054 | m_NavMeshLayer: 0 1055 | m_StaticEditorFlags: 0 1056 | m_IsActive: 1 1057 | --- !u!224 &1147107959 1058 | RectTransform: 1059 | m_ObjectHideFlags: 0 1060 | m_CorrespondingSourceObject: {fileID: 0} 1061 | m_PrefabInstance: {fileID: 0} 1062 | m_PrefabAsset: {fileID: 0} 1063 | m_GameObject: {fileID: 1147107958} 1064 | m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} 1065 | m_LocalPosition: {x: 0, y: 0, z: 0} 1066 | m_LocalScale: {x: 1, y: 1, z: 1} 1067 | m_ConstrainProportionsScale: 0 1068 | m_Children: [] 1069 | m_Father: {fileID: 531171049} 1070 | m_RootOrder: 1 1071 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 1072 | m_AnchorMin: {x: 0.5, y: 0.5} 1073 | m_AnchorMax: {x: 0.5, y: 0.5} 1074 | m_AnchoredPosition: {x: 321.38284, y: 172.44} 1075 | m_SizeDelta: {x: 439.36108, y: 314.87546} 1076 | m_Pivot: {x: 0.5, y: 0.5} 1077 | --- !u!114 &1147107960 1078 | MonoBehaviour: 1079 | m_ObjectHideFlags: 0 1080 | m_CorrespondingSourceObject: {fileID: 0} 1081 | m_PrefabInstance: {fileID: 0} 1082 | m_PrefabAsset: {fileID: 0} 1083 | m_GameObject: {fileID: 1147107958} 1084 | m_Enabled: 1 1085 | m_EditorHideFlags: 0 1086 | m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} 1087 | m_Name: 1088 | m_EditorClassIdentifier: 1089 | m_Material: {fileID: 0} 1090 | m_Color: {r: 1, g: 1, b: 1, a: 1} 1091 | m_RaycastTarget: 1 1092 | m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} 1093 | m_Maskable: 1 1094 | m_OnCullStateChanged: 1095 | m_PersistentCalls: 1096 | m_Calls: [] 1097 | m_Sprite: {fileID: 21300000, guid: 51d7754992ca4d447a2e3b02523458cd, type: 3} 1098 | m_Type: 0 1099 | m_PreserveAspect: 0 1100 | m_FillCenter: 1 1101 | m_FillMethod: 4 1102 | m_FillAmount: 1 1103 | m_FillClockwise: 1 1104 | m_FillOrigin: 0 1105 | m_UseSpriteMesh: 0 1106 | m_PixelsPerUnitMultiplier: 1 1107 | --- !u!222 &1147107961 1108 | CanvasRenderer: 1109 | m_ObjectHideFlags: 0 1110 | m_CorrespondingSourceObject: {fileID: 0} 1111 | m_PrefabInstance: {fileID: 0} 1112 | m_PrefabAsset: {fileID: 0} 1113 | m_GameObject: {fileID: 1147107958} 1114 | m_CullTransparentMesh: 1 1115 | --- !u!1 &1277999133 1116 | GameObject: 1117 | m_ObjectHideFlags: 0 1118 | m_CorrespondingSourceObject: {fileID: 0} 1119 | m_PrefabInstance: {fileID: 0} 1120 | m_PrefabAsset: {fileID: 0} 1121 | serializedVersion: 6 1122 | m_Component: 1123 | - component: {fileID: 1277999139} 1124 | - component: {fileID: 1277999138} 1125 | - component: {fileID: 1277999137} 1126 | - component: {fileID: 1277999136} 1127 | - component: {fileID: 1277999135} 1128 | - component: {fileID: 1277999134} 1129 | m_Layer: 5 1130 | m_Name: 'Canvas ' 1131 | m_TagString: Untagged 1132 | m_Icon: {fileID: 0} 1133 | m_NavMeshLayer: 0 1134 | m_StaticEditorFlags: 0 1135 | m_IsActive: 1 1136 | --- !u!114 &1277999134 1137 | MonoBehaviour: 1138 | m_ObjectHideFlags: 0 1139 | m_CorrespondingSourceObject: {fileID: 0} 1140 | m_PrefabInstance: {fileID: 0} 1141 | m_PrefabAsset: {fileID: 0} 1142 | m_GameObject: {fileID: 1277999133} 1143 | m_Enabled: 1 1144 | m_EditorHideFlags: 0 1145 | m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} 1146 | m_Name: 1147 | m_EditorClassIdentifier: 1148 | m_Material: {fileID: 0} 1149 | m_Color: {r: 0.5772517, g: 0.80607915, b: 0.8679245, a: 1} 1150 | m_RaycastTarget: 1 1151 | m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} 1152 | m_Maskable: 1 1153 | m_OnCullStateChanged: 1154 | m_PersistentCalls: 1155 | m_Calls: [] 1156 | m_Sprite: {fileID: 0} 1157 | m_Type: 0 1158 | m_PreserveAspect: 0 1159 | m_FillCenter: 1 1160 | m_FillMethod: 4 1161 | m_FillAmount: 1 1162 | m_FillClockwise: 1 1163 | m_FillOrigin: 0 1164 | m_UseSpriteMesh: 0 1165 | m_PixelsPerUnitMultiplier: 1 1166 | --- !u!222 &1277999135 1167 | CanvasRenderer: 1168 | m_ObjectHideFlags: 0 1169 | m_CorrespondingSourceObject: {fileID: 0} 1170 | m_PrefabInstance: {fileID: 0} 1171 | m_PrefabAsset: {fileID: 0} 1172 | m_GameObject: {fileID: 1277999133} 1173 | m_CullTransparentMesh: 1 1174 | --- !u!114 &1277999136 1175 | MonoBehaviour: 1176 | m_ObjectHideFlags: 0 1177 | m_CorrespondingSourceObject: {fileID: 0} 1178 | m_PrefabInstance: {fileID: 0} 1179 | m_PrefabAsset: {fileID: 0} 1180 | m_GameObject: {fileID: 1277999133} 1181 | m_Enabled: 1 1182 | m_EditorHideFlags: 0 1183 | m_Script: {fileID: 11500000, guid: dc42784cf147c0c48a680349fa168899, type: 3} 1184 | m_Name: 1185 | m_EditorClassIdentifier: 1186 | m_IgnoreReversedGraphics: 1 1187 | m_BlockingObjects: 0 1188 | m_BlockingMask: 1189 | serializedVersion: 2 1190 | m_Bits: 4294967295 1191 | --- !u!114 &1277999137 1192 | MonoBehaviour: 1193 | m_ObjectHideFlags: 0 1194 | m_CorrespondingSourceObject: {fileID: 0} 1195 | m_PrefabInstance: {fileID: 0} 1196 | m_PrefabAsset: {fileID: 0} 1197 | m_GameObject: {fileID: 1277999133} 1198 | m_Enabled: 1 1199 | m_EditorHideFlags: 0 1200 | m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3} 1201 | m_Name: 1202 | m_EditorClassIdentifier: 1203 | m_UiScaleMode: 1 1204 | m_ReferencePixelsPerUnit: 100 1205 | m_ScaleFactor: 1 1206 | m_ReferenceResolution: {x: 1280, y: 720} 1207 | m_ScreenMatchMode: 0 1208 | m_MatchWidthOrHeight: 0 1209 | m_PhysicalUnit: 3 1210 | m_FallbackScreenDPI: 96 1211 | m_DefaultSpriteDPI: 96 1212 | m_DynamicPixelsPerUnit: 1 1213 | m_PresetInfoIsWorld: 0 1214 | --- !u!223 &1277999138 1215 | Canvas: 1216 | m_ObjectHideFlags: 0 1217 | m_CorrespondingSourceObject: {fileID: 0} 1218 | m_PrefabInstance: {fileID: 0} 1219 | m_PrefabAsset: {fileID: 0} 1220 | m_GameObject: {fileID: 1277999133} 1221 | m_Enabled: 1 1222 | serializedVersion: 3 1223 | m_RenderMode: 0 1224 | m_Camera: {fileID: 0} 1225 | m_PlaneDistance: 100 1226 | m_PixelPerfect: 0 1227 | m_ReceivesEvents: 1 1228 | m_OverrideSorting: 0 1229 | m_OverridePixelPerfect: 0 1230 | m_SortingBucketNormalizedSize: 0 1231 | m_AdditionalShaderChannelsFlag: 25 1232 | m_SortingLayerID: 0 1233 | m_SortingOrder: -100 1234 | m_TargetDisplay: 0 1235 | --- !u!224 &1277999139 1236 | RectTransform: 1237 | m_ObjectHideFlags: 0 1238 | m_CorrespondingSourceObject: {fileID: 0} 1239 | m_PrefabInstance: {fileID: 0} 1240 | m_PrefabAsset: {fileID: 0} 1241 | m_GameObject: {fileID: 1277999133} 1242 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} 1243 | m_LocalPosition: {x: 0, y: 0, z: 0} 1244 | m_LocalScale: {x: 0, y: 0, z: 0} 1245 | m_ConstrainProportionsScale: 0 1246 | m_Children: 1247 | - {fileID: 77265287} 1248 | - {fileID: 1460980705} 1249 | - {fileID: 531171049} 1250 | m_Father: {fileID: 0} 1251 | m_RootOrder: 0 1252 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 1253 | m_AnchorMin: {x: 0, y: 0} 1254 | m_AnchorMax: {x: 0, y: 0} 1255 | m_AnchoredPosition: {x: 0, y: 0} 1256 | m_SizeDelta: {x: 0, y: 0} 1257 | m_Pivot: {x: 0, y: 0} 1258 | --- !u!1 &1440656155 1259 | GameObject: 1260 | m_ObjectHideFlags: 0 1261 | m_CorrespondingSourceObject: {fileID: 0} 1262 | m_PrefabInstance: {fileID: 0} 1263 | m_PrefabAsset: {fileID: 0} 1264 | serializedVersion: 6 1265 | m_Component: 1266 | - component: {fileID: 1440656156} 1267 | - component: {fileID: 1440656158} 1268 | - component: {fileID: 1440656157} 1269 | m_Layer: 5 1270 | m_Name: Content #7 hammer 1271 | m_TagString: Untagged 1272 | m_Icon: {fileID: 0} 1273 | m_NavMeshLayer: 0 1274 | m_StaticEditorFlags: 0 1275 | m_IsActive: 1 1276 | --- !u!224 &1440656156 1277 | RectTransform: 1278 | m_ObjectHideFlags: 0 1279 | m_CorrespondingSourceObject: {fileID: 0} 1280 | m_PrefabInstance: {fileID: 0} 1281 | m_PrefabAsset: {fileID: 0} 1282 | m_GameObject: {fileID: 1440656155} 1283 | m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} 1284 | m_LocalPosition: {x: 0, y: 0, z: 0} 1285 | m_LocalScale: {x: 1, y: 1, z: 1} 1286 | m_ConstrainProportionsScale: 1 1287 | m_Children: [] 1288 | m_Father: {fileID: 531171049} 1289 | m_RootOrder: 6 1290 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 1291 | m_AnchorMin: {x: 0.5, y: 0.5} 1292 | m_AnchorMax: {x: 0.5, y: 0.5} 1293 | m_AnchoredPosition: {x: -321.34885, y: -862.3305} 1294 | m_SizeDelta: {x: 288.07755, y: 314.87546} 1295 | m_Pivot: {x: 0.5, y: 0.5} 1296 | --- !u!114 &1440656157 1297 | MonoBehaviour: 1298 | m_ObjectHideFlags: 0 1299 | m_CorrespondingSourceObject: {fileID: 0} 1300 | m_PrefabInstance: {fileID: 0} 1301 | m_PrefabAsset: {fileID: 0} 1302 | m_GameObject: {fileID: 1440656155} 1303 | m_Enabled: 1 1304 | m_EditorHideFlags: 0 1305 | m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} 1306 | m_Name: 1307 | m_EditorClassIdentifier: 1308 | m_Material: {fileID: 0} 1309 | m_Color: {r: 1, g: 1, b: 1, a: 1} 1310 | m_RaycastTarget: 1 1311 | m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} 1312 | m_Maskable: 1 1313 | m_OnCullStateChanged: 1314 | m_PersistentCalls: 1315 | m_Calls: [] 1316 | m_Sprite: {fileID: 21300000, guid: 11b725965e7e9b1488bdcd6dd0c56c06, type: 3} 1317 | m_Type: 0 1318 | m_PreserveAspect: 0 1319 | m_FillCenter: 1 1320 | m_FillMethod: 4 1321 | m_FillAmount: 1 1322 | m_FillClockwise: 1 1323 | m_FillOrigin: 0 1324 | m_UseSpriteMesh: 0 1325 | m_PixelsPerUnitMultiplier: 1 1326 | --- !u!222 &1440656158 1327 | CanvasRenderer: 1328 | m_ObjectHideFlags: 0 1329 | m_CorrespondingSourceObject: {fileID: 0} 1330 | m_PrefabInstance: {fileID: 0} 1331 | m_PrefabAsset: {fileID: 0} 1332 | m_GameObject: {fileID: 1440656155} 1333 | m_CullTransparentMesh: 1 1334 | --- !u!1 &1460980701 1335 | GameObject: 1336 | m_ObjectHideFlags: 0 1337 | m_CorrespondingSourceObject: {fileID: 0} 1338 | m_PrefabInstance: {fileID: 0} 1339 | m_PrefabAsset: {fileID: 0} 1340 | serializedVersion: 6 1341 | m_Component: 1342 | - component: {fileID: 1460980705} 1343 | - component: {fileID: 1460980704} 1344 | - component: {fileID: 1460980703} 1345 | - component: {fileID: 1460980702} 1346 | - component: {fileID: 1460980707} 1347 | - component: {fileID: 1460980706} 1348 | - component: {fileID: 1460980708} 1349 | m_Layer: 5 1350 | m_Name: Test Content 1351 | m_TagString: Untagged 1352 | m_Icon: {fileID: 0} 1353 | m_NavMeshLayer: 0 1354 | m_StaticEditorFlags: 0 1355 | m_IsActive: 1 1356 | --- !u!114 &1460980702 1357 | MonoBehaviour: 1358 | m_ObjectHideFlags: 0 1359 | m_CorrespondingSourceObject: {fileID: 0} 1360 | m_PrefabInstance: {fileID: 0} 1361 | m_PrefabAsset: {fileID: 0} 1362 | m_GameObject: {fileID: 1460980701} 1363 | m_Enabled: 1 1364 | m_EditorHideFlags: 0 1365 | m_Script: {fileID: 11500000, guid: dc42784cf147c0c48a680349fa168899, type: 3} 1366 | m_Name: 1367 | m_EditorClassIdentifier: 1368 | m_IgnoreReversedGraphics: 1 1369 | m_BlockingObjects: 0 1370 | m_BlockingMask: 1371 | serializedVersion: 2 1372 | m_Bits: 4294967295 1373 | --- !u!114 &1460980703 1374 | MonoBehaviour: 1375 | m_ObjectHideFlags: 0 1376 | m_CorrespondingSourceObject: {fileID: 0} 1377 | m_PrefabInstance: {fileID: 0} 1378 | m_PrefabAsset: {fileID: 0} 1379 | m_GameObject: {fileID: 1460980701} 1380 | m_Enabled: 1 1381 | m_EditorHideFlags: 0 1382 | m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3} 1383 | m_Name: 1384 | m_EditorClassIdentifier: 1385 | m_UiScaleMode: 1 1386 | m_ReferencePixelsPerUnit: 100 1387 | m_ScaleFactor: 1 1388 | m_ReferenceResolution: {x: 1280, y: 720} 1389 | m_ScreenMatchMode: 0 1390 | m_MatchWidthOrHeight: 0 1391 | m_PhysicalUnit: 3 1392 | m_FallbackScreenDPI: 96 1393 | m_DefaultSpriteDPI: 96 1394 | m_DynamicPixelsPerUnit: 1 1395 | m_PresetInfoIsWorld: 0 1396 | --- !u!223 &1460980704 1397 | Canvas: 1398 | m_ObjectHideFlags: 0 1399 | m_CorrespondingSourceObject: {fileID: 0} 1400 | m_PrefabInstance: {fileID: 0} 1401 | m_PrefabAsset: {fileID: 0} 1402 | m_GameObject: {fileID: 1460980701} 1403 | m_Enabled: 1 1404 | serializedVersion: 3 1405 | m_RenderMode: 0 1406 | m_Camera: {fileID: 0} 1407 | m_PlaneDistance: 100 1408 | m_PixelPerfect: 0 1409 | m_ReceivesEvents: 1 1410 | m_OverrideSorting: 0 1411 | m_OverridePixelPerfect: 0 1412 | m_SortingBucketNormalizedSize: 0 1413 | m_AdditionalShaderChannelsFlag: 25 1414 | m_SortingLayerID: 0 1415 | m_SortingOrder: 100 1416 | m_TargetDisplay: 0 1417 | --- !u!224 &1460980705 1418 | RectTransform: 1419 | m_ObjectHideFlags: 0 1420 | m_CorrespondingSourceObject: {fileID: 0} 1421 | m_PrefabInstance: {fileID: 0} 1422 | m_PrefabAsset: {fileID: 0} 1423 | m_GameObject: {fileID: 1460980701} 1424 | m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} 1425 | m_LocalPosition: {x: 0, y: 0, z: 0} 1426 | m_LocalScale: {x: 1, y: 1, z: 1} 1427 | m_ConstrainProportionsScale: 0 1428 | m_Children: [] 1429 | m_Father: {fileID: 1277999139} 1430 | m_RootOrder: 1 1431 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 1432 | m_AnchorMin: {x: 0, y: 0} 1433 | m_AnchorMax: {x: 0, y: 0} 1434 | m_AnchoredPosition: {x: 640, y: 360} 1435 | m_SizeDelta: {x: 1280, y: 720} 1436 | m_Pivot: {x: 0.5, y: 0.5} 1437 | --- !u!114 &1460980706 1438 | MonoBehaviour: 1439 | m_ObjectHideFlags: 0 1440 | m_CorrespondingSourceObject: {fileID: 0} 1441 | m_PrefabInstance: {fileID: 0} 1442 | m_PrefabAsset: {fileID: 0} 1443 | m_GameObject: {fileID: 1460980701} 1444 | m_Enabled: 0 1445 | m_EditorHideFlags: 0 1446 | m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} 1447 | m_Name: 1448 | m_EditorClassIdentifier: 1449 | m_Material: {fileID: 0} 1450 | m_Color: {r: 0.5772517, g: 0.80607915, b: 0.8679245, a: 1} 1451 | m_RaycastTarget: 1 1452 | m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} 1453 | m_Maskable: 1 1454 | m_OnCullStateChanged: 1455 | m_PersistentCalls: 1456 | m_Calls: [] 1457 | m_Sprite: {fileID: 0} 1458 | m_Type: 0 1459 | m_PreserveAspect: 0 1460 | m_FillCenter: 1 1461 | m_FillMethod: 4 1462 | m_FillAmount: 1 1463 | m_FillClockwise: 1 1464 | m_FillOrigin: 0 1465 | m_UseSpriteMesh: 0 1466 | m_PixelsPerUnitMultiplier: 1 1467 | --- !u!222 &1460980707 1468 | CanvasRenderer: 1469 | m_ObjectHideFlags: 0 1470 | m_CorrespondingSourceObject: {fileID: 0} 1471 | m_PrefabInstance: {fileID: 0} 1472 | m_PrefabAsset: {fileID: 0} 1473 | m_GameObject: {fileID: 1460980701} 1474 | m_CullTransparentMesh: 1 1475 | --- !u!114 &1460980708 1476 | MonoBehaviour: 1477 | m_ObjectHideFlags: 0 1478 | m_CorrespondingSourceObject: {fileID: 0} 1479 | m_PrefabInstance: {fileID: 0} 1480 | m_PrefabAsset: {fileID: 0} 1481 | m_GameObject: {fileID: 1460980701} 1482 | m_Enabled: 1 1483 | m_EditorHideFlags: 0 1484 | m_Script: {fileID: 11500000, guid: 03c7b875c5fbb9644b52a00799e95ad2, type: 3} 1485 | m_Name: 1486 | m_EditorClassIdentifier: 1487 | _arrangeLayout: 0 1488 | _arrangePreset: 1489 | rid: 2461680133902434313 1490 | _gridMargin: 1491 | Horizontal: 0 1492 | Vertical: 0 1493 | _scaleMethod: 0 1494 | _scalePreset: 1495 | rid: 2461680133902434314 1496 | _cellPadding: 1497 | Horizontal: 0 1498 | Vertical: 0 1499 | references: 1500 | version: 2 1501 | RefIds: 1502 | - rid: 2461680133902434313 1503 | type: {class: ArrangeFill, ns: AdaptiveGrid, asm: Assembly-CSharp} 1504 | - rid: 2461680133902434314 1505 | type: {class: ScaleFit, ns: AdaptiveGrid, asm: Assembly-CSharp} 1506 | --- !u!1 &1809307106 1507 | GameObject: 1508 | m_ObjectHideFlags: 0 1509 | m_CorrespondingSourceObject: {fileID: 0} 1510 | m_PrefabInstance: {fileID: 0} 1511 | m_PrefabAsset: {fileID: 0} 1512 | serializedVersion: 6 1513 | m_Component: 1514 | - component: {fileID: 1809307107} 1515 | - component: {fileID: 1809307109} 1516 | - component: {fileID: 1809307108} 1517 | m_Layer: 5 1518 | m_Name: Content #8 hammer 1519 | m_TagString: Untagged 1520 | m_Icon: {fileID: 0} 1521 | m_NavMeshLayer: 0 1522 | m_StaticEditorFlags: 0 1523 | m_IsActive: 1 1524 | --- !u!224 &1809307107 1525 | RectTransform: 1526 | m_ObjectHideFlags: 0 1527 | m_CorrespondingSourceObject: {fileID: 0} 1528 | m_PrefabInstance: {fileID: 0} 1529 | m_PrefabAsset: {fileID: 0} 1530 | m_GameObject: {fileID: 1809307106} 1531 | m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} 1532 | m_LocalPosition: {x: 0, y: 0, z: 0} 1533 | m_LocalScale: {x: 1, y: 1, z: 1} 1534 | m_ConstrainProportionsScale: 0 1535 | m_Children: [] 1536 | m_Father: {fileID: 531171049} 1537 | m_RootOrder: 7 1538 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 1539 | m_AnchorMin: {x: 0.5, y: 0.5} 1540 | m_AnchorMax: {x: 0.5, y: 0.5} 1541 | m_AnchoredPosition: {x: 321.38284, y: -862.3305} 1542 | m_SizeDelta: {x: 363.85605, y: 314.87546} 1543 | m_Pivot: {x: 0.5, y: 0.5} 1544 | --- !u!114 &1809307108 1545 | MonoBehaviour: 1546 | m_ObjectHideFlags: 0 1547 | m_CorrespondingSourceObject: {fileID: 0} 1548 | m_PrefabInstance: {fileID: 0} 1549 | m_PrefabAsset: {fileID: 0} 1550 | m_GameObject: {fileID: 1809307106} 1551 | m_Enabled: 1 1552 | m_EditorHideFlags: 0 1553 | m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} 1554 | m_Name: 1555 | m_EditorClassIdentifier: 1556 | m_Material: {fileID: 0} 1557 | m_Color: {r: 1, g: 1, b: 1, a: 1} 1558 | m_RaycastTarget: 1 1559 | m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} 1560 | m_Maskable: 1 1561 | m_OnCullStateChanged: 1562 | m_PersistentCalls: 1563 | m_Calls: [] 1564 | m_Sprite: {fileID: 21300000, guid: 10465f480b51f974dae1b8f194e33ea2, type: 3} 1565 | m_Type: 0 1566 | m_PreserveAspect: 0 1567 | m_FillCenter: 1 1568 | m_FillMethod: 4 1569 | m_FillAmount: 1 1570 | m_FillClockwise: 1 1571 | m_FillOrigin: 0 1572 | m_UseSpriteMesh: 0 1573 | m_PixelsPerUnitMultiplier: 1 1574 | --- !u!222 &1809307109 1575 | CanvasRenderer: 1576 | m_ObjectHideFlags: 0 1577 | m_CorrespondingSourceObject: {fileID: 0} 1578 | m_PrefabInstance: {fileID: 0} 1579 | m_PrefabAsset: {fileID: 0} 1580 | m_GameObject: {fileID: 1809307106} 1581 | m_CullTransparentMesh: 1 1582 | --- !u!1 &2015537179 1583 | GameObject: 1584 | m_ObjectHideFlags: 0 1585 | m_CorrespondingSourceObject: {fileID: 0} 1586 | m_PrefabInstance: {fileID: 0} 1587 | m_PrefabAsset: {fileID: 0} 1588 | serializedVersion: 6 1589 | m_Component: 1590 | - component: {fileID: 2015537180} 1591 | - component: {fileID: 2015537182} 1592 | - component: {fileID: 2015537181} 1593 | m_Layer: 5 1594 | m_Name: Content #5 hammer 1595 | m_TagString: Untagged 1596 | m_Icon: {fileID: 0} 1597 | m_NavMeshLayer: 0 1598 | m_StaticEditorFlags: 0 1599 | m_IsActive: 1 1600 | --- !u!224 &2015537180 1601 | RectTransform: 1602 | m_ObjectHideFlags: 0 1603 | m_CorrespondingSourceObject: {fileID: 0} 1604 | m_PrefabInstance: {fileID: 0} 1605 | m_PrefabAsset: {fileID: 0} 1606 | m_GameObject: {fileID: 2015537179} 1607 | m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} 1608 | m_LocalPosition: {x: 0, y: 0, z: 0} 1609 | m_LocalScale: {x: 1, y: 1, z: 1} 1610 | m_ConstrainProportionsScale: 0 1611 | m_Children: [] 1612 | m_Father: {fileID: 531171049} 1613 | m_RootOrder: 4 1614 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 1615 | m_AnchorMin: {x: 0.5, y: 0.5} 1616 | m_AnchorMax: {x: 0.5, y: 0.5} 1617 | m_AnchoredPosition: {x: -321.34885, y: -517.407} 1618 | m_SizeDelta: {x: 303.15137, y: 314.87546} 1619 | m_Pivot: {x: 0.5, y: 0.5} 1620 | --- !u!114 &2015537181 1621 | MonoBehaviour: 1622 | m_ObjectHideFlags: 0 1623 | m_CorrespondingSourceObject: {fileID: 0} 1624 | m_PrefabInstance: {fileID: 0} 1625 | m_PrefabAsset: {fileID: 0} 1626 | m_GameObject: {fileID: 2015537179} 1627 | m_Enabled: 1 1628 | m_EditorHideFlags: 0 1629 | m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} 1630 | m_Name: 1631 | m_EditorClassIdentifier: 1632 | m_Material: {fileID: 0} 1633 | m_Color: {r: 1, g: 1, b: 1, a: 1} 1634 | m_RaycastTarget: 1 1635 | m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} 1636 | m_Maskable: 1 1637 | m_OnCullStateChanged: 1638 | m_PersistentCalls: 1639 | m_Calls: [] 1640 | m_Sprite: {fileID: 21300000, guid: 5d9c09deefe747c45af225ebcdb9fa63, type: 3} 1641 | m_Type: 0 1642 | m_PreserveAspect: 0 1643 | m_FillCenter: 1 1644 | m_FillMethod: 4 1645 | m_FillAmount: 1 1646 | m_FillClockwise: 1 1647 | m_FillOrigin: 0 1648 | m_UseSpriteMesh: 0 1649 | m_PixelsPerUnitMultiplier: 1 1650 | --- !u!222 &2015537182 1651 | CanvasRenderer: 1652 | m_ObjectHideFlags: 0 1653 | m_CorrespondingSourceObject: {fileID: 0} 1654 | m_PrefabInstance: {fileID: 0} 1655 | m_PrefabAsset: {fileID: 0} 1656 | m_GameObject: {fileID: 2015537179} 1657 | m_CullTransparentMesh: 1 1658 | --- !u!1 &2094810103 1659 | GameObject: 1660 | m_ObjectHideFlags: 0 1661 | m_CorrespondingSourceObject: {fileID: 0} 1662 | m_PrefabInstance: {fileID: 0} 1663 | m_PrefabAsset: {fileID: 0} 1664 | serializedVersion: 6 1665 | m_Component: 1666 | - component: {fileID: 2094810104} 1667 | - component: {fileID: 2094810106} 1668 | - component: {fileID: 2094810105} 1669 | m_Layer: 5 1670 | m_Name: Title container 1671 | m_TagString: Untagged 1672 | m_Icon: {fileID: 0} 1673 | m_NavMeshLayer: 0 1674 | m_StaticEditorFlags: 0 1675 | m_IsActive: 1 1676 | --- !u!224 &2094810104 1677 | RectTransform: 1678 | m_ObjectHideFlags: 0 1679 | m_CorrespondingSourceObject: {fileID: 0} 1680 | m_PrefabInstance: {fileID: 0} 1681 | m_PrefabAsset: {fileID: 0} 1682 | m_GameObject: {fileID: 2094810103} 1683 | m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} 1684 | m_LocalPosition: {x: 0, y: 0, z: 0} 1685 | m_LocalScale: {x: 1, y: 1, z: 1} 1686 | m_ConstrainProportionsScale: 0 1687 | m_Children: [] 1688 | m_Father: {fileID: 77265287} 1689 | m_RootOrder: 2 1690 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 1691 | m_AnchorMin: {x: 0.5, y: 0.5} 1692 | m_AnchorMax: {x: 0.5, y: 0.5} 1693 | m_AnchoredPosition: {x: -320, y: -180} 1694 | m_SizeDelta: {x: 640, y: 360} 1695 | m_Pivot: {x: 0.5, y: 0.5} 1696 | --- !u!114 &2094810105 1697 | MonoBehaviour: 1698 | m_ObjectHideFlags: 0 1699 | m_CorrespondingSourceObject: {fileID: 0} 1700 | m_PrefabInstance: {fileID: 0} 1701 | m_PrefabAsset: {fileID: 0} 1702 | m_GameObject: {fileID: 2094810103} 1703 | m_Enabled: 1 1704 | m_EditorHideFlags: 0 1705 | m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} 1706 | m_Name: 1707 | m_EditorClassIdentifier: 1708 | m_Material: {fileID: 0} 1709 | m_Color: {r: 0.2, g: 0.2, b: 0.2, a: 1} 1710 | m_RaycastTarget: 1 1711 | m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} 1712 | m_Maskable: 1 1713 | m_OnCullStateChanged: 1714 | m_PersistentCalls: 1715 | m_Calls: [] 1716 | m_FontData: 1717 | m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} 1718 | m_FontSize: 30 1719 | m_FontStyle: 0 1720 | m_BestFit: 0 1721 | m_MinSize: 0 1722 | m_MaxSize: 60 1723 | m_Alignment: 6 1724 | m_AlignByGeometry: 0 1725 | m_RichText: 1 1726 | m_HorizontalOverflow: 0 1727 | m_VerticalOverflow: 0 1728 | m_LineSpacing: 1 1729 | m_Text: Container 1730 | --- !u!222 &2094810106 1731 | CanvasRenderer: 1732 | m_ObjectHideFlags: 0 1733 | m_CorrespondingSourceObject: {fileID: 0} 1734 | m_PrefabInstance: {fileID: 0} 1735 | m_PrefabAsset: {fileID: 0} 1736 | m_GameObject: {fileID: 2094810103} 1737 | m_CullTransparentMesh: 1 1738 | -------------------------------------------------------------------------------- /AdaptiveGrid/LayoutTools.cs: -------------------------------------------------------------------------------- 1 | using msmshazan.TexturePacker; 2 | using System; 3 | using System.Collections.Generic; 4 | using UnityEngine; 5 | 6 | namespace AdaptiveGrid 7 | { 8 | [Serializable] 9 | public struct GridSize 10 | { 11 | public int Rows; 12 | public int Cols; 13 | 14 | public GridSize(int columns, int rows) 15 | { 16 | Rows = rows; 17 | Cols = columns; 18 | } 19 | 20 | public override string ToString() 21 | { 22 | return $"GridSize {Cols}x{Rows}"; 23 | } 24 | } 25 | 26 | [Serializable] 27 | public struct Offset 28 | { 29 | [Range(0, 0.9f)] public float Horizontal; 30 | [Range(0, 0.9f)] public float Vertical; 31 | } 32 | 33 | public static class LayoutTools 34 | { 35 | 36 | // Place elements in gridRect 37 | public static void ArrangeElements(List elements, Rect gridRect, GridSize gridSize, Offset gridMargin, Offset cellPadding) 38 | { 39 | 40 | float gridWidth = gridRect.width * (1 - gridMargin.Horizontal); 41 | float gridHeight = gridRect.height * (1 - gridMargin.Vertical); 42 | 43 | float cellWidth = gridWidth / gridSize.Cols; 44 | float cellWidthOffseted = cellWidth * (1 - cellPadding.Horizontal); 45 | 46 | float cellHeigth = gridHeight / gridSize.Rows; 47 | float cellHeigthOffseted = cellHeigth * (1 - cellPadding.Vertical); 48 | 49 | for (int i = 0; i < elements.Count; i++) 50 | { 51 | RectTransform element = elements[i]; 52 | 53 | int rowNum = i / gridSize.Cols; 54 | int colNum = i % gridSize.Cols; 55 | 56 | //normalize pivot and anchors 57 | element.pivot = new Vector2(0.5f, 0.5f); 58 | element.anchorMin = element.anchorMax = new Vector2(0.5f, 0.5f); 59 | element.sizeDelta = new Vector2(cellWidthOffseted, cellHeigthOffseted); 60 | element.anchoredPosition = new Vector2( 61 | colNum * (cellWidth + cellPadding.Horizontal / 2) + cellWidth * element.pivot.x - gridWidth / 2, 62 | -rowNum * (cellHeigth + cellPadding.Vertical / 2) - cellHeigth * element.pivot.y + gridHeight / 2); 63 | } 64 | } 65 | 66 | //Size of content fitted in container with const aspect ratio 67 | public static Vector2 FitContent(Vector2 contentSize, Rect container, Offset cellPadding) 68 | { 69 | float contentAspectRatio = contentSize.x / contentSize.y; 70 | 71 | float containerAspectRatio = (container.width) / (container.height); 72 | 73 | float fitRatio = containerAspectRatio / contentAspectRatio; 74 | 75 | //Calculate new size fitted 76 | Vector2 newSizeDelta = new Vector2(container.width, container.height); 77 | 78 | if (containerAspectRatio / contentAspectRatio >= 1.0f) 79 | { 80 | //content is too high 81 | newSizeDelta = new Vector2(newSizeDelta.x / fitRatio, newSizeDelta.y); 82 | } 83 | else 84 | { 85 | //content is too wide 86 | newSizeDelta = new Vector2(newSizeDelta.x, newSizeDelta.y * fitRatio); 87 | } 88 | newSizeDelta = new Vector2(newSizeDelta.x, newSizeDelta.y); 89 | return newSizeDelta; 90 | } 91 | 92 | //Calculate optimal grid size for minimum empty space in container 93 | public static GridSize OptimalGridSize(List elements, Rect gridRect, Vector2 contentSize, Offset gridMargin, Offset cellPadding) 94 | { 95 | 96 | int q = elements.Count; 97 | 98 | float minTotalEmptySpace = System.Single.MaxValue; 99 | int optimalRowColunt = 1; 100 | int optimalColCount = 1; 101 | 102 | for (int cols = 1; cols <= q; cols++) 103 | { 104 | for (int rows = 1; rows <= Mathf.Ceil((float)q / cols); rows++) 105 | { 106 | int emptyCells = cols * rows - q; 107 | if (emptyCells >= 0) 108 | { 109 | 110 | Vector2 eventualCellSize = new Vector2(gridRect.width / cols, gridRect.height / rows); 111 | float eventualCellSpace = eventualCellSize.x * eventualCellSize.y; 112 | 113 | Vector2 averageScaledContentSize = LayoutTools.FitContent(contentSize, new Rect(0, 0, eventualCellSize.x, eventualCellSize.y), cellPadding); 114 | float eventualCellEmptySpace = eventualCellSpace - averageScaledContentSize.magnitude; 115 | float eventualTotalEmptySpace = eventualCellEmptySpace * q + emptyCells * eventualCellSpace; 116 | 117 | if (eventualTotalEmptySpace < minTotalEmptySpace) 118 | { 119 | minTotalEmptySpace = eventualTotalEmptySpace; 120 | optimalRowColunt = rows; 121 | optimalColCount = cols; 122 | } 123 | } 124 | } 125 | } 126 | return new GridSize(optimalColCount, optimalRowColunt); 127 | } 128 | 129 | //Pack content in grid container (recursive) 130 | public static Rect[] PackRects(RectTransform grid, List contentList, MaxRectsBinPack.FreeRectChoiceHeuristic packAlgorithm, float scalePrecision, float scaleFactor = 1.0f) 131 | { 132 | 133 | int width = (int)grid.rect.width; 134 | int height = (int)grid.rect.height; 135 | MaxRectsBinPack binPacker = new MaxRectsBinPack(width, height); 136 | 137 | Rect[] packedRects = new Rect[contentList.Count]; 138 | 139 | for (int i = 0; i < contentList.Count; i++) 140 | { 141 | 142 | RectSize rectSize = contentList[i].sprite != null ? new RectSize(contentList[i].sprite.rect) : new RectSize(contentList[i].GetComponent().rect); 143 | int scaledRectWidth = (int)(rectSize.width * scaleFactor); 144 | int scaledRectHeight = (int)(rectSize.height * scaleFactor); 145 | if (scaledRectHeight == 0) 146 | { 147 | scaledRectHeight = 1; 148 | } 149 | if (scaledRectWidth == 0) 150 | { 151 | scaledRectWidth = 1; 152 | } 153 | 154 | //Try to insert content into container 155 | BinRect rect = binPacker.Insert(scaledRectWidth, scaledRectHeight, packAlgorithm); 156 | 157 | //If content cant be packed, make re-pack with smaller scale 158 | if (rect.width == 0 || rect.height == 0) 159 | { 160 | scaleFactor -= scalePrecision; 161 | return PackRects(grid, contentList, packAlgorithm, scalePrecision, scaleFactor); 162 | } 163 | 164 | packedRects[i] = (Rect)rect; 165 | } 166 | return packedRects; 167 | } 168 | } 169 | 170 | } -------------------------------------------------------------------------------- /AdaptiveGrid/MaxRects/BinRect.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | /* msmshazan TexturePacker 4 | * https://github.com/msmshazan/TexturePacker/ */ 5 | namespace msmshazan.TexturePacker 6 | { 7 | public struct BinRect : IEquatable 8 | { 9 | public int x; 10 | public int y; 11 | public int width; 12 | public int height; 13 | 14 | public static bool operator !=(BinRect rect1, BinRect rect2) 15 | { 16 | return !(rect1 == rect2); 17 | } 18 | 19 | public static bool operator ==(BinRect rect1, BinRect rect2) 20 | { 21 | return rect1.Equals(rect2); 22 | } 23 | 24 | public static explicit operator UnityEngine.Rect(BinRect binRect) => new UnityEngine.Rect((float)binRect.x, (float)binRect.y, (float)binRect.width, (float)binRect.height); 25 | 26 | public override bool Equals(object obj) 27 | { 28 | return obj is BinRect && Equals((BinRect)obj); 29 | } 30 | 31 | public bool Equals(BinRect other) 32 | { 33 | return x == other.x && 34 | y == other.y && 35 | width == other.width && 36 | height == other.height; 37 | } 38 | 39 | public override int GetHashCode() 40 | { 41 | var hashCode = -1222528132; 42 | hashCode = hashCode * -1521134295 + x.GetHashCode(); 43 | hashCode = hashCode * -1521134295 + y.GetHashCode(); 44 | hashCode = hashCode * -1521134295 + width.GetHashCode(); 45 | hashCode = hashCode * -1521134295 + height.GetHashCode(); 46 | return hashCode; 47 | } 48 | //public static explicit operator Digit(byte b) => new Digit(b); 49 | }; 50 | } -------------------------------------------------------------------------------- /AdaptiveGrid/MaxRects/MaxRectsBinPack.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | /* msmshazan TexturePacker 5 | * https://github.com/msmshazan/TexturePacker/ */ 6 | namespace msmshazan.TexturePacker 7 | { 8 | public class MaxRectsBinPack 9 | { 10 | 11 | List freeRectangles; 12 | public int binHeight; 13 | public int binWidth; 14 | public List usedRectangles; 15 | 16 | /// Instantiates a bin of size (0,0). Call Init to create a new bin. 17 | public MaxRectsBinPack() 18 | { 19 | Init(0, 0); 20 | } 21 | 22 | /// Instantiates a bin of the given size. 23 | /// @param allowFlip Specifies whether the packing algorithm is allowed to rotate the input rectangles by 90 degrees to consider a better placement. 24 | public MaxRectsBinPack(int width, int height) 25 | { 26 | Init(width, height); 27 | } 28 | 29 | /// Returns 0 if the two intervals i1 and i2 are disjoint, or the length of their overlap otherwise. 30 | private int CommonIntervalLength(int i1start, int i1end, int i2start, int i2end) 31 | { 32 | if (i1end < i2start || i2end < i1start) 33 | return 0; 34 | return Math.Min(i1end, i2end) - Math.Max(i1start, i2start); 35 | } 36 | 37 | /// Computes the placement score for the -CP variant. 38 | private int ContactPointScoreNode(int x, int y, int width, int height) 39 | { 40 | int score = 0; 41 | 42 | if (x == 0 || x + width == binWidth) 43 | score += height; 44 | if (y == 0 || y + height == binHeight) 45 | score += width; 46 | 47 | for (int i = 0; i < usedRectangles.Count; ++i) 48 | { 49 | if (usedRectangles[i].x == x + width || usedRectangles[i].x + usedRectangles[i].width == x) 50 | score += CommonIntervalLength(usedRectangles[i].y, usedRectangles[i].y + usedRectangles[i].height, y, y + height); 51 | if (usedRectangles[i].y == y + height || usedRectangles[i].y + usedRectangles[i].height == y) 52 | score += CommonIntervalLength(usedRectangles[i].x, usedRectangles[i].x + usedRectangles[i].width, x, x + width); 53 | } 54 | return score; 55 | } 56 | private BinRect FindPositionForNewNodeBestAreaFit(bool rot, int width, int height, ref int bestAreaFit, ref int bestShortSideFit) 57 | { 58 | BinRect bestNode = new BinRect(); 59 | 60 | bestAreaFit = int.MaxValue; 61 | bestShortSideFit = int.MaxValue; 62 | 63 | for (int i = 0; i < freeRectangles.Count; ++i) 64 | { 65 | int areaFit = freeRectangles[i].width * freeRectangles[i].height - width * height; 66 | 67 | // Try to place the rectangle in upright (non-flipped) orientation. 68 | if (freeRectangles[i].width >= width && freeRectangles[i].height >= height) 69 | { 70 | int leftoverHoriz = Math.Abs(freeRectangles[i].width - width); 71 | int leftoverVert = Math.Abs(freeRectangles[i].height - height); 72 | int shortSideFit = Math.Min(leftoverHoriz, leftoverVert); 73 | 74 | if (areaFit < bestAreaFit || (areaFit == bestAreaFit && shortSideFit < bestShortSideFit)) 75 | { 76 | bestNode.x = freeRectangles[i].x; 77 | bestNode.y = freeRectangles[i].y; 78 | bestNode.width = width; 79 | bestNode.height = height; 80 | bestShortSideFit = shortSideFit; 81 | bestAreaFit = areaFit; 82 | } 83 | } 84 | 85 | if (rot) 86 | { 87 | if (freeRectangles[i].width >= height && freeRectangles[i].height >= width) 88 | { 89 | int leftoverHoriz = Math.Abs(freeRectangles[i].width - height); 90 | int leftoverVert = Math.Abs(freeRectangles[i].height - width); 91 | int shortSideFit = Math.Min(leftoverHoriz, leftoverVert); 92 | 93 | if (areaFit < bestAreaFit || (areaFit == bestAreaFit && shortSideFit < bestShortSideFit)) 94 | { 95 | bestNode.x = freeRectangles[i].x; 96 | bestNode.y = freeRectangles[i].y; 97 | bestNode.width = height; 98 | bestNode.height = width; 99 | bestShortSideFit = shortSideFit; 100 | bestAreaFit = areaFit; 101 | } 102 | } 103 | } 104 | } 105 | return bestNode; 106 | } 107 | 108 | private BinRect FindPositionForNewNodeBestLongSideFit(bool rot, int width, int height, ref int bestShortSideFit, ref int bestLongSideFit) 109 | { 110 | BinRect bestNode = new BinRect(); 111 | 112 | bestShortSideFit = int.MaxValue; 113 | bestLongSideFit = int.MaxValue; 114 | 115 | for (int i = 0; i < freeRectangles.Count; ++i) 116 | { 117 | // Try to place the rectangle in upright (non-flipped) orientation. 118 | if (freeRectangles[i].width >= width && freeRectangles[i].height >= height) 119 | { 120 | int leftoverHoriz = Math.Abs(freeRectangles[i].width - width); 121 | int leftoverVert = Math.Abs(freeRectangles[i].height - height); 122 | int shortSideFit = Math.Min(leftoverHoriz, leftoverVert); 123 | int longSideFit = Math.Max(leftoverHoriz, leftoverVert); 124 | 125 | if (longSideFit < bestLongSideFit || (longSideFit == bestLongSideFit && shortSideFit < bestShortSideFit)) 126 | { 127 | bestNode.x = freeRectangles[i].x; 128 | bestNode.y = freeRectangles[i].y; 129 | bestNode.width = width; 130 | bestNode.height = height; 131 | bestShortSideFit = shortSideFit; 132 | bestLongSideFit = longSideFit; 133 | } 134 | } 135 | 136 | if (rot) 137 | { 138 | if (freeRectangles[i].width >= height && freeRectangles[i].height >= width) 139 | { 140 | int leftoverHoriz = Math.Abs(freeRectangles[i].width - height); 141 | int leftoverVert = Math.Abs(freeRectangles[i].height - width); 142 | int shortSideFit = Math.Min(leftoverHoriz, leftoverVert); 143 | int longSideFit = Math.Max(leftoverHoriz, leftoverVert); 144 | 145 | if (longSideFit < bestLongSideFit || (longSideFit == bestLongSideFit && shortSideFit < bestShortSideFit)) 146 | { 147 | bestNode.x = freeRectangles[i].x; 148 | bestNode.y = freeRectangles[i].y; 149 | bestNode.width = height; 150 | bestNode.height = width; 151 | bestShortSideFit = shortSideFit; 152 | bestLongSideFit = longSideFit; 153 | } 154 | } 155 | } 156 | } 157 | return bestNode; 158 | } 159 | 160 | private BinRect FindPositionForNewNodeBestShortSideFit(bool rot, int width, int height, ref int bestShortSideFit, ref int bestLongSideFit) 161 | { 162 | BinRect bestNode = new BinRect(); 163 | 164 | bestShortSideFit = int.MaxValue; 165 | bestLongSideFit = int.MaxValue; 166 | 167 | for (int i = 0; i < freeRectangles.Count; ++i) 168 | { 169 | // Try to place the rectangle in upright (non-flipped) orientation. 170 | if (freeRectangles[i].width >= width && freeRectangles[i].height >= height) 171 | { 172 | int leftoverHoriz = Math.Abs(freeRectangles[i].width - width); 173 | int leftoverVert = Math.Abs(freeRectangles[i].height - height); 174 | int shortSideFit = Math.Min(leftoverHoriz, leftoverVert); 175 | int longSideFit = Math.Max(leftoverHoriz, leftoverVert); 176 | 177 | if (shortSideFit < bestShortSideFit || (shortSideFit == bestShortSideFit && longSideFit < bestLongSideFit)) 178 | { 179 | bestNode.x = freeRectangles[i].x; 180 | bestNode.y = freeRectangles[i].y; 181 | bestNode.width = width; 182 | bestNode.height = height; 183 | bestShortSideFit = shortSideFit; 184 | bestLongSideFit = longSideFit; 185 | } 186 | } 187 | 188 | if (rot) 189 | { 190 | if (freeRectangles[i].width >= height && freeRectangles[i].height >= width) 191 | { 192 | int flippedLeftoverHoriz = Math.Abs(freeRectangles[i].width - height); 193 | int flippedLeftoverVert = Math.Abs(freeRectangles[i].height - width); 194 | int flippedShortSideFit = Math.Min(flippedLeftoverHoriz, flippedLeftoverVert); 195 | int flippedLongSideFit = Math.Max(flippedLeftoverHoriz, flippedLeftoverVert); 196 | 197 | if (flippedShortSideFit < bestShortSideFit || (flippedShortSideFit == bestShortSideFit && flippedLongSideFit < bestLongSideFit)) 198 | { 199 | bestNode.x = freeRectangles[i].x; 200 | bestNode.y = freeRectangles[i].y; 201 | bestNode.width = height; 202 | bestNode.height = width; 203 | bestShortSideFit = flippedShortSideFit; 204 | bestLongSideFit = flippedLongSideFit; 205 | } 206 | } 207 | } 208 | } 209 | return bestNode; 210 | } 211 | 212 | private BinRect FindPositionForNewNodeBottomLeft(bool rot, int width, int height, ref int bestY, ref int bestX) 213 | { 214 | BinRect bestNode = new BinRect(); 215 | 216 | bestY = int.MaxValue; 217 | bestX = int.MaxValue; 218 | 219 | for (int i = 0; i < freeRectangles.Count; ++i) 220 | { 221 | // Try to place the rectangle in upright (non-flipped) orientation. 222 | if (freeRectangles[i].width >= width && freeRectangles[i].height >= height) 223 | { 224 | int topSideY = freeRectangles[i].y + height; 225 | if (topSideY < bestY || (topSideY == bestY && freeRectangles[i].x < bestX)) 226 | { 227 | bestNode.x = freeRectangles[i].x; 228 | bestNode.y = freeRectangles[i].y; 229 | bestNode.width = width; 230 | bestNode.height = height; 231 | bestY = topSideY; 232 | bestX = freeRectangles[i].x; 233 | } 234 | } 235 | if (rot) 236 | { 237 | if (freeRectangles[i].width >= height && freeRectangles[i].height >= width) 238 | { 239 | int topSideY = freeRectangles[i].y + width; 240 | if (topSideY < bestY || (topSideY == bestY && freeRectangles[i].x < bestX)) 241 | { 242 | bestNode.x = freeRectangles[i].x; 243 | bestNode.y = freeRectangles[i].y; 244 | bestNode.width = height; 245 | bestNode.height = width; 246 | bestY = topSideY; 247 | bestX = freeRectangles[i].x; 248 | } 249 | } 250 | } 251 | } 252 | return bestNode; 253 | } 254 | 255 | 256 | private BinRect FindPositionForNewNodeContactPoint(bool rot, int width, int height, ref int bestContactScore) 257 | { 258 | BinRect bestNode = new BinRect(); 259 | 260 | bestContactScore = -1; 261 | 262 | for (int i = 0; i < freeRectangles.Count; ++i) 263 | { 264 | // Try to place the rectangle in upright (non-flipped) orientation. 265 | if (freeRectangles[i].width >= width && freeRectangles[i].height >= height) 266 | { 267 | int score = ContactPointScoreNode(freeRectangles[i].x, freeRectangles[i].y, width, height); 268 | if (score > bestContactScore) 269 | { 270 | bestNode.x = freeRectangles[i].x; 271 | bestNode.y = freeRectangles[i].y; 272 | bestNode.width = width; 273 | bestNode.height = height; 274 | bestContactScore = score; 275 | } 276 | } 277 | if (rot) 278 | { 279 | if (freeRectangles[i].width >= height && freeRectangles[i].height >= width) 280 | { 281 | int score = ContactPointScoreNode(freeRectangles[i].x, freeRectangles[i].y, height, width); 282 | if (score > bestContactScore) 283 | { 284 | bestNode.x = freeRectangles[i].x; 285 | bestNode.y = freeRectangles[i].y; 286 | bestNode.width = height; 287 | bestNode.height = width; 288 | bestContactScore = score; 289 | } 290 | } 291 | } 292 | } 293 | return bestNode; 294 | } 295 | 296 | /// Places the given rectangle into the bin. 297 | private void PlaceRect(ref BinRect node) 298 | { 299 | 300 | int numRectanglesToProcess = freeRectangles.Count; 301 | for (int i = 0; i < numRectanglesToProcess; ++i) 302 | { 303 | if (SplitFreeNode(freeRectangles[i], ref node)) 304 | { 305 | freeRectangles.RemoveAt(i); 306 | --i; 307 | --numRectanglesToProcess; 308 | } 309 | } 310 | 311 | PruneFreeList(); 312 | 313 | usedRectangles.Add(node); 314 | } 315 | 316 | /// Goes through the free rectangle list and removes any redundant entries. 317 | private void PruneFreeList() 318 | { 319 | /// Go through each pair and remove any rectangle that is redundant. 320 | for (int i = 0; i < freeRectangles.Count; ++i) 321 | for (int j = i + 1; j < freeRectangles.Count; ++j) 322 | { 323 | if (IsContainedIn(freeRectangles[i], freeRectangles[j])) 324 | { 325 | freeRectangles.RemoveAt(i); 326 | --i; 327 | break; 328 | } 329 | if (IsContainedIn(freeRectangles[j], freeRectangles[i])) 330 | { 331 | freeRectangles.RemoveAt(j); 332 | --j; 333 | } 334 | } 335 | } 336 | 337 | /// Computes the placement score for placing the given rectangle with the given method. 338 | /// @param score1 [out] The primary placement score will be outputted here. 339 | /// @param score2 [out] The secondary placement score will be outputted here. This is used to break ties. 340 | /// @return This struct identifies where the rectangle would be placed if it were placed. 341 | private BinRect ScoreRect(int width, int height, bool rot, FreeRectChoiceHeuristic method, ref int score1, ref int score2) 342 | { 343 | BinRect newNode = new BinRect(); 344 | score1 = int.MaxValue; 345 | score2 = int.MinValue; 346 | switch (method) 347 | { 348 | case FreeRectChoiceHeuristic.RectBestShortSideFit: newNode = FindPositionForNewNodeBestShortSideFit(rot, width, height, ref score1, ref score2); break; 349 | case FreeRectChoiceHeuristic.RectBottomLeftRule: newNode = FindPositionForNewNodeBottomLeft(rot, width, height, ref score1, ref score2); break; 350 | case FreeRectChoiceHeuristic.RectContactPointRule: 351 | newNode = FindPositionForNewNodeContactPoint(rot, width, height, ref score1); 352 | score1 = -score1; // Reverse since we are minimizing, but for contact point score bigger is better. 353 | break; 354 | case FreeRectChoiceHeuristic.RectBestLongSideFit: newNode = FindPositionForNewNodeBestLongSideFit(rot, width, height, ref score2, ref score1); break; 355 | case FreeRectChoiceHeuristic.RectBestAreaFit: newNode = FindPositionForNewNodeBestAreaFit(rot, width, height, ref score1, ref score2); break; 356 | } 357 | 358 | // Cannot fit the current rectangle. 359 | if (newNode.height == 0) 360 | { 361 | score1 = int.MaxValue; 362 | score2 = int.MaxValue; 363 | } 364 | 365 | return newNode; 366 | } 367 | 368 | /// @return True if the free node was split. 369 | private bool SplitFreeNode(BinRect freeNode, ref BinRect usedNode) 370 | { 371 | // Test with SAT if the rectangles even intersect. 372 | if (usedNode.x >= freeNode.x + freeNode.width || usedNode.x + usedNode.width <= freeNode.x || 373 | usedNode.y >= freeNode.y + freeNode.height || usedNode.y + usedNode.height <= freeNode.y) 374 | return false; 375 | 376 | if (usedNode.x < freeNode.x + freeNode.width && usedNode.x + usedNode.width > freeNode.x) 377 | { 378 | // New node at the top side of the used node. 379 | if (usedNode.y > freeNode.y && usedNode.y < freeNode.y + freeNode.height) 380 | { 381 | BinRect newNode = freeNode; 382 | newNode.height = usedNode.y - newNode.y; 383 | freeRectangles.Add(newNode); 384 | } 385 | 386 | // New node at the bottom side of the used node. 387 | if (usedNode.y + usedNode.height < freeNode.y + freeNode.height) 388 | { 389 | BinRect newNode = freeNode; 390 | newNode.y = usedNode.y + usedNode.height; 391 | newNode.height = freeNode.y + freeNode.height - (usedNode.y + usedNode.height); 392 | freeRectangles.Add(newNode); 393 | } 394 | } 395 | 396 | if (usedNode.y < freeNode.y + freeNode.height && usedNode.y + usedNode.height > freeNode.y) 397 | { 398 | // New node at the left side of the used node. 399 | if (usedNode.x > freeNode.x && usedNode.x < freeNode.x + freeNode.width) 400 | { 401 | BinRect newNode = freeNode; 402 | newNode.width = usedNode.x - newNode.x; 403 | freeRectangles.Add(newNode); 404 | } 405 | 406 | // New node at the right side of the used node. 407 | if (usedNode.x + usedNode.width < freeNode.x + freeNode.width) 408 | { 409 | BinRect newNode = freeNode; 410 | newNode.x = usedNode.x + usedNode.width; 411 | newNode.width = freeNode.x + freeNode.width - (usedNode.x + usedNode.width); 412 | freeRectangles.Add(newNode); 413 | } 414 | } 415 | 416 | return true; 417 | } 418 | 419 | public void DoubleSize() 420 | { 421 | Init(binWidth * 2, binHeight * 2); 422 | } 423 | 424 | /// (Re)initializes the packer to an empty bin of width x height units. Call whenever 425 | /// you need to restart with a new bin. 426 | public void Init(int width, int height) 427 | { 428 | binWidth = width; 429 | binHeight = height; 430 | usedRectangles = new List(); 431 | freeRectangles = new List(); 432 | BinRect n = new BinRect(); 433 | n.x = 0; 434 | n.y = 0; 435 | n.width = width; 436 | n.height = height; 437 | usedRectangles.Clear(); 438 | freeRectangles.Clear(); 439 | freeRectangles.Add(n); 440 | } 441 | 442 | /// Inserts the given list of rectangles in an offline/batch mode, possibly rotated. 443 | /// @param rects The list of rectangles to insert. This RectSize will be destroyed in the process. 444 | /// @param dst [out] This list will contain the packed rectangles. The indices will not correspond to that of rects. 445 | /// @param method The rectangle placement rule to use when packing. 446 | public void Insert(List rects, List dst, FreeRectChoiceHeuristic method) 447 | { 448 | dst.Clear(); 449 | 450 | while (rects.Count > 0) 451 | { 452 | int bestScore1 = int.MaxValue; 453 | int bestScore2 = int.MaxValue; 454 | int bestRectIndex = -1; 455 | BinRect bestNode = new BinRect(); 456 | 457 | for (int i = 0; i < rects.Count; ++i) 458 | { 459 | int score1 = 0; 460 | int score2 = 0; 461 | BinRect newNode = ScoreRect(rects[i].width, rects[i].height, false, method, ref score1, ref score2); 462 | 463 | if (score1 < bestScore1 || (score1 == bestScore1 && score2 < bestScore2)) 464 | { 465 | bestScore1 = score1; 466 | bestScore2 = score2; 467 | bestNode = newNode; 468 | bestRectIndex = i; 469 | } 470 | } 471 | 472 | if (bestRectIndex == -1) 473 | { 474 | return; 475 | } 476 | 477 | 478 | PlaceRect(ref bestNode); 479 | dst.Add(bestNode); 480 | rects.RemoveAt(bestRectIndex); 481 | } 482 | } 483 | 484 | /// Inserts a single rectangle into the bin, possibly rotated. 485 | public BinRect Insert(int width, int height, FreeRectChoiceHeuristic method) 486 | { 487 | bool rot = false; 488 | BinRect newNode = new BinRect(); 489 | // Unused in this function. We don't need to know the score after finding the position. 490 | int score1 = int.MaxValue; 491 | int score2 = int.MaxValue; 492 | switch (method) 493 | { 494 | case FreeRectChoiceHeuristic.RectBestShortSideFit: newNode = FindPositionForNewNodeBestShortSideFit(rot, width, height, ref score1, ref score2); break; 495 | case FreeRectChoiceHeuristic.RectBottomLeftRule: newNode = FindPositionForNewNodeBottomLeft(rot, width, height, ref score1, ref score2); break; 496 | case FreeRectChoiceHeuristic.RectContactPointRule: newNode = FindPositionForNewNodeContactPoint(rot, width, height, ref score1); break; 497 | case FreeRectChoiceHeuristic.RectBestLongSideFit: newNode = FindPositionForNewNodeBestLongSideFit(rot, width, height, ref score2, ref score1); break; 498 | case FreeRectChoiceHeuristic.RectBestAreaFit: newNode = FindPositionForNewNodeBestAreaFit(rot, width, height, ref score1, ref score2); break; 499 | } 500 | 501 | if (newNode.height == 0) 502 | { 503 | return newNode; 504 | } 505 | 506 | int numRectanglesToProcess = freeRectangles.Count; 507 | for (int i = 0; i < numRectanglesToProcess; ++i) 508 | { 509 | if (SplitFreeNode(freeRectangles[i], ref newNode)) 510 | { 511 | freeRectangles.RemoveAt(i); 512 | --i; 513 | --numRectanglesToProcess; 514 | } 515 | } 516 | 517 | PruneFreeList(); 518 | 519 | usedRectangles.Add(newNode); 520 | return newNode; 521 | } 522 | 523 | public bool IsContainedIn(BinRect a, BinRect b) 524 | { 525 | return a.x >= b.x && a.y >= b.y 526 | && a.x + a.width <= b.x + b.width 527 | && a.y + a.height <= b.y + b.height; 528 | } 529 | 530 | /// Computes the ratio of used surface area to the total bin area. 531 | public float Occupancy() 532 | { 533 | int usedSurfaceArea = 0; 534 | for (int i = 0; i < usedRectangles.Count; ++i) 535 | usedSurfaceArea += usedRectangles[i].width * usedRectangles[i].height; 536 | 537 | return (float)usedSurfaceArea / (binWidth * binHeight); 538 | } 539 | 540 | /// Specifies the different heuristic rules that can be used when deciding where to place a new rectangle. 541 | public enum FreeRectChoiceHeuristic 542 | { 543 | RectContactPointRule, /// -CP: Choosest the placement where the rectangle touches other rects as much as possible. 544 | RectBestShortSideFit, /// -BSSF: Positions the rectangle against the short side of a free rectangle into which it fits the best. 545 | RectBestLongSideFit, /// -BLSF: Positions the rectangle against the long side of a free rectangle into which it fits the best. 546 | RectBestAreaFit, /// -BAF: Positions the rectangle into the smallest free rect into which it fits. 547 | RectBottomLeftRule /// -BL: Does the Tetris placement. 548 | 549 | }; 550 | }; 551 | } -------------------------------------------------------------------------------- /AdaptiveGrid/MaxRects/RectSize.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | /* msmshazan TexturePacker 4 | * https://github.com/msmshazan/TexturePacker/ */ 5 | namespace msmshazan.TexturePacker 6 | { 7 | public struct Point 8 | { 9 | public int x; 10 | public int y; 11 | }; 12 | 13 | public struct RectSize : IEquatable 14 | { 15 | public int width; 16 | public int height; 17 | 18 | public RectSize(UnityEngine.Rect rect) 19 | { 20 | width = (int)rect.width; 21 | height = (int)rect.height; 22 | } 23 | 24 | public RectSize(int w, int h) 25 | { 26 | width = w; 27 | height = h; 28 | } 29 | public RectSize(float w, float h) 30 | { 31 | width = (int)w; 32 | height = (int)h; 33 | } 34 | 35 | public static bool operator !=(RectSize size1, RectSize size2) 36 | { 37 | return !(size1 == size2); 38 | } 39 | 40 | public static bool operator ==(RectSize size1, RectSize size2) 41 | { 42 | return size1.Equals(size2); 43 | } 44 | 45 | 46 | public override bool Equals(object obj) 47 | { 48 | return obj is RectSize && Equals((RectSize)obj); 49 | } 50 | 51 | public bool Equals(RectSize other) 52 | { 53 | return width == other.width && 54 | height == other.height; 55 | } 56 | 57 | public override int GetHashCode() 58 | { 59 | var hashCode = 1263118649; 60 | hashCode = hashCode * -1521134295 + width.GetHashCode(); 61 | hashCode = hashCode * -1521134295 + height.GetHashCode(); 62 | return hashCode; 63 | } 64 | }; 65 | } -------------------------------------------------------------------------------- /AdaptiveGrid/Preset.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reflection; 5 | using UnityEngine; 6 | 7 | 8 | 9 | namespace AdaptiveGrid 10 | { 11 | [Serializable] 12 | public abstract class AdaptivePreset : ICloneable 13 | { 14 | static AdaptivePreset() 15 | { 16 | _presetPototypeDict = new Dictionary(); 17 | IEnumerable inheritedAdaptivePresetTypes = 18 | Assembly.GetAssembly(typeof(AdaptivePreset)).GetTypes().Where(type => type.IsSubclassOf(typeof(AdaptivePreset))); 19 | 20 | foreach (Type t in inheritedAdaptivePresetTypes) 21 | { 22 | AdaptivePreset instance = (AdaptivePreset)Activator.CreateInstance(t); 23 | _presetPototypeDict.Add(instance.SelectorInInspector, instance); 24 | } 25 | } 26 | 27 | public static event Action PresetChanged; 28 | 29 | //Instantiates preset instance for concrete AdaptiveGrip component 30 | private static AdaptivePreset InstantiateAdaptivePreset(System.Enum e) 31 | { 32 | return (AdaptivePreset)_presetPototypeDict[e].Clone(); 33 | } 34 | 35 | // Initialize dictionary with each AdaptivePreset prototype instance 36 | private static Dictionary _presetPototypeDict { get; set; } 37 | 38 | //Realizes preset algorithm 39 | public abstract void Apply(List elements, RectTransform grid, Offset gridMargin, Offset cellPadding); 40 | 41 | //Changes preset value with callback 42 | public static void ChangeValue(ref AdaptivePreset AdaptivePreset, System.Enum e) 43 | { 44 | if (AdaptivePreset != null) if (AdaptivePreset.SelectorInInspector.Equals(e)) return; 45 | AdaptivePreset = InstantiateAdaptivePreset(e); 46 | PresetChanged?.Invoke(); 47 | } 48 | 49 | //Clones preset instance 50 | public object Clone() { return this.MemberwiseClone(); } 51 | 52 | //Relevant enum in inspector 53 | public abstract System.Enum SelectorInInspector { get; } 54 | } 55 | } -------------------------------------------------------------------------------- /AdaptiveGrid/Presets/ArrangeFill.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | using UnityEngine.UI; 5 | 6 | namespace AdaptiveGrid 7 | { 8 | [Serializable] 9 | public class ArrangeFill : AdaptivePreset 10 | { 11 | public override void Apply(List elements, RectTransform grid, Offset gridMargin, Offset cellPadding) { 12 | 13 | //Collect elements' content and calculate its average size 14 | List images = new List(); 15 | Vector2 accumulatedSize = Vector2.zero; 16 | 17 | 18 | int imageWithSpriteCounter = 0; 19 | foreach (RectTransform element in elements) { 20 | if (element.TryGetComponent(out Image image)) { 21 | images.Add(image); 22 | if (image.sprite != null) { 23 | imageWithSpriteCounter++; 24 | } 25 | accumulatedSize += image.sprite != null ? new Vector2(image.sprite.rect.width, image.sprite.rect.height) : Vector2.zero; 26 | } 27 | } 28 | 29 | Vector2 averageContentSize = imageWithSpriteCounter > 0 ? accumulatedSize / elements.Count : Vector2.one; 30 | 31 | 32 | 33 | //Calculate optimal grid size to arrange elements with min imum empty space 34 | GridSize optimalGridSize = LayoutTools.OptimalGridSize(elements, grid.rect, averageContentSize, gridMargin, cellPadding); 35 | 36 | LayoutTools.ArrangeElements(elements, grid.rect, optimalGridSize, gridMargin, cellPadding); 37 | } 38 | 39 | public override System.Enum SelectorInInspector => AdaptiveGrid.ArrangeLayout.Fill; 40 | } 41 | } -------------------------------------------------------------------------------- /AdaptiveGrid/Presets/ArrangeGrid.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using UnityEngine; 5 | 6 | namespace AdaptiveGrid 7 | { 8 | [Serializable] 9 | public class ArrangeGrid : AdaptivePreset 10 | { 11 | [SerializeField] GridSize _gridSize = new GridSize(2, 2); 12 | 13 | public override void Apply(List elements, RectTransform grid, Offset gridMargin, Offset cellPadding) 14 | { 15 | 16 | GridSize gridSize = _gridSize; 17 | if (gridSize.Cols == 0 && gridSize.Rows == 0) 18 | { 19 | Debug.LogWarning($"You are trying to arrange elements in 0x0 grid"); 20 | return; 21 | } 22 | if (gridSize.Rows == 0) 23 | { 24 | gridSize.Rows = (int)Mathf.Ceil((float)elements.Count / gridSize.Cols); 25 | } 26 | if (gridSize.Cols == 0) 27 | { 28 | gridSize.Cols = (int)Mathf.Ceil((float)elements.Count / gridSize.Rows); 29 | } 30 | 31 | if(_grid==null) return; 32 | LayoutTools.ArrangeElements(elements, grid.rect, gridSize, gridMargin, cellPadding); 33 | } 34 | 35 | public override System.Enum SelectorInInspector => AdaptiveGrid.ArrangeLayout.Grid; 36 | 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /AdaptiveGrid/Presets/ArrangePack.cs: -------------------------------------------------------------------------------- 1 | using msmshazan.TexturePacker; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using UnityEngine; 6 | using UnityEngine.UI; 7 | 8 | namespace AdaptiveGrid 9 | { 10 | public class ArrangePack : AdaptivePreset 11 | { 12 | 13 | //Bin packing 14 | [SerializeField] private MaxRectsBinPack.FreeRectChoiceHeuristic _packAlgorithm; 15 | [Range(1, 5)] [SerializeField] private int _precisionLevel = 5; 16 | private float _scalePrecision; 17 | 18 | public override void Apply(List elements, RectTransform grid, Offset gridMargin, Offset cellPadding) 19 | { 20 | 21 | //Set base values each Apply call needs cause preset object used as serialized reference 22 | _scalePrecision = (float)(6 - _precisionLevel) / 100; 23 | 24 | //Search for elements content 25 | List contentList = new List(); 26 | 27 | foreach (RectTransform element in elements) 28 | { 29 | if (element.childCount > 1) 30 | { 31 | Debug.LogWarning($"{element.name} driven by AdaptiveGrid has >1 child and might be arranged incorrect"); 32 | } 33 | 34 | if (element.TryGetComponent(out Image image)) 35 | { 36 | contentList.Add(image); 37 | } 38 | } 39 | 40 | if (contentList.Count == 0) 41 | { 42 | Debug.LogWarning($"AdaptiveGrid have no childs with Image.sprite and cant be arranged with Bin Packing algorithm"); 43 | } 44 | 45 | try 46 | { 47 | Rect[] rects = LayoutTools.PackRects(grid, contentList, _packAlgorithm, _scalePrecision); 48 | //Arrange elements by calculated rects 49 | for (int i = 0; i < rects.Length; i++) 50 | { 51 | elements[i].anchorMin = elements[i].anchorMax = new Vector2(0, 1); 52 | elements[i].anchoredPosition = new Vector2(rects[i].x + rects[i].width / 2, -rects[i].y - rects[i].height / 2); 53 | elements[i].sizeDelta = new Vector2(rects[i].width, rects[i].height); 54 | } 55 | } 56 | catch (Exception e) 57 | { 58 | Debug.LogWarning($"Bin packing AdaptiveGrid content error \n {e}"); 59 | } 60 | } 61 | 62 | public override System.Enum SelectorInInspector => AdaptiveGrid.ArrangeLayout.PackByImage; 63 | } 64 | } -------------------------------------------------------------------------------- /AdaptiveGrid/Presets/ScaleFit.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | using UnityEngine.UI; 5 | 6 | namespace AdaptiveGrid 7 | { 8 | [Serializable] 9 | public class ScaleFit : AdaptivePreset 10 | { 11 | public override void Apply(List elements, RectTransform grid, Offset gridMargin, Offset cellPadding) 12 | { 13 | foreach (RectTransform element in elements) 14 | { 15 | if (element.TryGetComponent(out Image image)) 16 | { 17 | if (image.sprite != null) 18 | { 19 | Vector2 contentSize = image.sprite.bounds.size; 20 | Vector2 scaledContentSize = LayoutTools.FitContent(contentSize, element.rect, cellPadding); 21 | element.sizeDelta = scaledContentSize; 22 | element.anchoredPosition = new Vector2(element.anchoredPosition.x, element.anchoredPosition.y); 23 | } 24 | } 25 | } 26 | } 27 | 28 | public override System.Enum SelectorInInspector => AdaptiveGrid.ScaleMethod.FitImage; 29 | } 30 | } -------------------------------------------------------------------------------- /AdaptiveGrid/Presets/ScaleStretch.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | 5 | namespace AdaptiveGrid 6 | { 7 | [Serializable] 8 | public class ScaleNone : AdaptivePreset 9 | { 10 | public override void Apply(List elements, RectTransform grid, Offset gridMargin, Offset cellPadding) 11 | { 12 | //This strategy implements do nothing with content 13 | return; 14 | } 15 | 16 | public override System.Enum SelectorInInspector => AdaptiveGrid.ScaleMethod.None; 17 | } 18 | } -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Kirill Korneev 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AdaptiveGrid 2 | ## Overview 3 | Adaptive UIBehaviour with auto-layout and flexible settings. 4 | 5 | 1. No need to count or control cell size manually (in units) and ajust to parent size changes. 6 | 2. Elements dont freeze like in LayoutGroup (it transforms not driven by object). Means it could be animated or used any other way. 7 | 3. Rebuilds only in regular cases (OnTransformChildrenChanged, OnTransformChildrenChanged, OnCanvasHierarchyChanged, OnValidate). 8 | 4. Easy to extend: just create class inherited from Preset and its enum-value for inspector (ArrangeLayout or ScaleMethod). 9 | 10 | ## How to use 11 | 1. Import package 12 | 2. Add component AdaptiveGrid to any object 13 | 3. Choose arrange mode: 14 | > * **Fill**. Auto layout - all content fits screen. 15 | > * **Grid**. Fixed layout - n*m cells fits screen. Set rows or columns number to 0 for screen overflow (scroll mode). 16 | > * **Pack**. Atlas mode. Pack childs with Image component via MaxRects algorithm. 17 | 18 | ### Component automatically arrange elements in container (fits content if it is Image) 19 | ![](http://korneev.spb.ru/adaptivegrid/promo2.gif) 20 | ### Reacting to children order and composition changes 21 | ![](http://korneev.spb.ru/adaptivegrid/promo1.gif) 22 | ### Flex padding settings 23 | ![](http://korneev.spb.ru/adaptivegrid/promo3.gif) 24 | ### Fixed NxM grid and MaxRects bin pack by Image content 25 | ![](http://korneev.spb.ru/adaptivegrid/promo4.gif) 26 | 27 | --------------------------------------------------------------------------------