fix: edit a level (#66)

Co-authored-by: Djelal BOUDJI <djelal@gmail.com>
Co-authored-by: Théo LUDWIG <contact@theoludwig.fr>
This commit is contained in:
M VINCENT PETT 2025-05-16 20:03:37 +02:00 committed by GitHub
parent 0b32ce7036
commit 728c57c66c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 209 additions and 66 deletions

View File

@ -1,7 +1,4 @@
using System.IO;
using UnityEngine;
using UnityEngine.SceneManagement;
public class NormalGameMode : IGameMode
{
@ -18,7 +15,6 @@ public class NormalGameMode : IGameMode
if (player.IsColliding && Input.GetKey(JumpKey) && !isRotating)
{
Debug.Log("Player is Jumping");
Jump(player);
}

View File

@ -51,6 +51,10 @@ public class LevelEditor : MonoBehaviour
HandleBlockDeletion();
}
void OnDestroy()
{
ClearEditor();
}
#region UI
void LoadPrefabs()
@ -176,7 +180,6 @@ public class LevelEditor : MonoBehaviour
foreach (var h in hits)
{
if (h == col) continue;
if (h.CompareTag("Ground")) continue;
if (h.transform.IsChildOf(currentBlock.transform)) continue;
return false;
}
@ -198,7 +201,7 @@ public class LevelEditor : MonoBehaviour
currentBlock = sel;
isPlacingBlock = true;
currentScale = currentBlock.transform.localScale;
Debug.Log($"🟢 Sélection : {sel.name}");
Debug.Log($"Sélection : {sel.name}");
}
}
void PlaceBlock()
@ -211,7 +214,7 @@ public class LevelEditor : MonoBehaviour
// 1) Bloquer si on perçoit un spike de même type dans la direction de snap
if (IsBlockedBySameTypeInSnapDirection())
{
Debug.LogError("Impossible de poser un spike sur un autre spike !");
Debug.LogError("Impossible de poser un spike sur un autre spike !");
Destroy(currentBlock);
}
else
@ -219,7 +222,7 @@ public class LevelEditor : MonoBehaviour
// 2) On snap dans la direction (down/left/up/right), et on détruit si aucun support
if (!SnapSpikeByRotation())
{
Debug.LogError("Impossible de poser un spike dans le vide !");
Debug.LogError("Impossible de poser un spike dans le vide !");
Destroy(currentBlock);
}
else
@ -370,7 +373,7 @@ public class LevelEditor : MonoBehaviour
else if (dir == Vector2.right) p.x = bestHit.point.x - hw;
currentBlock.transform.position = new Vector3(p.x, p.y, -1f);
Debug.Log($"📌 Spike snapé {dir} sur « {bestHit.collider.name} » à {currentBlock.transform.position}");
Debug.Log($"Spike snapé {dir} sur « {bestHit.collider.name} » à {currentBlock.transform.position}");
return true;
}
@ -403,7 +406,7 @@ public class LevelEditor : MonoBehaviour
? ResizeAxis.Horizontal
: ResizeAxis.Vertical;
isResizing = true;
Debug.Log($"🧰 Début redim {tgt.name} (axe {currentResizeAxis})");
Debug.Log($"Début redim {tgt.name} (axe {currentResizeAxis})");
}
void PerformResizing()
@ -419,14 +422,14 @@ public class LevelEditor : MonoBehaviour
if (IsOverlapping(resizingTarget))
{
resizingTarget.transform.localScale = originalScale;
Debug.Log("Redim annulé : collision");
Debug.Log("Redim annulé : collision");
}
if (Input.GetMouseButtonUp(0))
{
isResizing = false;
resizingTarget = null;
currentResizeAxis = ResizeAxis.None;
Debug.Log("Fin redim");
Debug.Log("Fin redim");
}
}
@ -452,7 +455,7 @@ public class LevelEditor : MonoBehaviour
toD = toD.transform.parent.gameObject;
if (toD == currentBlock) { currentBlock = null; isPlacingBlock = false; }
Destroy(toD);
Debug.Log($"🗑️ Supprimé {toD.name}");
Debug.Log($"Supprimé {toD.name}");
}
}
@ -470,45 +473,88 @@ public class LevelEditor : MonoBehaviour
var col = currentBlock.GetComponent<Collider2D>();
var b = col.bounds;
float snapDistance = 1f;
float verticalEps = 0.05f; // petite marge pour exclure trop hauts ou trop bas
float verticalEps = 0.1f;
// Taille et positions des deux zones de recherche latérales
Vector2 boxSize = new Vector2(snapDistance, b.size.y - verticalEps * 2f);
// à droite
// === SNAP HORIZONTAL (droite)
Vector2 hBoxSize = new Vector2(snapDistance, b.size.y - verticalEps * 2f);
Vector2 rightCenter = new Vector2(b.max.x + snapDistance / 2f, b.center.y);
// à gauche
Vector2 leftCenter = new Vector2(b.min.x - snapDistance / 2f, b.center.y);
// Cherche à droite
var hits = Physics2D.OverlapBoxAll(rightCenter, boxSize, 0f);
var hits = Physics2D.OverlapBoxAll(rightCenter, hBoxSize, 0f);
foreach (var h in hits)
{
if (h != null && h.gameObject != currentBlock && !h.isTrigger)
{
float newX = h.bounds.min.x - b.extents.x;
currentBlock.transform.position = new Vector3(newX, currentBlock.transform.position.y, -1f);
Debug.Log($"↔️ Snap horizontal à droite contre {h.name}");
return;
}
if (IsInvalidSnapTarget(h)) continue;
float newX = h.bounds.min.x - b.extents.x;
currentBlock.transform.position = new Vector3(newX, currentBlock.transform.position.y, -1f);
Debug.Log($"Snap horizontal à droite contre {h.name}");
return;
}
// Cherche à gauche
hits = Physics2D.OverlapBoxAll(leftCenter, boxSize, 0f);
// === SNAP HORIZONTAL (gauche)
Vector2 leftCenter = new Vector2(b.min.x - snapDistance / 2f, b.center.y);
hits = Physics2D.OverlapBoxAll(leftCenter, hBoxSize, 0f);
foreach (var h in hits)
{
if (h != null && h.gameObject != currentBlock && !h.isTrigger)
{
float newX = h.bounds.max.x + b.extents.x;
currentBlock.transform.position = new Vector3(newX, currentBlock.transform.position.y, -1f);
Debug.Log($"↔️ Snap horizontal à gauche contre {h.name}");
return;
}
if (IsInvalidSnapTarget(h)) continue;
float newX = h.bounds.max.x + b.extents.x;
currentBlock.transform.position = new Vector3(newX, currentBlock.transform.position.y, -1f);
Debug.Log($"Snap horizontal à gauche contre {h.name}");
return;
}
// === SNAP VERTICAL (dessous)
Vector2 downBoxSize = new Vector2(b.size.x - 0.1f, snapDistance);
Vector2 downCenter = new Vector2(b.center.x, b.min.y - snapDistance / 2f);
hits = Physics2D.OverlapBoxAll(downCenter, downBoxSize, 0f);
foreach (var h in hits)
{
if (IsInvalidSnapTarget(h)) continue;
float newY = h.bounds.max.y + b.extents.y;
currentBlock.transform.position = new Vector3(currentBlock.transform.position.x, newY, -1f);
Debug.Log($"Snap vertical (bas) contre {h.name}");
return;
}
// === SNAP VERTICAL (au-dessus)
Vector2 upCenter = new Vector2(b.center.x, b.max.y + snapDistance / 2f);
hits = Physics2D.OverlapBoxAll(upCenter, downBoxSize, 0f);
foreach (var h in hits)
{
if (IsInvalidSnapTarget(h)) continue;
float newY = h.bounds.min.y - b.extents.y;
currentBlock.transform.position = new Vector3(currentBlock.transform.position.x, newY, -1f);
Debug.Log($"Snap vertical (haut) contre {h.name}");
return;
}
}
bool IsInvalidSnapTarget(Collider2D h)
{
if (h == null || h.gameObject == currentBlock || h.isTrigger) return true;
var t = h.transform;
if (t.parent != null && t.parent.name.Contains("ObstacleBlock"))
{
if (t.name.Contains("ObstacleKiller") || t.name.Contains("ObstacleSafer"))
return true;
}
return false;
}
// Filtrage des enfants parasites
bool IsChildOfObstacleBlock(Collider2D col)
{
var t = col.transform;
if (t.parent == null) return false;
bool isNamedObstacleChild = t.name.Contains("ObstacleSafer") || t.name.Contains("ObstacleKiller");
bool parentIsBlock = t.parent.name.Contains("ObstacleBlock");
return isNamedObstacleChild && parentIsBlock;
}
void HandleBlockRotation()
{
currentBlock.transform.Rotate(0, 0, -90f);
Debug.Log("🔄 Rotation 90°!");
Debug.Log("Rotation 90°!");
}
void InstantiateAndPrepare(GameObject prefab, Vector3? scaleOverride = null)
@ -523,8 +569,25 @@ public class LevelEditor : MonoBehaviour
public void Save()
{
// TODO
}
#endregion
public void ClearEditor()
{
if (persistentBlockContainer == null) return;
foreach (Transform child in persistentBlockContainer)
{
Destroy(child.gameObject);
}
Debug.Log("Éditeur vidé.");
currentBlock = null;
isPlacingBlock = false;
currentPage = 0;
ClearCurrentButtons();
GenerateButtons();
}
}

View File

@ -13,7 +13,12 @@ public class LevelLoader : MonoBehaviour
private GameObject GetPrefab(string type)
{
return Resources.Load<GameObject>("Prefabs/" + type);
var prefab = Resources.Load<GameObject>("Prefabs/" + type);
if (prefab == null)
{
Debug.LogError($"Prefab introuvable pour : {type}");
}
return prefab;
}
private void LoadAudio()
@ -28,29 +33,95 @@ public class LevelLoader : MonoBehaviour
{
musicSource.volume = 1f;
}
musicSource.Play();
}
private void LoadElements()
{
Level current = levelsLoader.levelCurrent;
foreach (var element in current.elements)
{
GameObject prefab = GetPrefab(element.type);
GameObject instance = Instantiate(prefab, new Vector3(element.x, element.y, 0), Quaternion.identity);
if (prefab == null) continue;
if (prefab.CompareTag("Kill"))
GameObject instance = Instantiate(
prefab,
new Vector3(element.x, element.y, 0),
Quaternion.identity
);
if (editMode)
{
Instantiate(Resources.Load<GameObject>("AICollider"), new Vector3(element.x - 1, element.y, 0), Quaternion.identity);
foreach (Transform child in instance.transform)
{
if (child.name.Contains("ObstacleKiller"))
{
var col = child.GetComponent<BoxCollider2D>();
if (col != null && col.size.y > 2f) // Trop grand
{
Debug.LogWarning($"⚠️ Collider {child.name} trop grand, réduction appliquée.");
col.size = new Vector2(col.size.x, 1f);
col.offset = new Vector2(col.offset.x, -2f); // Ajuste selon ton design
}
}
}
}
// En mode jeu/test uniquement → ajout du AICollider
if (!editMode)
{
if (prefab.CompareTag("Kill"))
{
Instantiate(
Resources.Load<GameObject>("AICollider"),
new Vector3(element.x - 1, element.y, 0),
Quaternion.identity
);
}
}
// Appliquer l'échelle personnalisée
Vector3 originalScale = instance.transform.localScale;
float newScaleX = element.scaleX > 0 ? element.scaleX : originalScale.x;
float newScaleY = element.scaleY > 0 ? element.scaleY : originalScale.y;
instance.transform.localScale = new Vector3(newScaleX, newScaleY, originalScale.z);
}
// Sol uniquement en mode jeu
if (!editMode)
{
GameObject groundPrefab = GetPrefab("Ground");
if (groundPrefab != null)
{
GameObject groundInstance = Instantiate(
groundPrefab,
new Vector3(current.LastX / 2, groundY, 0),
Quaternion.identity
);
groundInstance.transform.localScale = new Vector3(current.LastX / 5f * 2, 1, 1);
}
}
// Mur de fin toujours placé
GameObject winWall = GetPrefab("WinnerWall");
if (winWall != null)
{
Instantiate(
winWall,
new Vector3(current.LastX, 0, 0),
Quaternion.Euler(0, 0, 90)
);
}
}
private void Awake()
{
levelsLoader = GameObject.FindGameObjectWithTag("LevelsLoader").GetComponent<LevelsLoader>();
Level current = levelsLoader.levelCurrent;
createMode = PlayerPrefs.GetInt("CreateMode", 0) == 1;
if (!editMode)
{
GameObject groundPrefab = GetPrefab("Ground");
@ -63,10 +134,12 @@ public class LevelLoader : MonoBehaviour
public void Start()
{
createMode = PlayerPrefs.GetInt("CreateMode", 0) == 1;
if (!createMode)
{
levelsLoader = GameObject.FindGameObjectWithTag("LevelsLoader").GetComponent<LevelsLoader>();
levelsLoader = GameObject
.FindGameObjectWithTag("LevelsLoader")
.GetComponent<LevelsLoader>();
levelsLoader.IncreaseTotalAttempts();
LoadElements();
@ -79,8 +152,7 @@ public class LevelLoader : MonoBehaviour
{
if (!editMode)
{
Level current = levelsLoader.levelCurrent;
progressionText.text = current.ProgressionPercent + "%";
progressionText.text = levelsLoader.levelCurrent.ProgressionPercent + "%";
}
}
}

View File

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 588b3f9ce673f764b8a3a81842ed9f46
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -91,22 +91,25 @@ public class Player : MonoBehaviour
{
CurrentGameMode?.OnCollisionEnter(this, collision);
if (editMode && (collision.gameObject.CompareTag("Kill") || collision.gameObject.CompareTag("Win")))
{
GameObject spawn = new GameObject("AutoSpawnPoint");
spawn.transform.position = new Vector3(-16, -3, 0f);
transform.position = spawn.transform.position;
RigidBody.linearVelocity = Vector2.zero;
SpeedMultiplier = 1f;
CurrentGameMode = new NormalGameMode();
SpriteRenderer.sprite = Resources.Load<Sprite>("Shapes/BaseSquare");
return;
}
if (collision.gameObject.CompareTag("Kill"))
{
if (editMode)
{
GameObject spawn = new GameObject("AutoSpawnPoint");
spawn.transform.position = new Vector3(-16, -3, 0f);
transform.position = spawn.transform.position;
RigidBody.linearVelocity = Vector2.zero;
SpeedMultiplier = 1f;
}
else
{
sfxSource.clip = Resources.Load<AudioClip>(Path.Combine("Sounds", "death"));
sfxSource.Play();
StartCoroutine(LevelHomeButton.PlaySoundAndLoadScene(sfxSource, SceneManager.GetActiveScene().name));
}
sfxSource.clip = Resources.Load<AudioClip>(Path.Combine("Sounds", "death"));
sfxSource.Play();
StartCoroutine(LevelHomeButton.PlaySoundAndLoadScene(sfxSource, SceneManager.GetActiveScene().name));
}
if (collision.gameObject.CompareTag("Win"))

View File

@ -76,6 +76,8 @@ public class TestManager : MonoBehaviour
}
currentPlayer.transform.position = spawnPoint.position;
currentPlayer.transform.rotation = Quaternion.Euler(0f, 0f, 0f);
currentPlayer.RigidBody.freezeRotation = true;
currentPlayer.RigidBody.linearVelocity = Vector2.zero;
currentPlayer.SpeedMultiplier = 1f;
// currentPlayer.SpriteRenderer.sprite = Resources.Load<Sprite>("Shapes/BaseSquare");
@ -93,7 +95,7 @@ public class TestManager : MonoBehaviour
currentPlayer.SpriteRenderer.enabled = true;
if (currentPlayer.Particle != null)
currentPlayer.Particle.Play(); // Démarrer la particule
currentPlayer.Particle.Play(); // Démarrer la particule
Debug.Log("[TestManager] Test du niveau démarré !");
}
@ -110,7 +112,7 @@ public class TestManager : MonoBehaviour
currentPlayer.SpeedMultiplier = 0f;
if (currentPlayer.Particle != null)
currentPlayer.Particle.Stop(true, ParticleSystemStopBehavior.StopEmittingAndClear); // Arrêter proprement
currentPlayer.Particle.Stop(true, ParticleSystemStopBehavior.StopEmittingAndClear); // Arrêter proprement
if (currentPlayer.SpriteRenderer != null)
currentPlayer.SpriteRenderer.enabled = false;