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
75375e88
Commit
75375e88
authored
Apr 02, 2026
by
mohamed20047
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
adding some animations
parent
0ed084a6
Changes
3
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
223 additions
and
13 deletions
+223
-13
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/ScienceStreet/MCQ/Scripts/New/AnswerButtonUI.cs
View file @
75375e88
...
@@ -3,6 +3,7 @@ using UnityEngine.UI;
...
@@ -3,6 +3,7 @@ using UnityEngine.UI;
using
TMPro
;
using
TMPro
;
using
System
;
using
System
;
using
LightSide
;
using
LightSide
;
using
DG.Tweening
;
public
class
AnswerButtonUI
:
MonoBehaviour
public
class
AnswerButtonUI
:
MonoBehaviour
{
{
...
@@ -16,12 +17,14 @@ public class AnswerButtonUI : MonoBehaviour
...
@@ -16,12 +17,14 @@ public class AnswerButtonUI : MonoBehaviour
[
SerializeField
]
private
Color
normalTextColor
=
Color
.
black
;
[
SerializeField
]
private
Color
normalTextColor
=
Color
.
black
;
[
SerializeField
]
private
Color
selectedCorrectColor
=
Color
.
green
;
[
SerializeField
]
private
Color
selectedCorrectColor
=
Color
.
green
;
[
SerializeField
]
private
Color
selectedIncorrectColor
=
Color
.
red
;
[
SerializeField
]
private
Color
selectedIncorrectColor
=
Color
.
red
;
[
SerializeField
]
private
Color
correctAnswerColor
=
new
Color
(
0.2f
,
0.8f
,
0.2f
,
1f
);
// Light green
[
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
);
// Gray
[
SerializeField
]
private
Color
disabledColor
=
new
Color
(
0.7f
,
0.7f
,
0.7f
,
1f
);
private
int
answerIndex
;
private
int
answerIndex
;
private
Action
<
int
>
onClicked
;
private
Action
<
int
>
onClicked
;
private
bool
isInteractable
=
true
;
private
bool
isInteractable
=
true
;
private
CanvasGroup
canvasGroup
;
private
RectTransform
rectTransform
;
private
void
OnEnable
()
private
void
OnEnable
()
{
{
...
@@ -31,16 +34,33 @@ public class AnswerButtonUI : MonoBehaviour
...
@@ -31,16 +34,33 @@ public class AnswerButtonUI : MonoBehaviour
}
}
}
}
private
void
OnDisable
()
{
DOTween
.
Kill
(
this
);
}
/// <summary>
/// <summary>
/// Setup answer button with text and optional image
/// Setup answer button with text and optional image
/// </summary>
/// </summary>
public
void
Setup
(
string
answerText
,
Sprite
answerImage
,
int
index
,
Action
<
int
>
callback
)
public
void
Setup
(
string
answerText
,
Sprite
answerImage
,
int
index
,
Action
<
int
>
callback
)
{
{
if
(
button
!=
null
)
button
.
Select
();
button
.
Select
();
answerIndex
=
index
;
answerIndex
=
index
;
onClicked
=
callback
;
onClicked
=
callback
;
isInteractable
=
true
;
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
// Setup text
if
(
answerTextComponent
!=
null
)
if
(
answerTextComponent
!=
null
)
{
{
...
@@ -103,7 +123,11 @@ public class AnswerButtonUI : MonoBehaviour
...
@@ -103,7 +123,11 @@ public class AnswerButtonUI : MonoBehaviour
if
(
buttonBackgroundImage
!=
null
)
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
)
if
(
button
!=
null
)
...
@@ -121,7 +145,9 @@ public class AnswerButtonUI : MonoBehaviour
...
@@ -121,7 +145,9 @@ public class AnswerButtonUI : MonoBehaviour
if
(
buttonBackgroundImage
!=
null
)
if
(
buttonBackgroundImage
!=
null
)
{
{
buttonBackgroundImage
.
color
=
correctAnswerColor
;
DOTween
.
Kill
(
buttonBackgroundImage
,
true
);
buttonBackgroundImage
.
DOColor
(
correctAnswerColor
,
0.3f
)
.
SetEase
(
Ease
.
OutQuad
);
}
}
if
(
button
!=
null
)
if
(
button
!=
null
)
...
@@ -139,7 +165,9 @@ public class AnswerButtonUI : MonoBehaviour
...
@@ -139,7 +165,9 @@ public class AnswerButtonUI : MonoBehaviour
if
(
buttonBackgroundImage
!=
null
)
if
(
buttonBackgroundImage
!=
null
)
{
{
buttonBackgroundImage
.
color
=
disabledColor
;
DOTween
.
Kill
(
buttonBackgroundImage
,
true
);
buttonBackgroundImage
.
DOColor
(
disabledColor
,
0.3f
)
.
SetEase
(
Ease
.
OutQuad
);
}
}
if
(
button
!=
null
)
if
(
button
!=
null
)
...
@@ -157,6 +185,7 @@ public class AnswerButtonUI : MonoBehaviour
...
@@ -157,6 +185,7 @@ public class AnswerButtonUI : MonoBehaviour
if
(
buttonBackgroundImage
!=
null
)
if
(
buttonBackgroundImage
!=
null
)
{
{
DOTween
.
Kill
(
buttonBackgroundImage
,
true
);
buttonBackgroundImage
.
color
=
normalColor
;
buttonBackgroundImage
.
color
=
normalColor
;
}
}
...
@@ -165,6 +194,16 @@ public class AnswerButtonUI : MonoBehaviour
...
@@ -165,6 +194,16 @@ public class AnswerButtonUI : MonoBehaviour
answerTextComponent
.
color
=
normalTextColor
;
answerTextComponent
.
color
=
normalTextColor
;
}
}
if
(
canvasGroup
!=
null
)
{
canvasGroup
.
alpha
=
1f
;
}
if
(
rectTransform
!=
null
)
{
rectTransform
.
localScale
=
Vector3
.
one
;
}
if
(
button
!=
null
)
if
(
button
!=
null
)
{
{
button
.
interactable
=
true
;
button
.
interactable
=
true
;
...
...
My project/Assets/ScienceStreet/MCQ/Scripts/New/NewMCQGameManger.cs
View file @
75375e88
...
@@ -193,6 +193,7 @@ namespace com.al_arcade.mcq
...
@@ -193,6 +193,7 @@ namespace com.al_arcade.mcq
if
(
Camera
.
main
!=
null
)
if
(
Camera
.
main
!=
null
)
{
{
Debug
.
Log
(
"shake"
);
DOTween
.
Kill
(
Camera
.
main
.
transform
,
"camShake"
);
DOTween
.
Kill
(
Camera
.
main
.
transform
,
"camShake"
);
Camera
.
main
.
transform
.
DOShakePosition
(
0.4f
,
0.3f
,
15
,
90f
,
false
,
true
)
Camera
.
main
.
transform
.
DOShakePosition
(
0.4f
,
0.3f
,
15
,
90f
,
false
,
true
)
.
SetEase
(
Ease
.
OutQuad
).
SetId
(
"camShake"
);
.
SetEase
(
Ease
.
OutQuad
).
SetId
(
"camShake"
);
...
...
My project/Assets/ScienceStreet/MCQ/Scripts/New/QuestionUi.cs
View file @
75375e88
...
@@ -4,22 +4,34 @@ using TMPro;
...
@@ -4,22 +4,34 @@ using TMPro;
using
System
;
using
System
;
using
com.al_arcade.shared
;
using
com.al_arcade.shared
;
using
LightSide
;
using
LightSide
;
using
DG.Tweening
;
public
class
QuestionUi
:
MonoBehaviour
public
class
QuestionUi
:
MonoBehaviour
{
{
public
static
QuestionUi
Instance
;
public
static
QuestionUi
Instance
;
[
SerializeField
]
private
CanvasGroup
questionPanelCanvasGroup
;
[
SerializeField
]
private
LayoutGroup
questionContainer
;
[
SerializeField
]
private
Image
questionImageComponent
;
[
SerializeField
]
private
Image
questionImageComponent
;
[
SerializeField
]
private
UniText
questionTextComponent
;
[
SerializeField
]
private
UniText
questionTextComponent
;
[
SerializeField
]
private
Transform
answersGrid
;
[
SerializeField
]
private
Transform
answersGrid
;
[
SerializeField
]
private
AnswerButtonUI
[]
answerButtons
=
new
AnswerButtonUI
[
4
];
[
SerializeField
]
private
AnswerButtonUI
[]
answerButtons
=
new
AnswerButtonUI
[
4
];
[
SerializeField
]
private
LayoutGroup
questionContainer
;
[
SerializeField
]
private
LayoutGroup
answersContainer
;
[
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
McqQuestion
currentQuestion
;
private
int
correctAnswerIndex
=
-
1
;
private
int
correctAnswerIndex
=
-
1
;
private
bool
hasAnswered
=
false
;
private
bool
hasAnswered
=
false
;
private
Action
<
int
,
bool
>
onAnswerSelected
;
private
Action
<
int
,
bool
>
onAnswerSelected
;
private
Sequence
questionSequence
;
private
Sequence
[]
answerSequences
=
new
Sequence
[
4
];
private
void
Awake
()
private
void
Awake
()
{
{
...
@@ -33,17 +45,27 @@ public class QuestionUi : MonoBehaviour
...
@@ -33,17 +45,27 @@ public class QuestionUi : MonoBehaviour
}
}
}
}
private
void
OnEnable
()
private
void
OnEnable
()
{
{
if
(
answerButtons
.
Length
!=
4
)
if
(
answerButtons
.
Length
!=
4
)
{
{
Debug
.
LogError
(
"MultiChoiceQuestionUI: Must have exactly 4 answer buttons!"
);
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>
/// <summary>
/// Display a multiple choice question with all its data
/// Display a multiple choice question with all its data
+ animations
/// </summary>
/// </summary>
public
void
DisplayQuestion
(
McqQuestion
question
,
Action
<
int
,
bool
>
onAnswerCallback
=
null
)
public
void
DisplayQuestion
(
McqQuestion
question
,
Action
<
int
,
bool
>
onAnswerCallback
=
null
)
{
{
...
@@ -58,6 +80,13 @@ public class QuestionUi : MonoBehaviour
...
@@ -58,6 +80,13 @@ public class QuestionUi : MonoBehaviour
hasAnswered
=
false
;
hasAnswered
=
false
;
correctAnswerIndex
=
-
1
;
correctAnswerIndex
=
-
1
;
// Kill previous animations
DOTween
.
Kill
(
questionSequence
);
for
(
int
i
=
0
;
i
<
4
;
i
++)
{
DOTween
.
Kill
(
answerSequences
[
i
]);
}
// Reset previous shuffle
// Reset previous shuffle
question
.
ResetShuffle
();
question
.
ResetShuffle
();
...
@@ -76,11 +105,13 @@ public class QuestionUi : MonoBehaviour
...
@@ -76,11 +105,13 @@ public class QuestionUi : MonoBehaviour
// Setup answer buttons with shuffled data
// Setup answer buttons with shuffled data
SetupAnswerButtons
(
shuffledAnswers
,
shuffledImages
);
SetupAnswerButtons
(
shuffledAnswers
,
shuffledImages
);
//RectTransform example = answerButtons[1].GetComponent<RectTransform>();
//(answersContainer as GridLayoutGroup).cellSize = new Vector2(example.rect.width, example.rect.height);
// Rebuild layout hierarchy
// Rebuild layout hierarchy
LayoutRebuilder
.
ForceRebuildLayoutImmediate
(
questionContainer
.
GetComponent
<
RectTransform
>());
LayoutRebuilder
.
ForceRebuildLayoutImmediate
(
questionContainer
.
GetComponent
<
RectTransform
>());
LayoutRebuilder
.
ForceRebuildLayoutImmediate
(
answersContainer
.
GetComponent
<
RectTransform
>());
LayoutRebuilder
.
ForceRebuildLayoutImmediate
(
answersContainer
.
GetComponent
<
RectTransform
>());
// Play entrance animations
// AnimateQuestionEntrance();
AnimateAnswersEntrance
();
}
}
/// <summary>
/// <summary>
...
@@ -125,6 +156,55 @@ public class QuestionUi : MonoBehaviour
...
@@ -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>
/// <summary>
/// Called when an answer button is clicked
/// Called when an answer button is clicked
/// </summary>
/// </summary>
...
@@ -154,16 +234,81 @@ public class QuestionUi : MonoBehaviour
...
@@ -154,16 +234,81 @@ public class QuestionUi : MonoBehaviour
if
(
i
==
selectedIndex
)
if
(
i
==
selectedIndex
)
{
{
answerButtons
[
i
].
SetSelected
(
isCorrect
);
answerButtons
[
i
].
SetSelected
(
isCorrect
);
AnimateAnswerSelection
(
i
,
isCorrect
);
}
}
else
if
(
i
==
correctAnswerIndex
&&
!
isCorrect
)
else
if
(
i
==
correctAnswerIndex
&&
!
isCorrect
)
{
{
answerButtons
[
i
].
SetCorrect
();
answerButtons
[
i
].
SetCorrect
();
AnimateCorrectAnswer
(
i
);
}
}
else
else
{
{
answerButtons
[
i
].
SetDisabled
();
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>
/// <summary>
...
@@ -174,10 +319,35 @@ public class QuestionUi : MonoBehaviour
...
@@ -174,10 +319,35 @@ public class QuestionUi : MonoBehaviour
hasAnswered
=
false
;
hasAnswered
=
false
;
correctAnswerIndex
=
-
1
;
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>
/// <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