Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
S
SSBookMinigames
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Administrator
SSBookMinigames
Commits
0ba46a41
Commit
0ba46a41
authored
Apr 02, 2026
by
Yousef Sameh
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote-tracking branch 'origin/New-MCQ' into Supabase
parents
cae9d3fe
571053a6
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
248 additions
and
18 deletions
+248
-18
New MSQ.unity
My project/Assets/Scenes/MCQ/New MSQ.unity
+25
-5
AnswerButtonUI.cs
...ct/Assets/ScienceStreet/MCQ/Scripts/New/AnswerButtonUI.cs
+45
-6
NewMCQGameManger.cs
.../Assets/ScienceStreet/MCQ/Scripts/New/NewMCQGameManger.cs
+1
-0
QuestionUi.cs
...roject/Assets/ScienceStreet/MCQ/Scripts/New/QuestionUi.cs
+177
-7
No files found.
My project/Assets/Scenes/MCQ/New MSQ.unity
View file @
0ba46a41
...
...
@@ -740,7 +740,7 @@ MonoBehaviour:
button
:
{
fileID
:
652543888
}
answerImageComponent
:
{
fileID
:
505502773
}
answerTextComponent
:
{
fileID
:
1714205094
}
answerLayout
:
{
fileID
:
0
}
answerLayout
:
{
fileID
:
652543886
}
buttonBackgroundImage
:
{
fileID
:
652543889
}
normalColor
:
{
r
:
1
,
g
:
1
,
b
:
1
,
a
:
1
}
normalTextColor
:
{
r
:
0
,
g
:
0
,
b
:
0
,
a
:
1
}
...
...
@@ -1614,7 +1614,7 @@ MonoBehaviour:
button
:
{
fileID
:
1001118205
}
answerImageComponent
:
{
fileID
:
36657994
}
answerTextComponent
:
{
fileID
:
2077715403
}
answerLayout
:
{
fileID
:
0
}
answerLayout
:
{
fileID
:
1001118203
}
buttonBackgroundImage
:
{
fileID
:
1001118206
}
normalColor
:
{
r
:
1
,
g
:
1
,
b
:
1
,
a
:
1
}
normalTextColor
:
{
r
:
0
,
g
:
0
,
b
:
0
,
a
:
1
}
...
...
@@ -1956,7 +1956,7 @@ MonoBehaviour:
button
:
{
fileID
:
1418877171
}
answerImageComponent
:
{
fileID
:
1130655416
}
answerTextComponent
:
{
fileID
:
1471177263
}
answerLayout
:
{
fileID
:
0
}
answerLayout
:
{
fileID
:
1418877169
}
buttonBackgroundImage
:
{
fileID
:
1418877172
}
normalColor
:
{
r
:
1
,
g
:
1
,
b
:
1
,
a
:
1
}
normalTextColor
:
{
r
:
0
,
g
:
0
,
b
:
0
,
a
:
1
}
...
...
@@ -2548,7 +2548,7 @@ MonoBehaviour:
button
:
{
fileID
:
1951693014
}
answerImageComponent
:
{
fileID
:
650788013
}
answerTextComponent
:
{
fileID
:
922617402
}
answerLayout
:
{
fileID
:
0
}
answerLayout
:
{
fileID
:
1951693018
}
buttonBackgroundImage
:
{
fileID
:
1951693015
}
normalColor
:
{
r
:
1
,
g
:
1
,
b
:
1
,
a
:
1
}
normalTextColor
:
{
r
:
0
,
g
:
0
,
b
:
0
,
a
:
1
}
...
...
@@ -2689,6 +2689,7 @@ GameObject:
-
component
:
{
fileID
:
2061407676
}
-
component
:
{
fileID
:
2061407678
}
-
component
:
{
fileID
:
2061407677
}
-
component
:
{
fileID
:
2061407680
}
-
component
:
{
fileID
:
2061407679
}
m_Layer
:
5
m_Name
:
Question Panel
...
...
@@ -2768,6 +2769,8 @@ MonoBehaviour:
m_Script
:
{
fileID
:
11500000
,
guid
:
68aee830395e108478a9643b20de1689
,
type
:
3
}
m_Name
:
m_EditorClassIdentifier
:
Assembly-CSharp::QuestionUi
questionPanelCanvasGroup
:
{
fileID
:
2061407680
}
questionContainer
:
{
fileID
:
1427982049
}
questionImageComponent
:
{
fileID
:
940564276
}
questionTextComponent
:
{
fileID
:
33964863
}
answersGrid
:
{
fileID
:
906182116
}
...
...
@@ -2776,8 +2779,25 @@ MonoBehaviour:
-
{
fileID
:
1418877170
}
-
{
fileID
:
652543887
}
-
{
fileID
:
1001118204
}
questionContainer
:
{
fileID
:
1427982049
}
answersContainer
:
{
fileID
:
906182118
}
gameUICanvasGroup
:
{
fileID
:
7013410525514931103
}
questionEntranceDuration
:
0.6
answerStaggerDelay
:
0.1
answerEntranceDuration
:
0.4
wrongAnswerShakeDuration
:
0.4
wrongAnswerShakeStrength
:
15
---
!u!225
&2061407680
CanvasGroup
:
m_ObjectHideFlags
:
0
m_CorrespondingSourceObject
:
{
fileID
:
0
}
m_PrefabInstance
:
{
fileID
:
0
}
m_PrefabAsset
:
{
fileID
:
0
}
m_GameObject
:
{
fileID
:
2061407675
}
m_Enabled
:
1
m_Alpha
:
1
m_Interactable
:
1
m_BlocksRaycasts
:
1
m_IgnoreParentGroups
:
0
---
!u!1
&2077715401
GameObject
:
m_ObjectHideFlags
:
0
...
...
My project/Assets/ScienceStreet/MCQ/Scripts/New/AnswerButtonUI.cs
View file @
0ba46a41
...
...
@@ -3,6 +3,7 @@ using UnityEngine.UI;
using
TMPro
;
using
System
;
using
LightSide
;
using
DG.Tweening
;
public
class
AnswerButtonUI
:
MonoBehaviour
{
...
...
@@ -16,12 +17,14 @@ public class AnswerButtonUI : MonoBehaviour
[
SerializeField
]
private
Color
normalTextColor
=
Color
.
black
;
[
SerializeField
]
private
Color
selectedCorrectColor
=
Color
.
green
;
[
SerializeField
]
private
Color
selectedIncorrectColor
=
Color
.
red
;
[
SerializeField
]
private
Color
correctAnswerColor
=
new
Color
(
0.2f
,
0.8f
,
0.2f
,
1f
);
// Light green
[
SerializeField
]
private
Color
disabledColor
=
new
Color
(
0.7f
,
0.7f
,
0.7f
,
1f
);
// Gray
[
SerializeField
]
private
Color
correctAnswerColor
=
new
Color
(
0.2f
,
0.8f
,
0.2f
,
1f
);
[
SerializeField
]
private
Color
disabledColor
=
new
Color
(
0.7f
,
0.7f
,
0.7f
,
1f
);
private
int
answerIndex
;
private
Action
<
int
>
onClicked
;
private
bool
isInteractable
=
true
;
private
CanvasGroup
canvasGroup
;
private
RectTransform
rectTransform
;
private
void
OnEnable
()
{
...
...
@@ -31,16 +34,33 @@ public class AnswerButtonUI : MonoBehaviour
}
}
private
void
OnDisable
()
{
DOTween
.
Kill
(
this
);
}
/// <summary>
/// Setup answer button with text and optional image
/// </summary>
public
void
Setup
(
string
answerText
,
Sprite
answerImage
,
int
index
,
Action
<
int
>
callback
)
{
button
.
Select
();
if
(
button
!=
null
)
button
.
Select
();
answerIndex
=
index
;
onClicked
=
callback
;
isInteractable
=
true
;
// Cache components
if
(
rectTransform
==
null
)
rectTransform
=
GetComponent
<
RectTransform
>();
if
(
canvasGroup
==
null
)
canvasGroup
=
GetComponent
<
CanvasGroup
>();
if
(
canvasGroup
==
null
)
canvasGroup
=
gameObject
.
AddComponent
<
CanvasGroup
>();
// Setup text
if
(
answerTextComponent
!=
null
)
{
...
...
@@ -103,7 +123,11 @@ public class AnswerButtonUI : MonoBehaviour
if
(
buttonBackgroundImage
!=
null
)
{
buttonBackgroundImage
.
color
=
isCorrect
?
selectedCorrectColor
:
selectedIncorrectColor
;
DOTween
.
Kill
(
buttonBackgroundImage
,
true
);
buttonBackgroundImage
.
DOColor
(
isCorrect
?
selectedCorrectColor
:
selectedIncorrectColor
,
0.3f
).
SetEase
(
Ease
.
OutQuad
);
}
if
(
button
!=
null
)
...
...
@@ -121,7 +145,9 @@ public class AnswerButtonUI : MonoBehaviour
if
(
buttonBackgroundImage
!=
null
)
{
buttonBackgroundImage
.
color
=
correctAnswerColor
;
DOTween
.
Kill
(
buttonBackgroundImage
,
true
);
buttonBackgroundImage
.
DOColor
(
correctAnswerColor
,
0.3f
)
.
SetEase
(
Ease
.
OutQuad
);
}
if
(
button
!=
null
)
...
...
@@ -139,7 +165,9 @@ public class AnswerButtonUI : MonoBehaviour
if
(
buttonBackgroundImage
!=
null
)
{
buttonBackgroundImage
.
color
=
disabledColor
;
DOTween
.
Kill
(
buttonBackgroundImage
,
true
);
buttonBackgroundImage
.
DOColor
(
disabledColor
,
0.3f
)
.
SetEase
(
Ease
.
OutQuad
);
}
if
(
button
!=
null
)
...
...
@@ -157,6 +185,7 @@ public class AnswerButtonUI : MonoBehaviour
if
(
buttonBackgroundImage
!=
null
)
{
DOTween
.
Kill
(
buttonBackgroundImage
,
true
);
buttonBackgroundImage
.
color
=
normalColor
;
}
...
...
@@ -165,6 +194,16 @@ public class AnswerButtonUI : MonoBehaviour
answerTextComponent
.
color
=
normalTextColor
;
}
if
(
canvasGroup
!=
null
)
{
canvasGroup
.
alpha
=
1f
;
}
if
(
rectTransform
!=
null
)
{
rectTransform
.
localScale
=
Vector3
.
one
;
}
if
(
button
!=
null
)
{
button
.
interactable
=
true
;
...
...
My project/Assets/ScienceStreet/MCQ/Scripts/New/NewMCQGameManger.cs
View file @
0ba46a41
...
...
@@ -193,6 +193,7 @@ namespace com.al_arcade.mcq
if
(
Camera
.
main
!=
null
)
{
Debug
.
Log
(
"shake"
);
DOTween
.
Kill
(
Camera
.
main
.
transform
,
"camShake"
);
Camera
.
main
.
transform
.
DOShakePosition
(
0.4f
,
0.3f
,
15
,
90f
,
false
,
true
)
.
SetEase
(
Ease
.
OutQuad
).
SetId
(
"camShake"
);
...
...
My project/Assets/ScienceStreet/MCQ/Scripts/New/QuestionUi.cs
View file @
0ba46a41
...
...
@@ -4,22 +4,34 @@ using TMPro;
using
System
;
using
com.al_arcade.shared
;
using
LightSide
;
using
DG.Tweening
;
public
class
QuestionUi
:
MonoBehaviour
{
public
static
QuestionUi
Instance
;
[
SerializeField
]
private
CanvasGroup
questionPanelCanvasGroup
;
[
SerializeField
]
private
LayoutGroup
questionContainer
;
[
SerializeField
]
private
Image
questionImageComponent
;
[
SerializeField
]
private
UniText
questionTextComponent
;
[
SerializeField
]
private
Transform
answersGrid
;
[
SerializeField
]
private
AnswerButtonUI
[]
answerButtons
=
new
AnswerButtonUI
[
4
];
[
SerializeField
]
private
LayoutGroup
questionContainer
;
[
SerializeField
]
private
LayoutGroup
answersContainer
;
[
SerializeField
]
private
CanvasGroup
gameUICanvasGroup
;
[
Header
(
"Animation Settings"
)]
[
SerializeField
]
private
float
questionEntranceDuration
=
0.6f
;
[
SerializeField
]
private
float
answerStaggerDelay
=
0.1f
;
[
SerializeField
]
private
float
answerEntranceDuration
=
0.4f
;
[
SerializeField
]
private
float
wrongAnswerShakeDuration
=
0.4f
;
[
SerializeField
]
private
float
wrongAnswerShakeStrength
=
15f
;
private
McqQuestion
currentQuestion
;
private
int
correctAnswerIndex
=
-
1
;
private
bool
hasAnswered
=
false
;
private
Action
<
int
,
bool
>
onAnswerSelected
;
private
Sequence
questionSequence
;
private
Sequence
[]
answerSequences
=
new
Sequence
[
4
];
private
void
Awake
()
{
...
...
@@ -33,17 +45,27 @@ public class QuestionUi : MonoBehaviour
}
}
private
void
OnEnable
()
{
if
(
answerButtons
.
Length
!=
4
)
{
Debug
.
LogError
(
"MultiChoiceQuestionUI: Must have exactly 4 answer buttons!"
);
}
// Auto-find CanvasGroup if not assigned
if
(
questionPanelCanvasGroup
==
null
)
{
questionPanelCanvasGroup
=
GetComponent
<
CanvasGroup
>();
}
if
(
gameUICanvasGroup
==
null
&&
answersContainer
!=
null
)
{
gameUICanvasGroup
=
answersContainer
.
GetComponentInParent
<
CanvasGroup
>();
}
}
/// <summary>
/// Display a multiple choice question with all its data
/// Display a multiple choice question with all its data
+ animations
/// </summary>
public
void
DisplayQuestion
(
McqQuestion
question
,
Action
<
int
,
bool
>
onAnswerCallback
=
null
)
{
...
...
@@ -58,6 +80,13 @@ public class QuestionUi : MonoBehaviour
hasAnswered
=
false
;
correctAnswerIndex
=
-
1
;
// Kill previous animations
DOTween
.
Kill
(
questionSequence
);
for
(
int
i
=
0
;
i
<
4
;
i
++)
{
DOTween
.
Kill
(
answerSequences
[
i
]);
}
// Reset previous shuffle
question
.
ResetShuffle
();
...
...
@@ -76,11 +105,13 @@ public class QuestionUi : MonoBehaviour
// Setup answer buttons with shuffled data
SetupAnswerButtons
(
shuffledAnswers
,
shuffledImages
);
//RectTransform example = answerButtons[1].GetComponent<RectTransform>();
//(answersContainer as GridLayoutGroup).cellSize = new Vector2(example.rect.width, example.rect.height);
// Rebuild layout hierarchy
LayoutRebuilder
.
ForceRebuildLayoutImmediate
(
questionContainer
.
GetComponent
<
RectTransform
>());
LayoutRebuilder
.
ForceRebuildLayoutImmediate
(
answersContainer
.
GetComponent
<
RectTransform
>());
// Play entrance animations
// AnimateQuestionEntrance();
AnimateAnswersEntrance
();
}
/// <summary>
...
...
@@ -125,6 +156,55 @@ public class QuestionUi : MonoBehaviour
}
}
/// Animate question entrance (fade only, no position change)
/// </summary>
private
void
AnimateQuestionEntrance
()
{
if
(
questionPanelCanvasGroup
==
null
)
return
;
// Reset state
questionPanelCanvasGroup
.
alpha
=
0
;
questionSequence
=
DOTween
.
Sequence
();
questionSequence
.
Append
(
questionPanelCanvasGroup
.
DOFade
(
1f
,
questionEntranceDuration
));
}
/// <summary>
/// Animate answers entrance (staggered, spring pop)
/// </summary>
private
void
AnimateAnswersEntrance
()
{
for
(
int
i
=
0
;
i
<
4
;
i
++)
{
AnimateAnswerButtonEntrance
(
i
);
}
}
private
void
AnimateAnswerButtonEntrance
(
int
index
)
{
RectTransform
answerRect
=
answerButtons
[
index
].
GetComponent
<
RectTransform
>();
CanvasGroup
answerCanvasGroup
=
answerButtons
[
index
].
GetComponent
<
CanvasGroup
>();
if
(
answerCanvasGroup
==
null
)
{
answerCanvasGroup
=
answerButtons
[
index
].
gameObject
.
AddComponent
<
CanvasGroup
>();
}
// Reset state
answerCanvasGroup
.
alpha
=
0
;
answerRect
.
localScale
=
Vector3
.
zero
;
float
delay
=
index
*
answerStaggerDelay
;
answerSequences
[
index
]
=
DOTween
.
Sequence
();
answerSequences
[
index
].
AppendInterval
(
delay
);
answerSequences
[
index
].
Append
(
answerCanvasGroup
.
DOFade
(
1f
,
answerEntranceDuration
*
0.5f
));
answerSequences
[
index
].
Join
(
answerRect
.
DOScale
(
1f
,
answerEntranceDuration
)
.
SetEase
(
Ease
.
OutBack
));
}
/// <summary>
/// Called when an answer button is clicked
/// </summary>
...
...
@@ -154,16 +234,81 @@ public class QuestionUi : MonoBehaviour
if
(
i
==
selectedIndex
)
{
answerButtons
[
i
].
SetSelected
(
isCorrect
);
AnimateAnswerSelection
(
i
,
isCorrect
);
}
else
if
(
i
==
correctAnswerIndex
&&
!
isCorrect
)
{
answerButtons
[
i
].
SetCorrect
();
AnimateCorrectAnswer
(
i
);
}
else
{
answerButtons
[
i
].
SetDisabled
();
AnimateDisabledAnswer
(
i
);
}
}
// Wrong answer screen shake
if
(!
isCorrect
)
{
ShakeGameUI
();
}
}
/// <summary>
/// Animate selected answer (pop + scale)
/// </summary>
private
void
AnimateAnswerSelection
(
int
index
,
bool
isCorrect
)
{
RectTransform
answerRect
=
answerButtons
[
index
].
GetComponent
<
RectTransform
>();
DOTween
.
Sequence
()
.
Append
(
answerRect
.
DOScale
(
1.15f
,
0.15f
).
SetEase
(
Ease
.
OutBack
))
.
Append
(
answerRect
.
DOScale
(
1f
,
0.1f
).
SetEase
(
Ease
.
InQuad
));
}
/// <summary>
/// Animate correct answer highlight (glow + pulse)
/// </summary>
private
void
AnimateCorrectAnswer
(
int
index
)
{
RectTransform
answerRect
=
answerButtons
[
index
].
GetComponent
<
RectTransform
>();
DOTween
.
Sequence
()
.
Append
(
answerRect
.
DOScale
(
1.05f
,
0.2f
).
SetEase
(
Ease
.
OutBack
))
.
SetLoops
(-
1
,
LoopType
.
Yoyo
)
.
SetId
(
$"correctAnswer_
{
index
}
"
);
}
/// <summary>
/// Animate disabled answer (fade out slightly)
/// </summary>
private
void
AnimateDisabledAnswer
(
int
index
)
{
CanvasGroup
answerCanvasGroup
=
answerButtons
[
index
].
GetComponent
<
CanvasGroup
>();
if
(
answerCanvasGroup
==
null
)
return
;
answerCanvasGroup
.
DOFade
(
0.5f
,
0.3f
).
SetEase
(
Ease
.
InQuad
);
}
/// <summary>
/// Screen shake for wrong answer (shake GameUI)
/// </summary>
private
void
ShakeGameUI
()
{
if
(
gameUICanvasGroup
==
null
)
return
;
RectTransform
gameUIRect
=
gameUICanvasGroup
.
GetComponent
<
RectTransform
>();
gameUIRect
.
DOShakeAnchorPos
(
wrongAnswerShakeDuration
,
new
Vector2
(
wrongAnswerShakeStrength
,
wrongAnswerShakeStrength
*
0.5f
),
vibrato
:
12
,
randomness
:
90f
,
snapping
:
false
).
SetEase
(
Ease
.
OutQuad
);
}
/// <summary>
...
...
@@ -174,10 +319,35 @@ public class QuestionUi : MonoBehaviour
hasAnswered
=
false
;
correctAnswerIndex
=
-
1
;
foreach
(
var
button
in
answerButtons
)
// Kill pulsing animations
for
(
int
i
=
0
;
i
<
4
;
i
++)
{
button
.
Reset
();
DOTween
.
Kill
(
$"correctAnswer_
{
i
}
"
);
answerButtons
[
i
].
Reset
();
}
// Fade out question
//AnimateQuestionExit();
}
/// <summary>
/// Animate question exit (fade out only, reset position)
/// </summary>
private
void
AnimateQuestionExit
()
{
if
(
questionPanelCanvasGroup
==
null
)
return
;
RectTransform
questionRect
=
questionContainer
.
GetComponent
<
RectTransform
>();
DOTween
.
Sequence
()
.
Append
(
questionPanelCanvasGroup
.
DOFade
(
0f
,
0.3f
))
.
OnComplete
(()
=>
{
// Reset position back to original after fade
if
(
questionRect
!=
null
)
questionRect
.
anchoredPosition
=
Vector2
.
zero
;
});
}
/// <summary>
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment