mirror of
				https://github.com/boudji-ludwig-pett/cnam-geometry-dash.git
				synced 2025-06-27 11:58:51 +02:00 
			
		
		
		
	Map editor design (#59)
This commit is contained in:
		| @@ -109,6 +109,7 @@ TextureImporter: | ||||
|     ignorePlatformSupport: 0 | ||||
|     androidETC2FallbackOverride: 0 | ||||
|     forceMaximumCompressionQuality_BC6H_BC7: 0 | ||||
| >>>>>>> develop | ||||
|   spriteSheet: | ||||
|     serializedVersion: 2 | ||||
|     sprites: | ||||
| @@ -147,8 +148,7 @@ TextureImporter: | ||||
|     secondaryTextures: [] | ||||
|     spriteCustomMetadata: | ||||
|       entries: [] | ||||
|     nameFileIdTable: | ||||
|       RegularBlock01_0: 229215520534054086 | ||||
|     nameFileIdTable: {} | ||||
|   mipmapLimitGroupName:  | ||||
|   pSDRemoveMatte: 0 | ||||
|   userData:  | ||||
|   | ||||
| @@ -147,8 +147,7 @@ TextureImporter: | ||||
|     secondaryTextures: [] | ||||
|     spriteCustomMetadata: | ||||
|       entries: [] | ||||
|     nameFileIdTable: | ||||
|       CubePortalLabelled_0: -799402021850825835 | ||||
|     nameFileIdTable: {} | ||||
|   mipmapLimitGroupName:  | ||||
|   pSDRemoveMatte: 0 | ||||
|   userData:  | ||||
|   | ||||
| @@ -147,8 +147,7 @@ TextureImporter: | ||||
|     secondaryTextures: [] | ||||
|     spriteCustomMetadata: | ||||
|       entries: [] | ||||
|     nameFileIdTable: | ||||
|       ShipPortalLabelled_0: -1834338360412052916 | ||||
|     nameFileIdTable: {} | ||||
|   mipmapLimitGroupName:  | ||||
|   pSDRemoveMatte: 0 | ||||
|   userData:  | ||||
|   | ||||
| @@ -222,63 +222,6 @@ MonoBehaviour: | ||||
|           m_StringArgument:  | ||||
|           m_BoolArgument: 0 | ||||
|         m_CallState: 2 | ||||
| --- !u!1001 &109370708 | ||||
| PrefabInstance: | ||||
|   m_ObjectHideFlags: 0 | ||||
|   serializedVersion: 2 | ||||
|   m_Modification: | ||||
|     serializedVersion: 3 | ||||
|     m_TransformParent: {fileID: 0} | ||||
|     m_Modifications: | ||||
|     - target: {fileID: 1771296619209216840, guid: e9dda45aef9258745a40efb48437d584, type: 3} | ||||
|       propertyPath: m_Name | ||||
|       value: BonusSlowSpeed | ||||
|       objectReference: {fileID: 0} | ||||
|     - target: {fileID: 6543394447596783970, guid: e9dda45aef9258745a40efb48437d584, type: 3} | ||||
|       propertyPath: m_LocalPosition.x | ||||
|       value: -5.4423084 | ||||
|       objectReference: {fileID: 0} | ||||
|     - target: {fileID: 6543394447596783970, guid: e9dda45aef9258745a40efb48437d584, type: 3} | ||||
|       propertyPath: m_LocalPosition.y | ||||
|       value: -2.783749 | ||||
|       objectReference: {fileID: 0} | ||||
|     - target: {fileID: 6543394447596783970, guid: e9dda45aef9258745a40efb48437d584, type: 3} | ||||
|       propertyPath: m_LocalPosition.z | ||||
|       value: 0 | ||||
|       objectReference: {fileID: 0} | ||||
|     - target: {fileID: 6543394447596783970, guid: e9dda45aef9258745a40efb48437d584, type: 3} | ||||
|       propertyPath: m_LocalRotation.w | ||||
|       value: 1 | ||||
|       objectReference: {fileID: 0} | ||||
|     - target: {fileID: 6543394447596783970, guid: e9dda45aef9258745a40efb48437d584, type: 3} | ||||
|       propertyPath: m_LocalRotation.x | ||||
|       value: 0 | ||||
|       objectReference: {fileID: 0} | ||||
|     - target: {fileID: 6543394447596783970, guid: e9dda45aef9258745a40efb48437d584, type: 3} | ||||
|       propertyPath: m_LocalRotation.y | ||||
|       value: 0 | ||||
|       objectReference: {fileID: 0} | ||||
|     - target: {fileID: 6543394447596783970, guid: e9dda45aef9258745a40efb48437d584, type: 3} | ||||
|       propertyPath: m_LocalRotation.z | ||||
|       value: 0 | ||||
|       objectReference: {fileID: 0} | ||||
|     - target: {fileID: 6543394447596783970, guid: e9dda45aef9258745a40efb48437d584, type: 3} | ||||
|       propertyPath: m_LocalEulerAnglesHint.x | ||||
|       value: 0 | ||||
|       objectReference: {fileID: 0} | ||||
|     - target: {fileID: 6543394447596783970, guid: e9dda45aef9258745a40efb48437d584, type: 3} | ||||
|       propertyPath: m_LocalEulerAnglesHint.y | ||||
|       value: 0 | ||||
|       objectReference: {fileID: 0} | ||||
|     - target: {fileID: 6543394447596783970, guid: e9dda45aef9258745a40efb48437d584, type: 3} | ||||
|       propertyPath: m_LocalEulerAnglesHint.z | ||||
|       value: 0 | ||||
|       objectReference: {fileID: 0} | ||||
|     m_RemovedComponents: [] | ||||
|     m_RemovedGameObjects: [] | ||||
|     m_AddedGameObjects: [] | ||||
|     m_AddedComponents: [] | ||||
|   m_SourcePrefab: {fileID: 100100000, guid: e9dda45aef9258745a40efb48437d584, type: 3} | ||||
| --- !u!1 &245275147 | ||||
| GameObject: | ||||
|   m_ObjectHideFlags: 0 | ||||
| @@ -434,6 +377,63 @@ CanvasRenderer: | ||||
|   m_PrefabAsset: {fileID: 0} | ||||
|   m_GameObject: {fileID: 487176671} | ||||
|   m_CullTransparentMesh: 1 | ||||
| --- !u!1001 &496264820 | ||||
| PrefabInstance: | ||||
|   m_ObjectHideFlags: 0 | ||||
|   serializedVersion: 2 | ||||
|   m_Modification: | ||||
|     serializedVersion: 3 | ||||
|     m_TransformParent: {fileID: 0} | ||||
|     m_Modifications: | ||||
|     - target: {fileID: 3025146551836412649, guid: 5d01d2d55c6c25541b0db90186e76c2b, type: 3} | ||||
|       propertyPath: m_Name | ||||
|       value: BonusBoostSpeed | ||||
|       objectReference: {fileID: 0} | ||||
|     - target: {fileID: 7134261581051338486, guid: 5d01d2d55c6c25541b0db90186e76c2b, type: 3} | ||||
|       propertyPath: m_LocalPosition.x | ||||
|       value: -2 | ||||
|       objectReference: {fileID: 0} | ||||
|     - target: {fileID: 7134261581051338486, guid: 5d01d2d55c6c25541b0db90186e76c2b, type: 3} | ||||
|       propertyPath: m_LocalPosition.y | ||||
|       value: -2.88 | ||||
|       objectReference: {fileID: 0} | ||||
|     - target: {fileID: 7134261581051338486, guid: 5d01d2d55c6c25541b0db90186e76c2b, type: 3} | ||||
|       propertyPath: m_LocalPosition.z | ||||
|       value: 0 | ||||
|       objectReference: {fileID: 0} | ||||
|     - target: {fileID: 7134261581051338486, guid: 5d01d2d55c6c25541b0db90186e76c2b, type: 3} | ||||
|       propertyPath: m_LocalRotation.w | ||||
|       value: 0.99681437 | ||||
|       objectReference: {fileID: 0} | ||||
|     - target: {fileID: 7134261581051338486, guid: 5d01d2d55c6c25541b0db90186e76c2b, type: 3} | ||||
|       propertyPath: m_LocalRotation.x | ||||
|       value: -0 | ||||
|       objectReference: {fileID: 0} | ||||
|     - target: {fileID: 7134261581051338486, guid: 5d01d2d55c6c25541b0db90186e76c2b, type: 3} | ||||
|       propertyPath: m_LocalRotation.y | ||||
|       value: -0 | ||||
|       objectReference: {fileID: 0} | ||||
|     - target: {fileID: 7134261581051338486, guid: 5d01d2d55c6c25541b0db90186e76c2b, type: 3} | ||||
|       propertyPath: m_LocalRotation.z | ||||
|       value: -0.079757296 | ||||
|       objectReference: {fileID: 0} | ||||
|     - target: {fileID: 7134261581051338486, guid: 5d01d2d55c6c25541b0db90186e76c2b, type: 3} | ||||
|       propertyPath: m_LocalEulerAnglesHint.x | ||||
|       value: 0 | ||||
|       objectReference: {fileID: 0} | ||||
|     - target: {fileID: 7134261581051338486, guid: 5d01d2d55c6c25541b0db90186e76c2b, type: 3} | ||||
|       propertyPath: m_LocalEulerAnglesHint.y | ||||
|       value: 0 | ||||
|       objectReference: {fileID: 0} | ||||
|     - target: {fileID: 7134261581051338486, guid: 5d01d2d55c6c25541b0db90186e76c2b, type: 3} | ||||
|       propertyPath: m_LocalEulerAnglesHint.z | ||||
|       value: -9.149 | ||||
|       objectReference: {fileID: 0} | ||||
|     m_RemovedComponents: [] | ||||
|     m_RemovedGameObjects: [] | ||||
|     m_AddedGameObjects: [] | ||||
|     m_AddedComponents: [] | ||||
|   m_SourcePrefab: {fileID: 100100000, guid: 5d01d2d55c6c25541b0db90186e76c2b, type: 3} | ||||
| --- !u!1 &519420028 | ||||
| GameObject: | ||||
|   m_ObjectHideFlags: 0 | ||||
| @@ -7475,4 +7475,4 @@ SceneRoots: | ||||
|   - {fileID: 1371294550} | ||||
|   - {fileID: 521952202} | ||||
|   - {fileID: 555497623} | ||||
|   - {fileID: 109370708} | ||||
|   - {fileID: 496264820} | ||||
|   | ||||
| @@ -1,5 +1,6 @@ | ||||
| using UnityEngine; | ||||
| using UnityEngine.UI; | ||||
| using UnityEngine.EventSystems; | ||||
| using System.Collections.Generic; | ||||
|  | ||||
| public class LevelEditor : MonoBehaviour | ||||
| @@ -34,6 +35,21 @@ public class LevelEditor : MonoBehaviour | ||||
|         GenerateButtons(); | ||||
|     } | ||||
|  | ||||
|     void Update() | ||||
|     { | ||||
|         if (IsPointerOverUI()) return; | ||||
|  | ||||
|         if (isPlacingBlock && currentBlock != null) | ||||
|             HandleBlockPlacement(); | ||||
|         else | ||||
|             HandleBlockSelection(); | ||||
|  | ||||
|         HandleBlockResizing(); | ||||
|         HandleBlockDeletion(); | ||||
|     } | ||||
|  | ||||
|     #region UI | ||||
|  | ||||
|     void LoadPrefabs() | ||||
|     { | ||||
|         blockPrefabs.AddRange(Resources.LoadAll<GameObject>("Prefabs")); | ||||
| @@ -41,21 +57,9 @@ public class LevelEditor : MonoBehaviour | ||||
|  | ||||
|     void GenerateButtons() | ||||
|     { | ||||
|         if (buttonPrefabTemplate == null) | ||||
|         { | ||||
|             Debug.LogError("LevelEditor.GenerateButtons(): buttonPrefabTemplate n’est pas assigné !"); | ||||
|             return; | ||||
|         } | ||||
|         if (blockGroupContainer == null) | ||||
|         { | ||||
|             Debug.LogError("LevelEditor.GenerateButtons(): blockGroupContainer n’est pas assigné !"); | ||||
|             return; | ||||
|         } | ||||
|         ClearCurrentButtons(); | ||||
|  | ||||
|         Transform container = blockGroupContainer; | ||||
|  | ||||
|         if (container == null || buttonPrefabTemplate == null) | ||||
|         if (blockGroupContainer == null || buttonPrefabTemplate == null) | ||||
|         { | ||||
|             Debug.LogError("UI Container ou prefab de bouton manquant."); | ||||
|             return; | ||||
| @@ -66,34 +70,10 @@ public class LevelEditor : MonoBehaviour | ||||
|  | ||||
|         for (int i = start; i < end; i++) | ||||
|         { | ||||
|             GameObject button = Instantiate(buttonPrefabTemplate, container); | ||||
|             GameObject button = Instantiate(buttonPrefabTemplate, blockGroupContainer); | ||||
|             button.SetActive(true); | ||||
|  | ||||
|             Transform canvas = button.transform.Find("Canvas"); | ||||
|             Transform bg = canvas?.Find("BlankSquare"); | ||||
|             Transform icon = canvas?.Find("PrefabIcon"); | ||||
|  | ||||
|             if (bg == null || icon == null) | ||||
|             { | ||||
|                 Destroy(button); | ||||
|                 continue; | ||||
|             } | ||||
|  | ||||
|             float xOffset = -375f + (i - start) * 125f; | ||||
|             bg.GetComponent<RectTransform>().anchoredPosition = new Vector2(xOffset, bg.GetComponent<RectTransform>().anchoredPosition.y); | ||||
|             icon.GetComponent<RectTransform>().anchoredPosition = new Vector2(xOffset, icon.GetComponent<RectTransform>().anchoredPosition.y); | ||||
|  | ||||
|             Image bgImage = bg.GetComponent<Image>(); | ||||
|             Image iconImage = icon.GetComponent<Image>(); | ||||
|  | ||||
|             bgImage.sprite = Resources.Load<Sprite>("InGame/ButtonSkin/BlankSquare"); | ||||
|             iconImage.sprite = blockPrefabs[i].GetComponent<SpriteRenderer>()?.sprite; | ||||
|  | ||||
|             string prefabName = blockPrefabs[i].name.ToLower(); | ||||
|             if (prefabName.Contains("smallspike") || prefabName.Contains("smallobstacle")) | ||||
|                 icon.GetComponent<RectTransform>().sizeDelta = new Vector2(50, 25); | ||||
|             else | ||||
|                 icon.GetComponent<RectTransform>().sizeDelta = new Vector2(50, 50); | ||||
|             SetupButtonVisual(button.transform, blockPrefabs[i], i - start); | ||||
|  | ||||
|             GameObject prefab = blockPrefabs[i]; | ||||
|             button.GetComponent<Button>().onClick.AddListener(() => SelectPrefab(prefab)); | ||||
| @@ -101,18 +81,40 @@ public class LevelEditor : MonoBehaviour | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     void SetupButtonVisual(Transform buttonTransform, GameObject prefab, int index) | ||||
|     { | ||||
|         Transform canvas = buttonTransform.Find("Canvas"); | ||||
|         Transform bg = canvas?.Find("BlankSquare"); | ||||
|         Transform icon = canvas?.Find("PrefabIcon"); | ||||
|  | ||||
|         if (bg == null || icon == null) | ||||
|         { | ||||
|             Destroy(buttonTransform.gameObject); | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         float xOffset = -375f + index * 125f; | ||||
|         bg.GetComponent<RectTransform>().anchoredPosition = new Vector2(xOffset, bg.GetComponent<RectTransform>().anchoredPosition.y); | ||||
|         icon.GetComponent<RectTransform>().anchoredPosition = new Vector2(xOffset, icon.GetComponent<RectTransform>().anchoredPosition.y); | ||||
|  | ||||
|         bg.GetComponent<Image>().sprite = Resources.Load<Sprite>("InGame/ButtonSkin/BlankSquare"); | ||||
|         icon.GetComponent<Image>().sprite = prefab.GetComponent<SpriteRenderer>()?.sprite; | ||||
|  | ||||
|         icon.GetComponent<RectTransform>().sizeDelta = prefab.name.ToLower().Contains("small") | ||||
|             ? new Vector2(50, 25) | ||||
|             : new Vector2(50, 50); | ||||
|     } | ||||
|  | ||||
|     void ClearCurrentButtons() | ||||
|     { | ||||
|         foreach (var button in currentButtons) | ||||
|             Destroy(button); | ||||
|  | ||||
|         currentButtons.Clear(); | ||||
|     } | ||||
|  | ||||
|     public void NextPage() | ||||
|     { | ||||
|         int maxPage = 3; | ||||
|         Debug.Log(currentPage); | ||||
|         int maxPage = Mathf.CeilToInt(blockPrefabs.Count / (float)buttonsPerPage); | ||||
|         if (currentPage < maxPage - 1) | ||||
|         { | ||||
|             currentPage++; | ||||
| @@ -122,7 +124,6 @@ public class LevelEditor : MonoBehaviour | ||||
|  | ||||
|     public void PreviousPage() | ||||
|     { | ||||
|         Debug.Log(currentPage); | ||||
|         if (currentPage > 0) | ||||
|         { | ||||
|             currentPage--; | ||||
| @@ -130,308 +131,196 @@ public class LevelEditor : MonoBehaviour | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     #endregion | ||||
|  | ||||
|     #region Placement | ||||
|  | ||||
|     void SelectPrefab(GameObject prefab) | ||||
|     { | ||||
|         if (isPlacingBlock) return; | ||||
|  | ||||
|         string name = prefab.name.ToLower(); | ||||
|  | ||||
|         if (name.Contains("portal")) | ||||
|             currentScale = new Vector3(0.5f, 0.5f, 1); | ||||
|         else if (name.Contains("small")) | ||||
|             currentScale = new Vector3(0.15f, 0.07f, 1); | ||||
|         else if (name.Contains("spike")) | ||||
|             currentScale = new Vector3(0.15f, 0.15f, 1); | ||||
|         else if (name.Contains("block")) | ||||
|             currentScale = new Vector3(0.2f, 0.2f, 1); | ||||
|         else if (name.Contains("bonus")) | ||||
|             currentScale = new Vector3(0.3f, 0.3f, 1); | ||||
|         else | ||||
|             currentScale = new Vector3(1f, 1f, 1); | ||||
|  | ||||
|         currentScale = DetermineScaleFromName(prefab.name); | ||||
|         InstantiateAndPrepare(prefab, currentScale); | ||||
|     } | ||||
|     void Update() | ||||
|  | ||||
|     Vector3 DetermineScaleFromName(string name) | ||||
|     { | ||||
|         // Déplacement de l'objet en cours de placement | ||||
|         if (isPlacingBlock && currentBlock != null) | ||||
|         name = name.ToLower(); | ||||
|  | ||||
|         if (name.Contains("portal")) return new Vector3(0.5f, 0.5f, 1); | ||||
|         if (name.Contains("small")) return new Vector3(0.15f, 0.07f, 1); | ||||
|         if (name.Contains("spike")) return new Vector3(0.15f, 0.15f, 1); | ||||
|         if (name.Contains("block")) return new Vector3(0.2f, 0.2f, 1); | ||||
|         if (name.Contains("bonus")) return new Vector3(0.3f, 0.3f, 1); | ||||
|  | ||||
|         return new Vector3(1f, 1f, 1); | ||||
|     } | ||||
|  | ||||
|     void HandleBlockPlacement() | ||||
|     { | ||||
|         Vector2 mousePos = Camera.main.ScreenToWorldPoint(Input.mousePosition); | ||||
|         currentBlock.transform.position = new Vector3(Mathf.Round(mousePos.x), Mathf.Round(mousePos.y), -1); | ||||
|  | ||||
|         if (Input.GetKeyDown(KeyCode.R)) | ||||
|             HandleBlockRotation(); | ||||
|  | ||||
|         if (!currentBlock.name.ToLower().Contains("portal")) | ||||
|         { | ||||
|             Vector2 mousePos = Camera.main.ScreenToWorldPoint(Input.mousePosition); | ||||
|             currentBlock.transform.position = new Vector3(Mathf.Round(mousePos.x), Mathf.Round(mousePos.y), -1); | ||||
|  | ||||
|             if (currentBlock != null && Input.GetKeyDown(KeyCode.R)) | ||||
|             float scroll = Input.GetAxis("Mouse ScrollWheel"); | ||||
|             if (scroll != 0) | ||||
|             { | ||||
|                 HandleBlockRotation(); // ✅ Nouvelle rotation | ||||
|             } | ||||
|  | ||||
|             if (!currentBlock.name.ToLower().Contains("portal")) | ||||
|             { | ||||
|                 float scroll = Input.GetAxis("Mouse ScrollWheel"); | ||||
|                 if (scroll != 0) | ||||
|                 { | ||||
|                     float newScale = Mathf.Max(0.1f, currentScale.x + scroll * scaleStep); | ||||
|                     currentScale = new Vector3(newScale, newScale, 1); | ||||
|                     currentBlock.transform.localScale = currentScale; | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             if (Input.GetMouseButtonDown(0)) | ||||
|             { | ||||
|                 Collider2D[] overlaps = Physics2D.OverlapBoxAll( | ||||
|                     currentBlock.transform.position, | ||||
|                     currentBlock.GetComponent<Collider2D>().bounds.size, | ||||
|                     0f | ||||
|                 ); | ||||
|  | ||||
|                 if (overlaps.Length > 1) | ||||
|                 { | ||||
|                     Debug.Log("Placement annulé : un objet est déjà présent à cet endroit."); | ||||
|                     return; | ||||
|                 } | ||||
|  | ||||
|                 PlaceBlock(); | ||||
|                 float newScale = Mathf.Max(0.1f, currentScale.x + scroll * scaleStep); | ||||
|                 currentScale = new Vector3(newScale, newScale, 1); | ||||
|                 currentBlock.transform.localScale = currentScale; | ||||
|             } | ||||
|         } | ||||
|         else if (Input.GetMouseButtonDown(0)) // Clic gauche pour reprendre un objet déjà placé | ||||
|  | ||||
|         if (Input.GetMouseButtonDown(0)) | ||||
|         { | ||||
|             if (!IsPlacementValid()) | ||||
|             { | ||||
|                 Debug.Log("Placement annulé : collision."); | ||||
|                 return; | ||||
|             } | ||||
|  | ||||
|             PlaceBlock(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     bool IsPlacementValid() | ||||
|     { | ||||
|         Collider2D[] overlaps = Physics2D.OverlapBoxAll( | ||||
|             currentBlock.transform.position, | ||||
|             currentBlock.GetComponent<Collider2D>().bounds.size, | ||||
|             0f | ||||
|         ); | ||||
|  | ||||
|         foreach (var col in overlaps) | ||||
|         { | ||||
|             if (col.transform.root == currentBlock.transform || col.CompareTag("Ground")) | ||||
|                 continue; | ||||
|             return false; | ||||
|         } | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     void HandleBlockSelection() | ||||
|     { | ||||
|         if (Input.GetMouseButtonDown(0)) | ||||
|         { | ||||
|             Vector2 mousePos = Camera.main.ScreenToWorldPoint(Input.mousePosition); | ||||
|             Collider2D hit = Physics2D.OverlapPoint(mousePos); | ||||
|  | ||||
|             if (hit != null && hit.transform != null) | ||||
|             if (hit != null && !hit.CompareTag("Ground")) | ||||
|             { | ||||
|                 if (hit.CompareTag("Ground")) | ||||
|                 { | ||||
|                     Debug.Log("Impossible de déplacer le sol (tag Ground)."); | ||||
|                     return; | ||||
|                 } | ||||
|                 currentBlock = hit.gameObject; | ||||
|                 isPlacingBlock = true; | ||||
|                 currentScale = currentBlock.transform.localScale; | ||||
|                 Debug.Log($"Déplacement de l'objet : {currentBlock.name}"); | ||||
|                 return; | ||||
|                 Debug.Log($"Bloc sélectionné : {currentBlock.name}"); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // Redimensionnement d'un objet déjà placé | ||||
|         if (Input.GetMouseButtonDown(0) && Input.GetKey(KeyCode.LeftShift) && !isPlacingBlock) | ||||
|         { | ||||
|             Vector2 mousePos = Camera.main.ScreenToWorldPoint(Input.mousePosition); | ||||
|             Collider2D hit = Physics2D.OverlapPoint(mousePos); | ||||
|  | ||||
|             if (hit != null && hit.transform != null && !hit.CompareTag("Ground")) | ||||
|             { | ||||
|                 resizingTarget = hit.gameObject; | ||||
|                 originalMousePos = mousePos; | ||||
|                 originalScale = resizingTarget.transform.localScale; | ||||
|  | ||||
|                 Vector2 localClick = mousePos - (Vector2)resizingTarget.transform.position; | ||||
|                 float ratio = resizingTarget.GetComponent<Collider2D>().bounds.size.x / | ||||
|                 resizingTarget.GetComponent<Collider2D>().bounds.size.y; | ||||
|  | ||||
|                 currentResizeAxis = Mathf.Abs(localClick.x) > Mathf.Abs(localClick.y * ratio) | ||||
|                     ? ResizeAxis.Horizontal | ||||
|                     : ResizeAxis.Vertical; | ||||
|  | ||||
|                 isResizing = true; | ||||
|                 Debug.Log($"Début de redimensionnement : {resizingTarget.name}, axe = {currentResizeAxis}"); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         if (isResizing && resizingTarget != null) | ||||
|         { | ||||
|             Vector3 currentMousePos = Camera.main.ScreenToWorldPoint(Input.mousePosition); | ||||
|             Vector3 delta = currentMousePos - originalMousePos; | ||||
|  | ||||
|             Vector3 newScale = originalScale; | ||||
|  | ||||
|             if (currentResizeAxis == ResizeAxis.Horizontal) | ||||
|                 newScale.x = Mathf.Max(0.1f, originalScale.x + delta.x); | ||||
|             else if (currentResizeAxis == ResizeAxis.Vertical) | ||||
|                 newScale.y = Mathf.Max(0.1f, originalScale.y + delta.y); | ||||
|  | ||||
|             // Temporarily apply the new scale for collision testing | ||||
|             Vector3 originalPos = resizingTarget.transform.position; | ||||
|             resizingTarget.transform.localScale = newScale; | ||||
|  | ||||
|             Bounds bounds = resizingTarget.GetComponent<Collider2D>().bounds; | ||||
|             Collider2D[] overlaps = Physics2D.OverlapBoxAll(bounds.center, bounds.size, 0f); | ||||
|  | ||||
|             bool hasCollision = false; | ||||
|             foreach (var col in overlaps) | ||||
|             { | ||||
|                 if (col.gameObject != resizingTarget) | ||||
|                 { | ||||
|                     hasCollision = true; | ||||
|                     break; | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             if (hasCollision) | ||||
|             { | ||||
|                 resizingTarget.transform.localScale = originalScale; // revert | ||||
|                 Debug.Log("Étirement annulé : collision détectée."); | ||||
|             } | ||||
|  | ||||
|             if (Input.GetMouseButtonUp(0)) | ||||
|             { | ||||
|                 isResizing = false; | ||||
|                 resizingTarget = null; | ||||
|                 currentResizeAxis = ResizeAxis.None; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|  | ||||
|         // Clic droit pour supprimer un objet déjà placé (sauf le sol) | ||||
|         if (Input.GetMouseButtonDown(1)) | ||||
|         { | ||||
|             Vector2 mousePos = Camera.main.ScreenToWorldPoint(Input.mousePosition); | ||||
|             Collider2D hit = Physics2D.OverlapPoint(mousePos); | ||||
|  | ||||
|             if (hit != null && hit.transform != null) | ||||
|             { | ||||
|                 if (hit.CompareTag("Ground")) | ||||
|                 { | ||||
|                     Debug.Log("Impossible de supprimer le sol (tag Ground)."); | ||||
|                     return; | ||||
|                 } | ||||
|  | ||||
|                 Destroy(hit.gameObject); | ||||
|                 Debug.Log($"Objet supprimé : {hit.name}"); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|     } | ||||
|  | ||||
|     void PlaceBlock() | ||||
|     { | ||||
|         bool skipVerticalSnap = false; | ||||
|         string name = currentBlock.name.ToLower(); | ||||
|  | ||||
|         if (currentBlock.name.ToLower().Contains("smallobstacle") || currentBlock.name.ToLower().Contains("portal")) | ||||
|         bool grounded = name.Contains("spike") || name.Contains("bonus") || name.Contains("smallobstacle"); | ||||
|  | ||||
|         if (grounded) | ||||
|         { | ||||
|             skipVerticalSnap = true; // On saute l'alignement vertical pour ces cas-là | ||||
|             StickBlockToGround(); | ||||
|         } | ||||
|         else if (!ShouldSkipVerticalSnap(name)) | ||||
|         { | ||||
|             SnapBlockVertically(); | ||||
|             TrySnapToNearbyBlock(); // ✅ seulement ici | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             TrySnapToNearbyBlock(); // ex: autres blocs | ||||
|         } | ||||
|  | ||||
|         if (!skipVerticalSnap) | ||||
|         { | ||||
|             Vector2 origin = currentBlock.transform.position; | ||||
|             RaycastHit2D[] hitsBelow = Physics2D.RaycastAll(origin, Vector2.down, 100f); | ||||
|  | ||||
|             float highestY = -Mathf.Infinity; | ||||
|             GameObject bestTargetBelow = null; | ||||
|  | ||||
|             foreach (var hit in hitsBelow) | ||||
|             { | ||||
|                 if (hit.collider != null && hit.collider.gameObject != currentBlock) | ||||
|                 { | ||||
|                     float topOfObject = hit.collider.bounds.max.y; | ||||
|                     if (topOfObject > highestY) | ||||
|                     { | ||||
|                         highestY = topOfObject; | ||||
|                         bestTargetBelow = hit.collider.gameObject; | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             if (bestTargetBelow != null) | ||||
|             { | ||||
|                 float height = currentBlock.GetComponent<Collider2D>().bounds.size.y; | ||||
|                 currentBlock.transform.position = new Vector3(currentBlock.transform.position.x, highestY + height / 2f, -1); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 float height = currentBlock.GetComponent<Collider2D>().bounds.size.y; | ||||
|                 currentBlock.transform.position = new Vector3(currentBlock.transform.position.x, height / 2f, -1); | ||||
|             } | ||||
|         } | ||||
|         // ➔ Toujours essayer de snap sur la droite et en bas même pour Portal et SmallObstacle | ||||
|         TrySnapToNearbyBlock(); | ||||
|  | ||||
|         isPlacingBlock = false; | ||||
|         currentBlock = null; | ||||
|     } | ||||
|  | ||||
|  | ||||
|     private void TrySnapToNearbyBlock() | ||||
|     void StickBlockToGround() | ||||
|     { | ||||
|         if (currentBlock == null) | ||||
|             return; | ||||
|         Collider2D col = currentBlock.GetComponent<Collider2D>(); | ||||
|         Bounds bounds = col.bounds; | ||||
|  | ||||
|         Collider2D blockCollider = currentBlock.GetComponent<Collider2D>(); | ||||
|         Bounds bounds = blockCollider.bounds; | ||||
|         Vector2 origin = new Vector2(bounds.center.x, bounds.min.y); | ||||
|         float rayLength = 100f; // on descend loin pour être sûr de toucher le sol | ||||
|  | ||||
|         float snapDistance = 1f; // Distance de snap (en Unity units) | ||||
|         RaycastHit2D hit = Physics2D.Raycast(origin, Vector2.down, rayLength); | ||||
|  | ||||
|         // Zone de scan à droite | ||||
|         Vector2 rightAreaStart = new Vector2(bounds.max.x, bounds.min.y); | ||||
|         Vector2 rightAreaEnd = new Vector2(bounds.max.x + snapDistance, bounds.max.y); | ||||
|  | ||||
|         // Zone de scan à gauche | ||||
|         Vector2 leftAreaStart = new Vector2(bounds.min.x - snapDistance, bounds.min.y); | ||||
|         Vector2 leftAreaEnd = new Vector2(bounds.min.x, bounds.max.y); | ||||
|  | ||||
|         // Zone de scan en dessous | ||||
|         Vector2 bottomAreaStart = new Vector2(bounds.min.x, bounds.min.y - snapDistance); | ||||
|         Vector2 bottomAreaEnd = new Vector2(bounds.max.x, bounds.min.y); | ||||
|  | ||||
|         // Zone de scan au dessus | ||||
|         Vector2 topAreaStart = new Vector2(bounds.min.x, bounds.max.y); | ||||
|         Vector2 topAreaEnd = new Vector2(bounds.max.x, bounds.max.y + snapDistance); | ||||
|  | ||||
|         Collider2D[] hitsRight = Physics2D.OverlapAreaAll(rightAreaStart, rightAreaEnd); | ||||
|         Collider2D[] hitsLeft = Physics2D.OverlapAreaAll(leftAreaStart, leftAreaEnd); | ||||
|         Collider2D[] hitsBelow = Physics2D.OverlapAreaAll(bottomAreaStart, bottomAreaEnd); | ||||
|         Collider2D[] hitsAbove = Physics2D.OverlapAreaAll(topAreaStart, topAreaEnd); | ||||
|  | ||||
|         // ➔ Priorité : droite > gauche > bas > haut | ||||
|  | ||||
|         foreach (var hit in hitsRight) | ||||
|         if (hit.collider != null && hit.collider.gameObject != currentBlock) | ||||
|         { | ||||
|             if (hit != null && hit.gameObject != currentBlock) | ||||
|             { | ||||
|                 float theirLeft = hit.bounds.min.x; | ||||
|                 float ourWidth = bounds.size.x; | ||||
|                 currentBlock.transform.position = new Vector3(theirLeft - ourWidth / 2f, currentBlock.transform.position.y, -1); | ||||
|                 Debug.Log("✅ Snap automatique à droite !"); | ||||
|                 return; | ||||
|             } | ||||
|         } | ||||
|             float topY = hit.collider.bounds.max.y; | ||||
|             float height = bounds.size.y; | ||||
|             float newY = topY + height / 2f; | ||||
|  | ||||
|         foreach (var hit in hitsLeft) | ||||
|         { | ||||
|             if (hit != null && hit.gameObject != currentBlock) | ||||
|             { | ||||
|                 float theirRight = hit.bounds.max.x; | ||||
|                 float ourWidth = bounds.size.x; | ||||
|                 currentBlock.transform.position = new Vector3(theirRight + ourWidth / 2f, currentBlock.transform.position.y, -1); | ||||
|                 Debug.Log("✅ Snap automatique à gauche !"); | ||||
|                 return; | ||||
|             } | ||||
|             currentBlock.transform.position = new Vector3(currentBlock.transform.position.x, newY, -1f); | ||||
|             Debug.Log($"📌 Bloc descendu sur {hit.collider.name} à Y={newY}"); | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             Debug.Log("❗ Aucun support trouvé en dessous pour aligner le bloc."); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     bool ShouldSkipVerticalSnap(string name) | ||||
|     { | ||||
|         name = name.ToLower(); | ||||
|         return name.Contains("smallobstacle") || name.Contains("portal"); | ||||
|     } | ||||
|  | ||||
|     void SnapBlockVertically() | ||||
|     { | ||||
|         Collider2D col = currentBlock.GetComponent<Collider2D>(); | ||||
|         Bounds bounds = col.bounds; | ||||
|  | ||||
|         float snapThreshold = 0.1f; // ➜ 0.1 unité = environ 2 pixels | ||||
|  | ||||
|         Vector2 checkStart = new Vector2(bounds.min.x, bounds.min.y - snapThreshold); | ||||
|         Vector2 checkEnd = new Vector2(bounds.max.x, bounds.min.y); | ||||
|  | ||||
|         Collider2D[] hitsBelow = Physics2D.OverlapAreaAll(checkStart, checkEnd); | ||||
|  | ||||
|         float highestY = -Mathf.Infinity; | ||||
|         GameObject bestTarget = null; | ||||
|  | ||||
|         foreach (var hit in hitsBelow) | ||||
|         { | ||||
|             if (hit != null && hit.gameObject != currentBlock) | ||||
|             if (hit == null || hit.gameObject == currentBlock || hit.transform.IsChildOf(currentBlock.transform)) | ||||
|                 continue; | ||||
|  | ||||
|             float top = hit.bounds.max.y; | ||||
|             if (top > highestY) | ||||
|             { | ||||
|                 float theirTop = hit.bounds.max.y; | ||||
|                 float ourHeight = bounds.size.y; | ||||
|                 currentBlock.transform.position = new Vector3(currentBlock.transform.position.x, theirTop + ourHeight / 2f, -1); | ||||
|                 Debug.Log("✅ Snap automatique en bas !"); | ||||
|                 return; | ||||
|                 highestY = top; | ||||
|                 bestTarget = hit.gameObject; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         foreach (var hit in hitsAbove) | ||||
|         if (bestTarget != null) | ||||
|         { | ||||
|             if (hit != null && hit.gameObject != currentBlock) | ||||
|             { | ||||
|                 float theirBottom = hit.bounds.min.y; | ||||
|                 float ourHeight = bounds.size.y; | ||||
|                 currentBlock.transform.position = new Vector3(currentBlock.transform.position.x, theirBottom - ourHeight / 2f, -1); | ||||
|                 Debug.Log("✅ Snap automatique en haut !"); | ||||
|                 return; | ||||
|             } | ||||
|             float blockHeight = bounds.size.y; | ||||
|             float snapY = highestY + blockHeight / 2f; | ||||
|  | ||||
|             currentBlock.transform.position = new Vector3(currentBlock.transform.position.x, snapY, -1f); | ||||
|             Debug.Log($"✅ Snap vertical à {snapY} sur {bestTarget.name}"); | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             Debug.Log("❌ Aucun bloc trouvé assez proche en dessous pour snap."); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|  | ||||
|     void InstantiateAndPrepare(GameObject prefab, Vector3? scaleOverride = null) | ||||
|     { | ||||
|         GameObject obj = Instantiate(prefab); | ||||
| @@ -439,15 +328,194 @@ public class LevelEditor : MonoBehaviour | ||||
|         obj.transform.localScale = scaleOverride ?? currentScale; | ||||
|  | ||||
|         try { obj.tag = prefab.name; } | ||||
|         catch { Debug.LogWarning($"Le tag '{prefab.name}' n'existe pas. Ajoutez-le dans Project Settings > Tags."); } | ||||
|         catch { Debug.LogWarning($"Le tag '{prefab.name}' est manquant."); } | ||||
|  | ||||
|         currentBlock = obj; | ||||
|         isPlacingBlock = true; | ||||
|     } | ||||
|  | ||||
|     private void HandleBlockRotation() | ||||
|     void HandleBlockRotation() | ||||
|     { | ||||
|         currentBlock.transform.Rotate(0f, 0f, -90f); // ➔ Rotation de 90° dans le sens horaire | ||||
|         currentBlock.transform.Rotate(0f, 0f, -90f); | ||||
|         Debug.Log("🔄 Bloc pivoté de 90° !"); | ||||
|     } | ||||
|  | ||||
|     #endregion | ||||
|  | ||||
|     #region Resizing & Deletion | ||||
|  | ||||
|     void HandleBlockResizing() | ||||
|     { | ||||
|         if (Input.GetMouseButtonDown(0) && Input.GetKey(KeyCode.LeftShift) && !isPlacingBlock) | ||||
|         { | ||||
|             Vector2 mousePos = Camera.main.ScreenToWorldPoint(Input.mousePosition); | ||||
|             Collider2D hit = Physics2D.OverlapPoint(mousePos); | ||||
|  | ||||
|             if (hit != null && !hit.CompareTag("Ground")) | ||||
|             { | ||||
|                 BeginResizing(hit.gameObject, mousePos); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         if (isResizing && resizingTarget != null) | ||||
|         { | ||||
|             PerformResizing(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     void BeginResizing(GameObject target, Vector2 mousePos) | ||||
|     { | ||||
|         resizingTarget = target; | ||||
|         originalMousePos = mousePos; | ||||
|         originalScale = target.transform.localScale; | ||||
|  | ||||
|         Vector2 localClick = mousePos - (Vector2)target.transform.position; | ||||
|         float ratio = target.GetComponent<Collider2D>().bounds.size.x / target.GetComponent<Collider2D>().bounds.size.y; | ||||
|  | ||||
|         currentResizeAxis = Mathf.Abs(localClick.x) > Mathf.Abs(localClick.y * ratio) | ||||
|             ? ResizeAxis.Horizontal | ||||
|             : ResizeAxis.Vertical; | ||||
|  | ||||
|         isResizing = true; | ||||
|         Debug.Log($"🧰 Début du redimensionnement : {target.name} (axe : {currentResizeAxis})"); | ||||
|     } | ||||
|  | ||||
|     void PerformResizing() | ||||
|     { | ||||
|         Vector3 currentMousePos = Camera.main.ScreenToWorldPoint(Input.mousePosition); | ||||
|         Vector3 delta = currentMousePos - originalMousePos; | ||||
|  | ||||
|         Vector3 newScale = originalScale; | ||||
|         if (currentResizeAxis == ResizeAxis.Horizontal) | ||||
|             newScale.x = Mathf.Max(0.1f, originalScale.x + delta.x); | ||||
|         else if (currentResizeAxis == ResizeAxis.Vertical) | ||||
|             newScale.y = Mathf.Max(0.1f, originalScale.y + delta.y); | ||||
|  | ||||
|         resizingTarget.transform.localScale = newScale; | ||||
|  | ||||
|         if (IsOverlapping(resizingTarget)) | ||||
|         { | ||||
|             resizingTarget.transform.localScale = originalScale; | ||||
|             Debug.Log("❌ Redimensionnement annulé : collision."); | ||||
|         } | ||||
|  | ||||
|         if (Input.GetMouseButtonUp(0)) | ||||
|         { | ||||
|             isResizing = false; | ||||
|             resizingTarget = null; | ||||
|             currentResizeAxis = ResizeAxis.None; | ||||
|             Debug.Log("✅ Fin du redimensionnement"); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     bool IsOverlapping(GameObject obj) | ||||
|     { | ||||
|         Bounds bounds = obj.GetComponent<Collider2D>().bounds; | ||||
|         Collider2D[] overlaps = Physics2D.OverlapBoxAll(bounds.center, bounds.size, 0f); | ||||
|  | ||||
|         foreach (var col in overlaps) | ||||
|         { | ||||
|             if (col.gameObject != obj) | ||||
|                 return true; | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     void HandleBlockDeletion() | ||||
|     { | ||||
|         if (Input.GetMouseButtonDown(1)) | ||||
|         { | ||||
|             Vector2 mousePos = Camera.main.ScreenToWorldPoint(Input.mousePosition); | ||||
|             Collider2D hit = Physics2D.OverlapPoint(mousePos); | ||||
|  | ||||
|             if (hit != null && !hit.CompareTag("Ground")) | ||||
|             { | ||||
|                 GameObject toDestroy = hit.gameObject; | ||||
|  | ||||
|                 // ✅ Cas spécial : ObstacleBlock ou ses enfants | ||||
|                 if (toDestroy.name.Contains("ObstacleSafer") || toDestroy.name.Contains("ObstacleKiller")) | ||||
|                 { | ||||
|                     Transform parent = toDestroy.transform.parent; | ||||
|                     if (parent != null && parent.name.Contains("ObstacleBlock")) | ||||
|                     { | ||||
|                         toDestroy = parent.gameObject; | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 if (toDestroy == currentBlock) | ||||
|                 { | ||||
|                     currentBlock = null; | ||||
|                     isPlacingBlock = false; | ||||
|                 } | ||||
|  | ||||
|                 Destroy(toDestroy); | ||||
|                 Debug.Log($"🗑️ Supprimé : {toDestroy.name}"); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     #endregion | ||||
|  | ||||
|     #region Utility | ||||
|  | ||||
|     bool IsPointerOverUI() | ||||
|     { | ||||
|         return EventSystem.current != null && EventSystem.current.IsPointerOverGameObject(); | ||||
|     } | ||||
|  | ||||
|     void TrySnapToNearbyBlock() | ||||
|     { | ||||
|         if (currentBlock == null) return; | ||||
|  | ||||
|         Collider2D blockCollider = currentBlock.GetComponent<Collider2D>(); | ||||
|         Bounds bounds = blockCollider.bounds; | ||||
|         float snapDistance = 1f; | ||||
|  | ||||
|         Vector2[] directions = | ||||
|         { | ||||
|             Vector2.right, Vector2.left, Vector2.down, Vector2.up | ||||
|         }; | ||||
|  | ||||
|         foreach (var dir in directions) | ||||
|         { | ||||
|             Vector2 extent2D = new Vector2(bounds.extents.x, bounds.extents.y); | ||||
|             Vector2 start = (Vector2)bounds.center + dir * (extent2D + Vector2.one * (snapDistance / 2f)); | ||||
|             Collider2D[] hits = Physics2D.OverlapCircleAll(start, snapDistance); | ||||
|  | ||||
|             foreach (var hit in hits) | ||||
|             { | ||||
|                 if (hit != null && hit.gameObject != currentBlock) | ||||
|                 { | ||||
|                     SnapToTarget(hit, dir); | ||||
|                     return; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     void SnapToTarget(Collider2D hit, Vector2 dir) | ||||
|     { | ||||
|         Bounds hitBounds = hit.bounds; | ||||
|         Bounds ourBounds = currentBlock.GetComponent<Collider2D>().bounds; | ||||
|  | ||||
|         Vector3 newPos = currentBlock.transform.position; | ||||
|  | ||||
|         if (dir == Vector2.right) | ||||
|             newPos.x = hitBounds.min.x - ourBounds.size.x / 2f; | ||||
|         else if (dir == Vector2.left) | ||||
|             newPos.x = hitBounds.max.x + ourBounds.size.x / 2f; | ||||
|         else if (dir == Vector2.down) | ||||
|             newPos.y = hitBounds.max.y + ourBounds.size.y / 2f; | ||||
|         else if (dir == Vector2.up) | ||||
|             newPos.y = hitBounds.min.y - ourBounds.size.y / 2f; | ||||
|  | ||||
|         currentBlock.transform.position = new Vector3(newPos.x, newPos.y, -1); | ||||
|         Debug.Log("✅ Snap à " + dir); | ||||
|     } | ||||
|  | ||||
|     public void Save() | ||||
|     { | ||||
|         // TODO : Sauvegarde du niveau | ||||
|     } | ||||
|  | ||||
|     #endregion | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user