Commit c59801ad authored by Mahmoud Aglan's avatar Mahmoud Aglan

Fixes Some performance headaches in the mcq game

parent e94cf53a
{"TestSuite":"","Date":0,"Player":{"Development":false,"ScreenWidth":0,"ScreenHeight":0,"ScreenRefreshRate":0,"Fullscreen":false,"Vsync":0,"AntiAliasing":0,"Batchmode":false,"RenderThreadingMode":"MultiThreaded","MtRendering":false,"GraphicsJobs":false,"GpuSkinning":true,"Platform":"","ColorSpace":"","AnisotropicFiltering":"","BlendWeights":"","GraphicsApi":"","ScriptingBackend":"IL2CPP","AndroidTargetSdkVersion":"AndroidApiLevelAuto","AndroidBuildSystem":"Gradle","BuildTarget":"Android","StereoRenderingPath":"MultiPass"},"Hardware":{"OperatingSystem":"","DeviceModel":"","DeviceName":"","ProcessorType":"","ProcessorCount":0,"GraphicsDeviceName":"","SystemMemorySizeMB":0},"Editor":{"Version":"6000.3.9f1","Branch":"6000.3/staging","Changeset":"7a9955a4f2fa","Date":1770746648},"Dependencies":["com.cysharp.unitask@2.5.10","com.github-glitchenzo.nugetforunity@4.5.0","com.unity.2d.sprite@1.0.0","com.unity.ai.navigation@2.0.11","com.unity.cinemachine@3.1.6","com.unity.collab-proxy@2.11.4","com.unity.ide.rider@3.0.39","com.unity.ide.visualstudio@2.0.26","com.unity.inputsystem@1.19.0","com.unity.multiplayer.center@1.0.1","com.unity.nuget.newtonsoft-json@3.2.2","com.unity.postprocessing@3.5.4","com.unity.recorder@5.1.6","com.unity.render-pipelines.universal@17.3.0","com.unity.shadergraph@17.3.0","com.unity.test-framework@1.6.0","com.unity.timeline@1.8.11","com.unity.ugui@2.0.0","com.unity.visualeffectgraph@17.3.0","com.unity.visualscripting@1.9.11","media.lightside.unitext@1.0.0","com.unity.modules.accessibility@1.0.0","com.unity.modules.adaptiveperformance@1.0.0","com.unity.modules.ai@1.0.0","com.unity.modules.androidjni@1.0.0","com.unity.modules.animation@1.0.0","com.unity.modules.assetbundle@1.0.0","com.unity.modules.audio@1.0.0","com.unity.modules.cloth@1.0.0","com.unity.modules.director@1.0.0","com.unity.modules.imageconversion@1.0.0","com.unity.modules.imgui@1.0.0","com.unity.modules.jsonserialize@1.0.0","com.unity.modules.particlesystem@1.0.0","com.unity.modules.physics@1.0.0","com.unity.modules.physics2d@1.0.0","com.unity.modules.screencapture@1.0.0","com.unity.modules.terrain@1.0.0","com.unity.modules.terrainphysics@1.0.0","com.unity.modules.tilemap@1.0.0","com.unity.modules.ui@1.0.0","com.unity.modules.uielements@1.0.0","com.unity.modules.umbra@1.0.0","com.unity.modules.unityanalytics@1.0.0","com.unity.modules.unitywebrequest@1.0.0","com.unity.modules.unitywebrequestassetbundle@1.0.0","com.unity.modules.unitywebrequestaudio@1.0.0","com.unity.modules.unitywebrequesttexture@1.0.0","com.unity.modules.unitywebrequestwww@1.0.0","com.unity.modules.vectorgraphics@1.0.0","com.unity.modules.vehicles@1.0.0","com.unity.modules.video@1.0.0","com.unity.modules.vr@1.0.0","com.unity.modules.wind@1.0.0","com.unity.modules.xr@1.0.0","com.unity.modules.subsystems@1.0.0","com.unity.modules.hierarchycore@1.0.0","com.unity.render-pipelines.core@17.3.0","com.unity.ext.nunit@2.0.5","com.unity.searcher@4.9.4","com.unity.render-pipelines.universal-config@17.0.3","com.unity.collections@2.6.2","com.unity.bindings.openimageio@1.0.2","com.unity.splines@2.8.2","com.unity.burst@1.8.28","com.unity.mathematics@1.3.3","com.unity.nuget.mono-cecil@1.11.6","com.unity.test-framework.performance@3.2.0","com.unity.settings-manager@2.1.1"],"Results":[]}
\ No newline at end of file
{"MeasurementCount":-1}
\ No newline at end of file
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
......@@ -134,36 +135,70 @@ namespace com.al_arcade.mcq
}
// Combined dashes into a single mesh (100 objects → 1)
{
var tempCube = GameObject.CreatePrimitive(PrimitiveType.Cube);
var cubeMesh = tempCube.GetComponent<MeshFilter>().sharedMesh;
Destroy(tempCube);
var combines = new List<CombineInstance>();
for (float z = 0; z < 400; z += 4)
{
var dash = GameObject.CreatePrimitive(PrimitiveType.Cube);
dash.name = "Dash";
dash.transform.position = new Vector3(0, 0.01f, z);
dash.transform.localScale = new Vector3(0.05f, 0.01f, 2f);
Destroy(dash.GetComponent<Collider>());
dash.GetComponent<Renderer>().material = new Material(shader)
combines.Add(new CombineInstance
{
mesh = cubeMesh,
transform = Matrix4x4.TRS(
new Vector3(0, 0.01f, z),
Quaternion.identity,
new Vector3(0.05f, 0.01f, 2f))
});
}
var dashObj = new GameObject("RoadDashes");
var mf = dashObj.AddComponent<MeshFilter>();
var mr = dashObj.AddComponent<MeshRenderer>();
var combined = new Mesh();
combined.CombineMeshes(combines.ToArray(), true, true);
mf.mesh = combined;
mr.material = new Material(shader)
{ color = SSColorPalette.WithAlpha(Color.white, 0.2f) };
}
// Combined side blocks into a single mesh (40 objects → 1)
{
var tempCube = GameObject.CreatePrimitive(PrimitiveType.Cube);
var cubeMesh = tempCube.GetComponent<MeshFilter>().sharedMesh;
Destroy(tempCube);
var combines = new List<CombineInstance>();
for (int side = -1; side <= 1; side += 2)
{
for (float z = 0; z < 400; z += 20)
{
var block = GameObject.CreatePrimitive(PrimitiveType.Cube);
block.name = "SideBlock";
float h = Random.Range(2f, 5f);
block.transform.position = new Vector3(side * 12f, h / 2f, z);
block.transform.localScale = new Vector3(
Random.Range(2f, 4f), h, Random.Range(3f, 8f));
Destroy(block.GetComponent<Collider>());
var c = Color.Lerp(SSColorPalette.Primary,
SSColorPalette.PrimaryLight, Random.value);
block.GetComponent<Renderer>().material = new Material(shader)
{ color = SSColorPalette.WithAlpha(c, 0.4f) };
combines.Add(new CombineInstance
{
mesh = cubeMesh,
transform = Matrix4x4.TRS(
new Vector3(side * 12f, h / 2f, z),
Quaternion.identity,
new Vector3(Random.Range(2f, 4f), h, Random.Range(3f, 8f)))
});
}
}
var blocksObj = new GameObject("SideBlocks");
var mf = blocksObj.AddComponent<MeshFilter>();
var mr = blocksObj.AddComponent<MeshRenderer>();
var combined = new Mesh();
combined.CombineMeshes(combines.ToArray(), true, true);
mf.mesh = combined;
var midColor = Color.Lerp(SSColorPalette.Primary, SSColorPalette.PrimaryLight, 0.5f);
mr.material = new Material(shader)
{ color = SSColorPalette.WithAlpha(midColor, 0.4f) };
}
var horizon = GameObject.CreatePrimitive(PrimitiveType.Cube);
horizon.name = "Horizon";
......
......@@ -50,6 +50,10 @@ namespace com.al_arcade.mcq
private Camera _mainCamera;
private bool _isTicking;
// Gate object pool — reuse instead of Instantiate/Destroy per question
private List<McqGateController> _gatePool = new();
private const int GatePoolSize = 6;
// ✅ NEW: CS-style progress counter
// goes +1 on correct, -1 on wrong, clamped to [0, pointsToWin]
private int _deltaChangeInSize;
......@@ -176,6 +180,7 @@ namespace com.al_arcade.mcq
// ─── BeginGameplay ───────────────────────────────────────────────────
protected override void BeginGameplay()
{
InitGatePool();
_currentIndex = _score = _streak = _correctCount = _wrongCount = 0;
_bestStreak = 0;
......@@ -327,7 +332,7 @@ namespace com.al_arcade.mcq
DOTween.Kill(gate.transform);
gate.transform.DOScale(Vector3.zero, 0.3f)
.SetEase(Ease.InBack)
.OnComplete(() => { if (gate != null) Destroy(gate.gameObject); });
.OnComplete(() => { if (gate != null) gate.Recycle(); });
}
}
_activeGates.Clear();
......@@ -455,12 +460,82 @@ namespace com.al_arcade.mcq
if (g != null)
{
DOTween.Kill(g.transform);
Destroy(g.gameObject);
g.Recycle();
}
}
_activeGates.Clear();
}
// ─── Gate Pool ──────────────────────────────────────────────────────
private void InitGatePool()
{
if (_gatePool.Count > 0) return;
GameObject prefab = prefabBuilder != null ? prefabBuilder.GetGatePrefab() : null;
for (int i = 0; i < GatePoolSize; i++)
{
GameObject go;
McqGateController gate;
if (prefab == null)
{
go = new GameObject($"Gate_Pool_{i}");
gate = go.AddComponent<McqGateController>();
}
else
{
go = Instantiate(prefab);
gate = go.GetComponent<McqGateController>();
}
if (gateParent != null) go.transform.SetParent(gateParent);
go.SetActive(false);
_gatePool.Add(gate);
}
}
private McqGateController GetGateFromPool(Vector3 position, int index,
string answerText, bool isCorrect)
{
McqGateController gate = null;
for (int i = 0; i < _gatePool.Count; i++)
{
if (!_gatePool[i].gameObject.activeSelf)
{
gate = _gatePool[i];
break;
}
}
// Pool exhausted — expand
if (gate == null)
{
GameObject prefab = prefabBuilder != null ? prefabBuilder.GetGatePrefab() : null;
GameObject go;
if (prefab == null)
{
go = new GameObject($"Gate_Pool_{_gatePool.Count}");
gate = go.AddComponent<McqGateController>();
}
else
{
go = Instantiate(prefab);
gate = go.GetComponent<McqGateController>();
}
if (gateParent != null) go.transform.SetParent(gateParent);
_gatePool.Add(gate);
}
gate.transform.position = position;
gate.gameObject.SetActive(true);
gate.Setup(index, answerText, isCorrect);
return gate;
}
// ─── Gate Spawning ───────────────────────────────────────────────────
private void SpawnGates(McqQuestion question)
{
......@@ -481,7 +556,7 @@ namespace com.al_arcade.mcq
for (int i = 0; i < answers.Length; i++)
{
Vector3 gatePos = basePos + Vector3.right * (startX + i * gateSpacing);
var gate = CreateGate(gatePos, i, answers[i], i == _correctGateIndex);
var gate = GetGateFromPool(gatePos, i, answers[i], i == _correctGateIndex);
_activeGates.Add(gate);
gate.transform.DOScale(Vector3.one, 0.5f)
......@@ -491,34 +566,6 @@ namespace com.al_arcade.mcq
}
}
private McqGateController CreateGate(Vector3 position, int index,
string answerText, bool isCorrect)
{
GameObject gatePrefab = prefabBuilder != null ? prefabBuilder.GetGatePrefab() : null;
GameObject go;
if (gatePrefab == null)
{
go = new GameObject($"Gate_{index}");
go.transform.position = position;
}
else
{
go = Instantiate(gatePrefab, position, Quaternion.identity);
}
if (gateParent != null) go.transform.SetParent(gateParent);
McqGateController gate;
if (gatePrefab == null)
gate = go.AddComponent<McqGateController>();
else
gate = go.GetComponent<McqGateController>();
gate.Setup(index, answerText, isCorrect);
return gate;
}
// ─── Feedback ────────────────────────────────────────────────────────
private void ShowCorrectFeedback(int points)
{
......
......@@ -24,6 +24,7 @@ namespace com.al_arcade.mcq
private MaterialPropertyBlock _mpb;
private Sequence _idleAnim;
private Sequence _glowAnim;
private bool _built;
private const float GateWidth = 2.5f;
private const float GateHeight = 3.5f;
......@@ -48,12 +49,33 @@ namespace com.al_arcade.mcq
IsCorrect = correct;
WasEntered = false;
EnsureMaterial();
if (_built)
UpdateContent();
else
{
BuildVisuals();
_built = true;
}
if (_mpb != null)
SetPanelColor(SSColorPalette.GateDefault);
StartIdleAnimation();
}
public void Start()
{
EnsureMaterial();
if (_mpb != null)
SetPanelColor(SSColorPalette.GateDefault);
}
private void EnsureMaterial()
{
if (_panelRenderer == null || _mpb != null) return;
if (_sharedGateMaterial == null)
{
_sharedGateMaterial = new Material(_panelRenderer.material.shader);
......@@ -61,9 +83,7 @@ namespace com.al_arcade.mcq
}
_panelRenderer.sharedMaterial = _sharedGateMaterial;
_panelMaterial = _sharedGateMaterial;
_mpb = new MaterialPropertyBlock();
SetPanelColor(SSColorPalette.GateDefault);
}
private void SetPanelColor(Color color)
......@@ -73,6 +93,30 @@ namespace com.al_arcade.mcq
_panelRenderer.SetPropertyBlock(_mpb);
}
private void UpdateContent()
{
if (_answerText != null)
{
_answerText.Text = AnswerText;
_answerTextShadow.Text = AnswerText;
}
else if (_label != null)
{
_label.arabicText = AnswerText;
}
}
public void Recycle()
{
KillAllTweens();
WasEntered = false;
onPlayerEnter = null;
transform.localScale = Vector3.one;
if (_mpb != null)
SetPanelColor(SSColorPalette.GateDefault);
gameObject.SetActive(false);
}
private void BuildVisuals()
{
var shader = GetShader();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment