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_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: b4c7f4a40cc765b4c871298980d3045d, type: 3}
m_Script: {fileID: 11500000, guid: 5e486cfb8f5242f4bb3541192679bd01, type: 3}
m_Name:
m_EditorClassIdentifier:
--- !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)
{
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();
Debug.Log("🔗 Clicked link: " + 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)
{
CursorManager.Instance?.SetDefaultCursor();

View File

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

View File

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

View File

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

View File

@ -19,6 +19,7 @@ public class EmailOpenPanel : MonoBehaviour
public Button ignoreBtn;
private EmailData emailData;
public EmailData Email => emailData;
public void Setup(EmailData data, string initial, Sprite iconSprite)
{
@ -45,7 +46,11 @@ public class EmailOpenPanel : MonoBehaviour
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)
{
@ -57,4 +62,5 @@ public class EmailOpenPanel : MonoBehaviour
break;
}
}
}

View File

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

View File

@ -50,5 +50,8 @@ public class EmailUIController : MonoBehaviour
WorldTimelineManager.Instance.OpenedEmailPanel = panel;
EmailOpenPanel controller = panel.GetComponent<EmailOpenPanel>();
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 float cameraMoveSpeed = 1.5f;
public Camera mainCamera;
public Transform teacherTarget;
public GameObject DebriefObj;
public GameObject LaptopCanvas;
private void Awake()
{
Instance = this;
@ -68,19 +70,46 @@ public class SceneOutcomeManager : MonoBehaviour
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;
Vector3 startPos = mainCamera.transform.position;
Quaternion startRot = mainCamera.transform.rotation;
Quaternion finalRot = cameraTarget.rotation;
float duration = 2f;
float t = 0;
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.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;
}
// 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 EmailListPanel;
public GameObject OpenedEmailPanel;
public GameObject DataStolen;
[Header("Timeline Canvas (World Space)")]
public Transform timelineParent;
public float panelSpacing = 2f;
@ -30,16 +30,17 @@ public class WorldTimelineManager : MonoBehaviour
public void SnapshotCurrentSequence()
{
UserActionLogger.Instance.ShowSummary();
ClearPlaybackFrames();
CloneAndAddToTimeline(newEmailReceived);
CloneAndAddToTimeline(EmailListPanel);
if (OpenedEmailPanel != null)
{
CloneAndAddToTimeline(OpenedEmailPanel);
}
CloneAndAddToTimeline(DataStolen);
PlayTimelineLoop();
}
@ -50,7 +51,8 @@ public class WorldTimelineManager : MonoBehaviour
GameObject clone = Instantiate(original, timelineParent);
clone.transform.localScale = original.transform.localScale;
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);
DisableButtons(clone);
@ -62,7 +64,7 @@ public class WorldTimelineManager : MonoBehaviour
{
foreach (Button btn in root.GetComponentsInChildren<Button>(true))
{
btn.interactable = false;
btn.enabled = false;
}
}

View File

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

View File

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

BIN
Build.zip

Binary file not shown.