MiniQuiz and Projector flow Added

This commit is contained in:
Ali Sharoz 2025-05-29 20:41:47 +05:00
parent 26b02343e4
commit 5a17d38946
21 changed files with 6133 additions and 65 deletions

45
Assets/MiniQuizManager.cs Normal file
View File

@ -0,0 +1,45 @@
using UnityEngine;
using UnityEngine.UI;
using TMPro;
public class MiniQuizManager : MonoBehaviour
{
public Button[] answerButtons; // Assign in order: A, B, C, D
public TextMeshProUGUI[] answerLabels; // Same order as buttons
public TextMeshProUGUI feedbackText;
private string[] answerTexts = new string[]
{
"Typos in the subject",
"Urgent language",
"Mismatched sender email",
"All of the above"
};
private int correctIndex = 3;
public void SubmitAnswer(int selectedIndex)
{
string selectedAnswer = answerTexts[selectedIndex];
UserActionLogger.Instance?.LogQuizAnswer(selectedAnswer);
// Feedback
if (selectedIndex == correctIndex)
{
feedbackText.text = "✅ Correct! All of those were red flags.";
}
else
{
feedbackText.text = $"❌ Not quite. The correct answer was: {answerTexts[correctIndex]}";
}
// Lock all buttons
foreach (var btn in answerButtons)
{
btn.interactable = false;
}
// Mark selected
answerLabels[selectedIndex].text = "✅ " + answerLabels[selectedIndex].text;
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2e91fa26b90b93441b32c069c085f507
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -617,7 +617,7 @@ MonoBehaviour:
m_GameObject: {fileID: 5379223866780212926} m_GameObject: {fileID: 5379223866780212926}
m_Enabled: 1 m_Enabled: 1
m_EditorHideFlags: 0 m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: b4c7f4a40cc765b4c871298980d3045d, type: 3} m_Script: {fileID: 11500000, guid: 5e486cfb8f5242f4bb3541192679bd01, type: 3}
m_Name: m_Name:
m_EditorClassIdentifier: m_EditorClassIdentifier:
--- !u!1 &5764583576712336997 --- !u!1 &5764583576712336997

File diff suppressed because it is too large Load Diff

View File

@ -32,7 +32,6 @@ public class BodyLinkHandler : MonoBehaviour, IPointerClickHandler, IPointerExit
} }
} }
public void OnPointerClick(PointerEventData eventData) public void OnPointerClick(PointerEventData eventData)
{ {
int linkIndex = TMP_TextUtilities.FindIntersectingLink(tmp, Input.mousePosition, eventData.pressEventCamera); int linkIndex = TMP_TextUtilities.FindIntersectingLink(tmp, Input.mousePosition, eventData.pressEventCamera);
@ -41,9 +40,29 @@ public class BodyLinkHandler : MonoBehaviour, IPointerClickHandler, IPointerExit
string linkID = tmp.textInfo.linkInfo[linkIndex].GetLinkID(); string linkID = tmp.textInfo.linkInfo[linkIndex].GetLinkID();
Debug.Log("🔗 Clicked link: " + linkID); Debug.Log("🔗 Clicked link: " + linkID);
EmailPopupManager.Instance?.ShowPopup(linkID); EmailPopupManager.Instance?.ShowPopup(linkID);
var emailPanelGO = WorldTimelineManager.Instance?.OpenedEmailPanel;
if (emailPanelGO != null && emailPanelGO.TryGetComponent<EmailOpenPanel>(out var emailPanel))
{
EmailData email = emailPanel.Email;
if (email != null)
{
SceneOutcomeManager.Instance?.Clicked(email);
UserActionLogger.Instance?.Log($"Clicked link '{linkID}' in email from '{email.senderName}'");
}
else
{
Debug.LogWarning("📭 EmailData is null in EmailOpenPanel.");
}
}
else
{
Debug.LogWarning("📭 OpenedEmailPanel or EmailOpenPanel script not found.");
}
} }
} }
public void OnPointerExit(PointerEventData eventData) public void OnPointerExit(PointerEventData eventData)
{ {
CursorManager.Instance?.SetDefaultCursor(); CursorManager.Instance?.SetDefaultCursor();

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: b4c7f4a40cc765b4c871298980d3045d guid: 5e486cfb8f5242f4bb3541192679bd01
MonoImporter: MonoImporter:
externalObjects: {} externalObjects: {}
serializedVersion: 2 serializedVersion: 2

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: 2166b6693dad68f408dc926e8b965506 guid: a2ef96e578f9abe49abb006299b30dd1
MonoImporter: MonoImporter:
externalObjects: {} externalObjects: {}
serializedVersion: 2 serializedVersion: 2

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: bdfc1490af05318459a63557af7e3ffc guid: 5f6cd8f9035e17c4a8b194a57bc220ea
MonoImporter: MonoImporter:
externalObjects: {} externalObjects: {}
serializedVersion: 2 serializedVersion: 2

View File

@ -19,6 +19,7 @@ public class EmailOpenPanel : MonoBehaviour
public Button ignoreBtn; public Button ignoreBtn;
private EmailData emailData; private EmailData emailData;
public EmailData Email => emailData;
public void Setup(EmailData data, string initial, Sprite iconSprite) public void Setup(EmailData data, string initial, Sprite iconSprite)
{ {
@ -45,7 +46,11 @@ public class EmailOpenPanel : MonoBehaviour
void OnAction(string action) void OnAction(string action)
{ {
Destroy(gameObject); gameObject.SetActive(false);
string summary = $"{action.ToUpper()} clicked on email from '{emailData.senderName}' with subject '{emailData.subject}'";
UserActionLogger.Instance?.Log(summary);
switch (action) switch (action)
{ {
@ -57,4 +62,5 @@ public class EmailOpenPanel : MonoBehaviour
break; break;
} }
} }
} }

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: 0cc1fd5d5866e1d4dad7ab40904b0fe9 guid: 8d44862abbde4da439e2a61442be398a
MonoImporter: MonoImporter:
externalObjects: {} externalObjects: {}
serializedVersion: 2 serializedVersion: 2

View File

@ -50,5 +50,8 @@ public class EmailUIController : MonoBehaviour
WorldTimelineManager.Instance.OpenedEmailPanel = panel; WorldTimelineManager.Instance.OpenedEmailPanel = panel;
EmailOpenPanel controller = panel.GetComponent<EmailOpenPanel>(); EmailOpenPanel controller = panel.GetComponent<EmailOpenPanel>();
controller.Setup(data, cachedInitial, cachedSprite); controller.Setup(data, cachedInitial, cachedSprite);
UserActionLogger.Instance?.Log($"Opened email from '{data.senderName}' with subject '{data.subject}'");
} }
} }

View File

@ -14,7 +14,9 @@ public class SceneOutcomeManager : MonoBehaviour
public Transform cameraTarget; public Transform cameraTarget;
public float cameraMoveSpeed = 1.5f; public float cameraMoveSpeed = 1.5f;
public Camera mainCamera; public Camera mainCamera;
public Transform teacherTarget;
public GameObject DebriefObj;
public GameObject LaptopCanvas;
private void Awake() private void Awake()
{ {
Instance = this; Instance = this;
@ -68,19 +70,46 @@ public class SceneOutcomeManager : MonoBehaviour
private IEnumerator MoveCameraToDebrief() private IEnumerator MoveCameraToDebrief()
{ {
if (mainCamera == null || cameraTarget == null) DebriefObj.SetActive(true);
yield return new WaitForSeconds(2);
if (mainCamera == null || cameraTarget == null || teacherTarget == null)
yield break; yield break;
Vector3 startPos = mainCamera.transform.position; Vector3 startPos = mainCamera.transform.position;
Quaternion startRot = mainCamera.transform.rotation; Quaternion startRot = mainCamera.transform.rotation;
Quaternion finalRot = cameraTarget.rotation;
float duration = 2f;
float t = 0; float t = 0;
while (t < 1) while (t < 1)
{ {
t += Time.deltaTime * cameraMoveSpeed; t += Time.deltaTime / duration;
// Smooth position interpolation
mainCamera.transform.position = Vector3.Lerp(startPos, cameraTarget.position, t); mainCamera.transform.position = Vector3.Lerp(startPos, cameraTarget.position, t);
mainCamera.transform.rotation = Quaternion.Slerp(startRot, cameraTarget.rotation, t);
if (t < 0.4f)
{
LaptopCanvas.SetActive(false);
// First half: look at teacher
Quaternion lookAtTeacher = Quaternion.LookRotation(teacherTarget.position - mainCamera.transform.position);
mainCamera.transform.rotation = Quaternion.Slerp(mainCamera.transform.rotation, lookAtTeacher, Time.deltaTime * 5f);
}
else
{
// Second half: rotate towards final camera rotation
float rotT = (t - 0.4f) * 2f; // Normalize from 01 for second half
mainCamera.transform.rotation = Quaternion.Slerp(mainCamera.transform.rotation, finalRot, rotT);
}
yield return null; yield return null;
} }
// Snap to ensure exact final values
mainCamera.transform.position = cameraTarget.position;
mainCamera.transform.rotation = finalRot;
} }
} }

View File

@ -0,0 +1,53 @@
using System.Collections.Generic;
using UnityEngine;
using System.Text;
using TMPro;
public class UserActionLogger : MonoBehaviour
{
public static UserActionLogger Instance;
private List<string> logs = new List<string>();
public TextMeshProUGUI summaryText;
private void Awake()
{
if (Instance == null)
Instance = this;
else
Destroy(gameObject);
}
public void Log(string action)
{
logs.Add(action);
Debug.Log($"📜 Action Logged: {logs.Count}. {action}");
}
public void LogQuizAnswer(string answerText)
{
Log($"Answered quiz: {answerText}");
}
public string GetFullLog()
{
StringBuilder sb = new StringBuilder();
for (int i = 0; i < logs.Count; i++)
{
sb.AppendLine($"{i + 1}. {logs[i]}");
}
return sb.ToString();
}
[ContextMenu("ShowSummary")]
public void ShowSummary()
{
if (summaryText != null)
summaryText.text = GetFullLog();
}
public void ClearLog()
{
logs.Clear();
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 20d8955ce25121f43b41083e81df52dd
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -11,7 +11,7 @@ public class WorldTimelineManager : MonoBehaviour
public GameObject newEmailReceived; public GameObject newEmailReceived;
public GameObject EmailListPanel; public GameObject EmailListPanel;
public GameObject OpenedEmailPanel; public GameObject OpenedEmailPanel;
public GameObject DataStolen;
[Header("Timeline Canvas (World Space)")] [Header("Timeline Canvas (World Space)")]
public Transform timelineParent; public Transform timelineParent;
public float panelSpacing = 2f; public float panelSpacing = 2f;
@ -30,16 +30,17 @@ public class WorldTimelineManager : MonoBehaviour
public void SnapshotCurrentSequence() public void SnapshotCurrentSequence()
{ {
UserActionLogger.Instance.ShowSummary();
ClearPlaybackFrames(); ClearPlaybackFrames();
CloneAndAddToTimeline(newEmailReceived); CloneAndAddToTimeline(newEmailReceived);
CloneAndAddToTimeline(EmailListPanel); CloneAndAddToTimeline(EmailListPanel);
if (OpenedEmailPanel != null) if (OpenedEmailPanel != null)
{ {
CloneAndAddToTimeline(OpenedEmailPanel); CloneAndAddToTimeline(OpenedEmailPanel);
} }
CloneAndAddToTimeline(DataStolen);
PlayTimelineLoop(); PlayTimelineLoop();
} }
@ -50,7 +51,8 @@ public class WorldTimelineManager : MonoBehaviour
GameObject clone = Instantiate(original, timelineParent); GameObject clone = Instantiate(original, timelineParent);
clone.transform.localScale = original.transform.localScale; clone.transform.localScale = original.transform.localScale;
clone.transform.localRotation = Quaternion.identity; clone.transform.localRotation = Quaternion.identity;
clone.transform.localPosition = Vector3.right * panelSpacing * playbackFrames.Count; clone.transform.localPosition = Vector3.zero;
//clone.transform.localPosition = Vector3.right * panelSpacing * playbackFrames.Count;
clone.SetActive(false); clone.SetActive(false);
DisableButtons(clone); DisableButtons(clone);
@ -62,7 +64,7 @@ public class WorldTimelineManager : MonoBehaviour
{ {
foreach (Button btn in root.GetComponentsInChildren<Button>(true)) foreach (Button btn in root.GetComponentsInChildren<Button>(true))
{ {
btn.interactable = false; btn.enabled = false;
} }
} }

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: 91243539438e2954caec899557cb4054 guid: 93396d2ba10e0644cb39e79325195d12
MonoImporter: MonoImporter:
externalObjects: {} externalObjects: {}
serializedVersion: 2 serializedVersion: 2

View File

@ -2,20 +2,24 @@
%TAG !u! tag:unity3d.com,2011: %TAG !u! tag:unity3d.com,2011:
--- !u!21 &2180264 --- !u!21 &2180264
Material: Material:
serializedVersion: 6 serializedVersion: 8
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0} m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0} m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0} m_PrefabAsset: {fileID: 0}
m_Name: LiberationSans SDF Material m_Name: LiberationSans SDF Material
m_Shader: {fileID: 4800000, guid: fe393ace9b354375a9cb14cdbbc28be4, type: 3} m_Shader: {fileID: 4800000, guid: fe393ace9b354375a9cb14cdbbc28be4, type: 3}
m_ShaderKeywords: m_Parent: {fileID: 0}
m_ModifiedSerializedProperties: 0
m_ValidKeywords: []
m_InvalidKeywords: []
m_LightmapFlags: 1 m_LightmapFlags: 1
m_EnableInstancingVariants: 0 m_EnableInstancingVariants: 0
m_DoubleSidedGI: 0 m_DoubleSidedGI: 0
m_CustomRenderQueue: -1 m_CustomRenderQueue: -1
stringTagMap: {} stringTagMap: {}
disabledShaderPasses: [] disabledShaderPasses: []
m_LockedProperties:
m_SavedProperties: m_SavedProperties:
serializedVersion: 3 serializedVersion: 3
m_TexEnvs: m_TexEnvs:
@ -67,6 +71,7 @@ Material:
m_Texture: {fileID: 0} m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1} m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0} m_Offset: {x: 0, y: 0}
m_Ints: []
m_Floats: m_Floats:
- _Ambient: 0.5 - _Ambient: 0.5
- _Bevel: 0.5 - _Bevel: 0.5
@ -107,9 +112,9 @@ Material:
- _Parallax: 0.02 - _Parallax: 0.02
- _PerspectiveFilter: 0.875 - _PerspectiveFilter: 0.875
- _Reflectivity: 10 - _Reflectivity: 10
- _ScaleRatioA: 0.90909094 - _ScaleRatioA: 0.9
- _ScaleRatioB: 0.73125 - _ScaleRatioB: 0.73125
- _ScaleRatioC: 0.7386364 - _ScaleRatioC: 0.73125
- _ScaleX: 1 - _ScaleX: 1
- _ScaleY: 1 - _ScaleY: 1
- _ShaderFlags: 0 - _ShaderFlags: 0
@ -148,6 +153,7 @@ Material:
- _ReflectOutlineColor: {r: 0, g: 0, b: 0, a: 1} - _ReflectOutlineColor: {r: 0, g: 0, b: 0, a: 1}
- _SpecularColor: {r: 1, g: 1, b: 1, a: 1} - _SpecularColor: {r: 1, g: 1, b: 1, a: 1}
- _UnderlayColor: {r: 0, g: 0, b: 0, a: 0.5} - _UnderlayColor: {r: 0, g: 0, b: 0, a: 0.5}
m_BuildTextureStacks: []
--- !u!114 &11400000 --- !u!114 &11400000
MonoBehaviour: MonoBehaviour:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@ -165,15 +171,16 @@ MonoBehaviour:
materialHashCode: 462855346 materialHashCode: 462855346
m_Version: 1.1.0 m_Version: 1.1.0
m_SourceFontFileGUID: e3265ab4bf004d28a9537516768c1c75 m_SourceFontFileGUID: e3265ab4bf004d28a9537516768c1c75
m_SourceFontFile_EditorRef: {fileID: 12800000, guid: e3265ab4bf004d28a9537516768c1c75, m_SourceFontFile_EditorRef: {fileID: 12800000, guid: e3265ab4bf004d28a9537516768c1c75, type: 3}
type: 3}
m_SourceFontFile: {fileID: 12800000, guid: e3265ab4bf004d28a9537516768c1c75, type: 3} m_SourceFontFile: {fileID: 12800000, guid: e3265ab4bf004d28a9537516768c1c75, type: 3}
m_AtlasPopulationMode: 1 m_AtlasPopulationMode: 1
m_FaceInfo: m_FaceInfo:
m_FaceIndex: 0
m_FamilyName: Liberation Sans m_FamilyName: Liberation Sans
m_StyleName: Regular m_StyleName: Regular
m_PointSize: 86 m_PointSize: 86
m_Scale: 1 m_Scale: 1
m_UnitsPerEM: 0
m_LineHeight: 98.8916 m_LineHeight: 98.8916
m_AscentLine: 77.853516 m_AscentLine: 77.853516
m_CapLine: 59 m_CapLine: 59
@ -313,15 +320,21 @@ Texture2D:
Hash: 00000000000000000000000000000000 Hash: 00000000000000000000000000000000
m_ForcedFallbackFormat: 4 m_ForcedFallbackFormat: 4
m_DownscaleFallback: 0 m_DownscaleFallback: 0
m_IsAlphaChannelOptional: 0
serializedVersion: 2 serializedVersion: 2
m_Width: 0 m_Width: 0
m_Height: 0 m_Height: 0
m_CompleteImageSize: 0 m_CompleteImageSize: 0
m_MipsStripped: 0
m_TextureFormat: 1 m_TextureFormat: 1
m_MipCount: 1 m_MipCount: 1
m_IsReadable: 1 m_IsReadable: 1
m_IsPreProcessed: 0
m_IgnoreMipmapLimit: 0
m_MipmapLimitGroupName:
m_StreamingMipmaps: 0 m_StreamingMipmaps: 0
m_StreamingMipmapsPriority: 0 m_StreamingMipmapsPriority: 0
m_VTOnly: 0
m_AlphaIsTransparency: 0 m_AlphaIsTransparency: 0
m_ImageCount: 1 m_ImageCount: 1
m_TextureDimension: 2 m_TextureDimension: 2
@ -335,9 +348,11 @@ Texture2D:
m_WrapW: 0 m_WrapW: 0
m_LightmapFormat: 0 m_LightmapFormat: 0
m_ColorSpace: 0 m_ColorSpace: 0
m_PlatformBlob:
image data: 0 image data: 0
_typelessdata: _typelessdata:
m_StreamData: m_StreamData:
serializedVersion: 2
offset: 0 offset: 0
size: 0 size: 0
path: path:

BIN
Build.zip

Binary file not shown.