This commit is contained in:
Lucastaa
2026-04-29 21:31:49 +07:00
623 changed files with 6393 additions and 17359 deletions

2
.gitignore vendored
View File

@@ -73,3 +73,5 @@ crashlytics-build.properties
/[Aa]ssets/[Ss]treamingAssets/aa.meta
/[Aa]ssets/[Ss]treamingAssets/aa/*
Assets/Settings/Project Setting/FirebaseConfig.asset
Assets/Settings/Project Setting/FirebaseConfig.asset.meta

View File

@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding" addBOMForNewFiles="with BOM under Windows, with no BOM otherwise">
<file url="file://$PROJECT_DIR$/Assets/Scripts/Elo_System_Spec.txt" charset="ISO-8859-1" />
<file url="file://$PROJECT_DIR$/Assets/Scripts/GameSetup/Maze/Crawler.cs" charset="ISO-8859-1" />
<file url="file://$PROJECT_DIR$/Assets/Scripts/GameSetup/Maze/Extensions.cs" charset="ISO-8859-1" />
<file url="file://$PROJECT_DIR$/Assets/Scripts/GameSetup/Maze/Wilsons.cs" charset="ISO-8859-1" />

View File

@@ -6,9 +6,25 @@
<component name="ChangeListManager">
<list default="true" id="f9183c68-daf0-43b8-be4c-fad79983f91b" name="Changes" comment="">
<change beforePath="$PROJECT_DIR$/.idea/.idea.HALLUCINATE/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/.idea.HALLUCINATE/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Assets/Scripts/Duy/PlayerInputData.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Assets/Scripts/Duy/PlayerInputData.cs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Assets/Scripts/Duy/_BasicSpawner.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Assets/Scripts/Duy/_BasicSpawner.cs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Assets/Scripts/Duy/_PlayerDataManager.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Assets/Scripts/Duy/_PlayerDataManager.cs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Assets/Scripts/Fusion.meta" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Assets/Scripts/Fusion/BasicSpawner.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Assets/Scripts/Fusion/BasicSpawner.cs.meta" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Assets/Scripts/Fusion/LobbyHelper.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Assets/Scripts/Fusion/LobbyHelper.cs.meta" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Assets/Scripts/Fusion/LobbyManager.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Assets/Scripts/Fusion/LobbyManager.cs.meta" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Assets/Scripts/Fusion/PlayerProfile.cs" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Assets/Scripts/Fusion/PlayerProfile.cs.meta" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Assets/Scripts/Player Controller/PlayerStateMachine.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Assets/Scripts/Player Controller/PlayerStateMachine.cs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Assets/Scripts/Player Controller/PlayerStats.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Assets/Scripts/Player Controller/PlayerStats.cs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Assets/Scripts/UI/BaseUIController.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Assets/Scripts/UI/BaseUIController.cs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Assets/Scripts/UI/HUDController.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Assets/Scripts/UI/HUDController.cs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Assets/Scripts/UI/LobbyController.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Assets/Scripts/UI/LobbyController.cs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Assets/Scripts/UI/MainMenuController.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Assets/Scripts/UI/MainMenuController.cs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Assets/Scripts/UI/UIManager.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Assets/Scripts/UI/UIManager.cs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Assets/UI/Documents/MainMenu.uxml" beforeDir="false" afterPath="$PROJECT_DIR$/Assets/UI/Documents/MainMenu.uxml" afterDir="false" />
</list>
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
@@ -16,17 +32,18 @@
<option name="LAST_RESOLUTION" value="IGNORE" />
</component>
<component name="EmbeddingIndexingInfo">
<option name="cachedIndexableFilesCount" value="40" />
<option name="cachedIndexableFilesCount" value="8" />
<option name="fileBasedEmbeddingIndicesEnabled" value="true" />
</component>
<component name="Git.Settings">
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
</component>
<component name="HighlightingSettingsPerFile">
<setting file="file://$PROJECT_DIR$/Assets/Scripts/Attributes/Health.cs" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$PROJECT_DIR$/Assets/Scripts/Interactables/BaseInteractable.cs" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$PROJECT_DIR$/Assets/Scripts/Interactables/HealthInteractable.cs" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$PROJECT_DIR$/Assets/Scripts/UI/LobbyController.cs" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$PROJECT_DIR$/Assets/Third Parties/Photon/Fusion/Editor/Fusion.Unity.Editor.cs" root0="SKIP_HIGHLIGHTING" />
<setting file="file://$PROJECT_DIR$/Assets/UI/MainPanelSettings.asset" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$PROJECT_DIR$/Library/PackageCache/com.unity.render-pipelines.core@04ab0eefa0c3/Editor/Utilities/LocalizationHelper.cs" root0="SKIP_HIGHLIGHTING" />
<setting file="file://$PROJECT_DIR$/Library/PackageCache/com.unity.timeline@7f8b2fb101b6/Editor/Localization/Localization.cs" root0="SKIP_HIGHLIGHTING" />
<setting file="file://$PROJECT_DIR$/Library/PackageCache/com.wooshii.foldericons@201a18f355d3/FolderIcons/Editor/FolderIcons.cs" root0="SKIP_HIGHLIGHTING" />
</component>
<component name="McpProjectServerCommands">
<commands />
@@ -142,7 +159,10 @@
<workItem from="1777150520438" duration="58000" />
<workItem from="1777150592854" duration="4699000" />
<workItem from="1777181837663" duration="1519000" />
<workItem from="1777269364664" duration="5003000" />
<workItem from="1777269364664" duration="40284000" />
<workItem from="1777373072815" duration="1852000" />
<workItem from="1777376778745" duration="10727000" />
<workItem from="1777392719306" duration="13382000" />
</task>
<servers />
</component>
@@ -157,6 +177,17 @@
<option name="unityProjectFolder" value="true" />
</component>
<component name="UnityUnitTestConfiguration" currentTestLauncher="Both" />
<component name="Vcs.Log.Tabs.Properties">
<option name="TAB_STATES">
<map>
<entry key="MAIN">
<value>
<State />
</value>
</entry>
</map>
</option>
</component>
<component name="VcsManagerConfiguration">
<option name="CLEAR_INITIAL_COMMIT_MESSAGE" value="true" />
</component>

View File

@@ -1,70 +0,0 @@
using UnityEditor;
using UnityEngine;
using UI;
namespace UIEditor
{
[CustomEditor(typeof(UIManager))]
public class UIManagerEditor : UnityEditor.Editor
{
public override void OnInspectorGUI()
{
UIManager manager = (UIManager)target;
// Draw default fields (Initial Screen, Focus Radius, Global Opacity, etc.)
base.OnInspectorGUI();
EditorGUILayout.Space(10);
EditorGUILayout.LabelField("GLOBAL STYLING", EditorStyles.boldLabel);
// Re-sync if opacity slider changes
EditorGUI.BeginChangeCheck();
if (EditorGUI.EndChangeCheck())
{
manager.SyncScreens();
EditorUtility.SetDirty(manager);
}
EditorGUILayout.Space(20);
EditorGUILayout.LabelField("QUICK DASHBOARD", EditorStyles.boldLabel);
EditorGUILayout.HelpBox("Click các nút dưới đây để xem nhanh giao diện mà không cần Play game.", MessageType.Info);
if (manager.screens != null)
{
foreach (var screen in manager.screens)
{
EditorGUILayout.BeginHorizontal();
// Nút bấm để hiện duy nhất màn hình này
if (GUILayout.Button($"SHOW: {screen.screenName}", GUILayout.Height(30)))
{
manager.ShowOnly(screen.screenName);
EditorUtility.SetDirty(manager);
}
// Toggle nhanh trạng thái Active
bool newActive = EditorGUILayout.Toggle(screen.isActive, GUILayout.Width(20));
if (newActive != screen.isActive)
{
screen.isActive = newActive;
manager.SyncScreens();
EditorUtility.SetDirty(manager);
}
EditorGUILayout.EndHorizontal();
}
}
EditorGUILayout.Space(10);
if (GUILayout.Button("HIDE ALL SCREENS", GUILayout.Height(25)))
{
foreach (var s in manager.screens) s.isActive = false;
manager.SyncScreens();
EditorUtility.SetDirty(manager);
}
EditorGUILayout.Space(10);
EditorGUILayout.HelpBox("TIP: Bạn có thể thay đổi Global Opacity ở trên để xem độ mờ của toàn bộ UI.", MessageType.None);
}
}
}

View File

@@ -1,2 +0,0 @@
fileFormatVersion: 2
guid: 0e118f8ca802ae54e92d305688e5b5e3

Binary file not shown.

View File

@@ -1,21 +0,0 @@
fileFormatVersion: 2
guid: 3efebbfa35a5ea14187c984a295ccbbf
TrueTypeFontImporter:
externalObjects: {}
serializedVersion: 4
fontSize: 16
forceTextureCase: -2
characterSpacing: 0
characterPadding: 1
includeFontData: 1
fontNames:
- VCR OSD Mono
fallbackFontReferences: []
customCharacters:
fontRenderingMode: 0
ascentCalculationMode: 1
useLegacyBoundsCalculation: 0
shouldRoundAdvanceValue: 1
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because one or more lines are too long

View File

@@ -642,6 +642,24 @@
"processors": "",
"interactions": "",
"initialStateCheck": false
},
{
"name": "ToggleSetting",
"type": "Button",
"id": "ae29d662-c797-4411-8ff3-8b5ad78427d8",
"expectedControlType": "",
"processors": "",
"interactions": "",
"initialStateCheck": false
},
{
"name": "Escape",
"type": "Button",
"id": "79227a8d-6fd2-496d-8466-68f007a2c355",
"expectedControlType": "",
"processors": "",
"interactions": "",
"initialStateCheck": false
}
],
"bindings": [
@@ -1062,6 +1080,50 @@
"action": "TrackedDeviceOrientation",
"isComposite": false,
"isPartOfComposite": false
},
{
"name": "One Modifier",
"id": "112443de-ae57-4a55-a65c-98090d95ee75",
"path": "OneModifier",
"interactions": "",
"processors": "",
"groups": "",
"action": "ToggleSetting",
"isComposite": true,
"isPartOfComposite": false
},
{
"name": "modifier",
"id": "4fae2510-0264-46ca-9c9d-9d2cb0ad32d1",
"path": "<Keyboard>/leftCtrl",
"interactions": "",
"processors": "",
"groups": "",
"action": "ToggleSetting",
"isComposite": false,
"isPartOfComposite": true
},
{
"name": "binding",
"id": "822afb75-3d28-4c6d-8a32-3c7c65f81ddb",
"path": "<Keyboard>/g",
"interactions": "",
"processors": "",
"groups": "",
"action": "ToggleSetting",
"isComposite": false,
"isPartOfComposite": true
},
{
"name": "",
"id": "7b81fba6-40c0-412f-8836-6385914c8a3f",
"path": "<Keyboard>/escape",
"interactions": "",
"processors": "",
"groups": "",
"action": "Escape",
"isComposite": false,
"isPartOfComposite": false
}
]
}

View File

@@ -9,19 +9,23 @@ GameObject:
serializedVersion: 6
m_Component:
- component: {fileID: 3154409663696148700}
- component: {fileID: 5811177247042239962}
- component: {fileID: 8915611492738107882}
- component: {fileID: 5811177247042239962}
- component: {fileID: 9098752589608501196}
- component: {fileID: 5600577104145922999}
- component: {fileID: 3010251870038942475}
- component: {fileID: 830356296960548640}
- component: {fileID: 3043298118541876184}
- component: {fileID: 3866929919288054183}
- component: {fileID: 5773292363125757170}
- component: {fileID: 504047695906043424}
- component: {fileID: -5076913349690967641}
- component: {fileID: 5474834257287499008}
- component: {fileID: 591040529181574494}
- component: {fileID: 7826563193135964281}
- component: {fileID: 517879385770431681}
- component: {fileID: 8601091490777624370}
- component: {fileID: 7730391503324595278}
- component: {fileID: 3043298118541876184}
- component: {fileID: 5773292363125757170}
- component: {fileID: 3866929919288054183}
m_Layer: 0
m_Name: Player
m_TagString: Player
@@ -45,29 +49,8 @@ Transform:
- {fileID: 8004958684693924044}
- {fileID: 1837528887711025940}
- {fileID: 2204320233506982349}
- {fileID: 197467923929726417}
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &5811177247042239962
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1054594849095937263}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 169e37d35fede30409266070c88b118f, type: 3}
m_Name:
m_EditorClassIdentifier: Assembly-CSharp::OnlyScove.Scripts.EnvironmentScanner
forwardRayOffset: {x: 0, y: 2.5, z: 0}
forwardRayLength: 10
obstacleLayer:
serializedVersion: 2
m_Bits: 128
heightRayLength: 0
interactionOffset: {x: 0, y: 1.5, z: 0}
interactionRadius: 0.5
--- !u!143 &8915611492738107882
CharacterController:
m_ObjectHideFlags: 0
@@ -93,6 +76,26 @@ CharacterController:
m_SkinWidth: 0.019215723
m_MinMoveDistance: 0.001
m_Center: {x: 0, y: 0.8984509, z: 0.05}
--- !u!114 &5811177247042239962
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1054594849095937263}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 169e37d35fede30409266070c88b118f, type: 3}
m_Name:
m_EditorClassIdentifier: Assembly-CSharp::OnlyScove.Scripts.EnvironmentScanner
forwardRayOffset: {x: 0, y: 2.5, z: 0}
forwardRayLength: 10
obstacleLayer:
serializedVersion: 2
m_Bits: 128
heightRayLength: 0
interactionOffset: {x: 0, y: 1.5, z: 0}
interactionRadius: 0.5
--- !u!95 &9098752589608501196
Animator:
serializedVersion: 7
@@ -377,93 +380,13 @@ MonoBehaviour:
<Input>k__BackingField: {fileID: 5600577104145922999}
<Anim>k__BackingField: {fileID: 9098752589608501196}
<Scanner>k__BackingField: {fileID: 5811177247042239962}
speedParamName: Speed
velocityXParamName: Velocity X
velocityZParamName: Velocity Z
<WalkSpeed>k__BackingField: 5
<RunSpeed>k__BackingField: 10
<SprintSpeed>k__BackingField: 9
<SneakSpeed>k__BackingField: 1.5
<DashForce>k__BackingField: 15
<RotationSpeed>k__BackingField: 500
<AnimationDamping>k__BackingField: 0.2
<JumpHeight>k__BackingField: 2
<Gravity>k__BackingField: -9.81
<ThrustDownwardForce>k__BackingField: -20
<GroundCheckRadius>k__BackingField: 0.11529434
<GroundCheckOffset>k__BackingField: {x: 0, y: 0.079278834, z: 0.05}
<GroundMask>k__BackingField:
serializedVersion: 2
m_Bits: 64
<InteractionRange>k__BackingField: 2
<InteractionMask>k__BackingField:
serializedVersion: 2
m_Bits: 512
Stats: {fileID: 7826563193135964281}
Interaction: {fileID: 517879385770431681}
Movement: {fileID: 8601091490777624370}
AnimationHandler: {fileID: 7730391503324595278}
_NetworkedCameraRotation: {x: 0, y: 0, z: 0, w: 0}
_NetworkedMoveInput: {x: 0, y: 0}
_NetworkedSpeed: 0
_NetworkedPosition: {x: 0, y: 0, z: 0}
--- !u!114 &3043298118541876184
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1054594849095937263}
m_Enabled: 0
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: e16a6690e589f0449ad89a6bf508ab62, type: 3}
m_Name:
m_EditorClassIdentifier: Assembly-CSharp::OnlyScove.Scripts.GameSetup.CharacterAutoSetup
defaultHeight: 1.8
defaultShoulderWidth: 0.4
modelRoot: {fileID: 0}
autoDetectOnStart: 0
zCenterOffset: 0.05
--- !u!114 &3866929919288054183
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1054594849095937263}
m_Enabled: 0
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 1630760c9d97a5f4eb1bc179549c95cd, type: 3}
m_Name:
m_EditorClassIdentifier: Assembly-CSharp::SukunaAbilityController
inputReader: {fileID: 5600577104145922999}
blackProjectilePrefab: {fileID: 7925862234553078923, guid: a9db8dc0d7288b8418ab54e786fbffa7, type: 3}
redProjectilePrefab: {fileID: 1113287330716207023, guid: 03163717f6c5cad409e7e7f079f06ea5, type: 3}
attackRate: 0.1
forwardOffset: 4.55
verticalOffset: 1
rangeX: {x: -360, y: 360}
rangeY: {x: -10, y: 10}
rangeZ: {x: 50, y: 120}
--- !u!114 &5773292363125757170
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1054594849095937263}
m_Enabled: 0
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 271dd39a46bad974485107bb1a070e0a, type: 3}
m_Name:
m_EditorClassIdentifier: Assembly-CSharp::OnlyScove.Scripts.SukunaDomainController
playerStateMachine: {fileID: 830356296960548640}
slashPrefab: {fileID: 7424378359907903745, guid: 80f98b444eac25541afe9e9081c8303a, type: 3}
shrinePrefab: {fileID: 5712645696331672719, guid: b0b71c635e9971346ae9ab6b7ecdd65d, type: 3}
domainVolumeProfile: {fileID: 11400000, guid: 837c34edbcc0ece44ae8c54e25ec20de, type: 2}
cinematicCameraPoint: {fileID: 0}
domainRadius: 30
domainDuration: 10
slashRate: 100
shrineRiseHeight: 5
shrineFloorOffset: 0.5
camMoveSpeed: 4
--- !u!114 &504047695906043424
MonoBehaviour:
m_ObjectHideFlags: 0
@@ -501,6 +424,10 @@ MonoBehaviour:
- {fileID: 830356296960548640}
- {fileID: 504047695906043424}
- {fileID: 5474834257287499008}
- {fileID: 7826563193135964281}
- {fileID: 517879385770431681}
- {fileID: 8601091490777624370}
- {fileID: 7730391503324595278}
ForceRemoteRenderTimeframe: 0
--- !u!114 &5474834257287499008
MonoBehaviour:
@@ -514,9 +441,9 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: 70abb536cf50f2948882e913634daedf, type: 3}
m_Name:
m_EditorClassIdentifier: Assembly-CSharp::_PlayerInfo
_playerName:
_playerName: Runner
playerDataManager: {fileID: 0}
nameText: {fileID: 4162277074137292865}
nameText: {fileID: 0}
characterIcons:
- {fileID: 2663176581072049613}
- {fileID: 9158604782533009244}
@@ -537,108 +464,144 @@ MonoBehaviour:
followOffset: {x: 1.5, y: 2, z: 0}
smoothTime: 0.15
lookAtCamera: 1
--- !u!1 &2962936552048247184
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 197467923929726417}
- component: {fileID: 1018225786754720096}
- component: {fileID: 4475173704176190241}
- component: {fileID: 289368611602352569}
m_Layer: 5
m_Name: Canvas
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &197467923929726417
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2962936552048247184}
m_LocalRotation: {x: 0, y: 1, z: 0, w: 0}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 0.01, y: 0.01, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 7931877178581140798}
m_Father: {fileID: 3154409663696148700}
m_LocalEulerAnglesHint: {x: 0, y: 180, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchoredPosition: {x: -0.9036, y: 1.8528}
m_SizeDelta: {x: 509.2823, y: 17.4373}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!223 &1018225786754720096
Canvas:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2962936552048247184}
m_Enabled: 1
serializedVersion: 3
m_RenderMode: 2
m_Camera: {fileID: 0}
m_PlaneDistance: 100
m_PixelPerfect: 0
m_ReceivesEvents: 1
m_OverrideSorting: 0
m_OverridePixelPerfect: 0
m_SortingBucketNormalizedSize: 0
m_VertexColorAlwaysGammaSpace: 0
m_AdditionalShaderChannelsFlag: 25
m_UpdateRectTransformForStandalone: 0
m_SortingLayerID: 0
m_SortingOrder: 0
m_TargetDisplay: 0
--- !u!114 &4475173704176190241
--- !u!114 &7826563193135964281
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2962936552048247184}
m_GameObject: {fileID: 1054594849095937263}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3}
m_Script: {fileID: 11500000, guid: a1494b79b59fcdf4d9f7956dde31bc42, type: 3}
m_Name:
m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.CanvasScaler
m_UiScaleMode: 0
m_ReferencePixelsPerUnit: 100
m_ScaleFactor: 1
m_ReferenceResolution: {x: 800, y: 600}
m_ScreenMatchMode: 0
m_MatchWidthOrHeight: 0
m_PhysicalUnit: 3
m_FallbackScreenDPI: 96
m_DefaultSpriteDPI: 96
m_DynamicPixelsPerUnit: 1
m_PresetInfoIsWorld: 1
--- !u!114 &289368611602352569
m_EditorClassIdentifier: Assembly-CSharp::OnlyScove.Scripts.PlayerStats
_Health: 100
_Stamina: 100
_NoiseLevel: 0
--- !u!114 &517879385770431681
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2962936552048247184}
m_GameObject: {fileID: 1054594849095937263}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: dc42784cf147c0c48a680349fa168899, type: 3}
m_Script: {fileID: 11500000, guid: 9dcff2851697b4f4c8c25ef8381665ba, type: 3}
m_Name:
m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.GraphicRaycaster
m_IgnoreReversedGraphics: 1
m_BlockingObjects: 0
m_BlockingMask:
m_EditorClassIdentifier: Assembly-CSharp::OnlyScove.Scripts.PlayerInteraction
InteractionRange: 2
InteractionMask:
serializedVersion: 2
m_Bits: 4294967295
m_Bits: 512
--- !u!114 &8601091490777624370
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1054594849095937263}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 79bbcfd4d37b7834ebe0d61bb649714d, type: 3}
m_Name:
m_EditorClassIdentifier: Assembly-CSharp::OnlyScove.Scripts.PlayerMovement
<WalkSpeed>k__BackingField: 3
<RunSpeed>k__BackingField: 6
<SprintSpeed>k__BackingField: 9
<SneakSpeed>k__BackingField: 1.5
<DashForce>k__BackingField: 10
<RotationSpeed>k__BackingField: 500
<JumpHeight>k__BackingField: 2
<Gravity>k__BackingField: -15
<ThrustDownwardForce>k__BackingField: -20
<GroundCheckRadius>k__BackingField: 0.2
<GroundCheckOffset>k__BackingField: {x: 0, y: 0, z: 0}
<GroundMask>k__BackingField:
serializedVersion: 2
m_Bits: 64
_IsGrounded: 0
_WasGrounded: 0
_VelocityY: 0
_NetworkedPosition: {x: 0, y: 0, z: 0}
--- !u!114 &7730391503324595278
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1054594849095937263}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 965ec86f3b9695640bdc85e624d0e9e7, type: 3}
m_Name:
m_EditorClassIdentifier: Assembly-CSharp::OnlyScove.Scripts.PlayerAnimationHandler
speedParamName: Speed
velocityXParamName: Velocity X
velocityZParamName: Velocity Z
animationDamping: 0.2
--- !u!114 &3043298118541876184
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1054594849095937263}
m_Enabled: 0
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: e16a6690e589f0449ad89a6bf508ab62, type: 3}
m_Name:
m_EditorClassIdentifier: Assembly-CSharp::OnlyScove.Scripts.GameSetup.CharacterAutoSetup
defaultHeight: 1.8
defaultShoulderWidth: 0.4
modelRoot: {fileID: 0}
autoDetectOnStart: 0
zCenterOffset: 0.05
--- !u!114 &5773292363125757170
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1054594849095937263}
m_Enabled: 0
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 271dd39a46bad974485107bb1a070e0a, type: 3}
m_Name:
m_EditorClassIdentifier: Assembly-CSharp::OnlyScove.Scripts.SukunaDomainController
playerStateMachine: {fileID: 830356296960548640}
slashPrefab: {fileID: 7424378359907903745, guid: 80f98b444eac25541afe9e9081c8303a, type: 3}
shrinePrefab: {fileID: 5712645696331672719, guid: b0b71c635e9971346ae9ab6b7ecdd65d, type: 3}
domainVolumeProfile: {fileID: 11400000, guid: 837c34edbcc0ece44ae8c54e25ec20de, type: 2}
cinematicCameraPoint: {fileID: 0}
domainRadius: 30
domainDuration: 10
slashRate: 100
shrineRiseHeight: 5
shrineFloorOffset: 0.5
camMoveSpeed: 4
--- !u!114 &3866929919288054183
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1054594849095937263}
m_Enabled: 0
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 1630760c9d97a5f4eb1bc179549c95cd, type: 3}
m_Name:
m_EditorClassIdentifier: Assembly-CSharp::SukunaAbilityController
inputReader: {fileID: 5600577104145922999}
blackProjectilePrefab: {fileID: 7925862234553078923, guid: a9db8dc0d7288b8418ab54e786fbffa7, type: 3}
redProjectilePrefab: {fileID: 1113287330716207023, guid: 03163717f6c5cad409e7e7f079f06ea5, type: 3}
attackRate: 0.1
forwardOffset: 4.55
verticalOffset: 1
rangeX: {x: -360, y: 360}
rangeY: {x: -10, y: 10}
rangeZ: {x: 50, y: 120}
--- !u!1 &3751838835891881608
GameObject:
m_ObjectHideFlags: 0
@@ -803,143 +766,6 @@ Transform:
m_Children: []
m_Father: {fileID: 3154409663696148700}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &8169517334317903866
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 7931877178581140798}
- component: {fileID: 5886073058445326450}
- component: {fileID: 4162277074137292865}
m_Layer: 5
m_Name: PlayerNameCanvas
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &7931877178581140798
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 8169517334317903866}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 197467923929726417}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 0.5}
m_AnchorMax: {x: 0.5, y: 0.5}
m_AnchoredPosition: {x: -90.9, y: 14.141}
m_SizeDelta: {x: 291.33, y: 45.719}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &5886073058445326450
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 8169517334317903866}
m_CullTransparentMesh: 1
--- !u!114 &4162277074137292865
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 8169517334317903866}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3}
m_Name:
m_EditorClassIdentifier: Unity.TextMeshPro::TMPro.TextMeshProUGUI
m_Material: {fileID: 0}
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_RaycastTarget: 1
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_text: PlayerName
m_isRightToLeft: 0
m_fontAsset: {fileID: 11400000, guid: a32ff21294cb0854181fe2ea1602ab9f, type: 2}
m_sharedMaterial: {fileID: -5366533617542256513, guid: a32ff21294cb0854181fe2ea1602ab9f, type: 2}
m_fontSharedMaterials: []
m_fontMaterial: {fileID: 0}
m_fontMaterials: []
m_fontColor32:
serializedVersion: 2
rgba: 4294967295
m_fontColor: {r: 1, g: 1, b: 1, a: 1}
m_enableVertexGradient: 0
m_colorMode: 3
m_fontColorGradient:
topLeft: {r: 1, g: 1, b: 1, a: 1}
topRight: {r: 1, g: 1, b: 1, a: 1}
bottomLeft: {r: 1, g: 1, b: 1, a: 1}
bottomRight: {r: 1, g: 1, b: 1, a: 1}
m_fontColorGradientPreset: {fileID: 0}
m_spriteAsset: {fileID: 0}
m_tintAllSprites: 0
m_StyleSheet: {fileID: 0}
m_TextStyleHashCode: -1183493901
m_overrideHtmlColors: 0
m_faceColor:
serializedVersion: 2
rgba: 4294967295
m_fontSize: 44.85
m_fontSizeBase: 36
m_fontWeight: 400
m_enableAutoSizing: 1
m_fontSizeMin: 18
m_fontSizeMax: 72
m_fontStyle: 1
m_HorizontalAlignment: 2
m_VerticalAlignment: 512
m_textAlignment: 65535
m_characterSpacing: 0
m_characterHorizontalScale: 1
m_wordSpacing: 0
m_lineSpacing: 0
m_lineSpacingMax: 0
m_paragraphSpacing: 0
m_charWidthMaxAdj: 0
m_TextWrappingMode: 1
m_wordWrappingRatios: 0.4
m_overflowMode: 0
m_linkedTextComponent: {fileID: 0}
parentLinkedComponent: {fileID: 0}
m_enableKerning: 0
m_ActiveFontFeatures: 6e72656b
m_enableExtraPadding: 0
checkPaddingRequired: 0
m_isRichText: 1
m_EmojiFallbackSupport: 1
m_parseCtrlCharacters: 1
m_isOrthographic: 1
m_isCullingEnabled: 0
m_horizontalMapping: 0
m_verticalMapping: 0
m_uvLineOffset: 0
m_geometrySortingOrder: 0
m_IsTextObjectScaleStatic: 0
m_VertexBufferAutoSizeReduction: 0
m_useMaxVisibleDescender: 1
m_pageToDisplay: 1
m_margin: {x: 0, y: 0, z: 0, w: 0}
m_isUsingLegacyAnimationComponent: 0
m_isVolumetricText: 0
m_hasFontAssetChanged: 0
m_baseMaterial: {fileID: 0}
m_maskOffset: {x: 0, y: 0, z: 0, w: 0}
--- !u!1 &8335303598418656312
GameObject:
m_ObjectHideFlags: 0
@@ -1074,15 +900,15 @@ PrefabInstance:
objectReference: {fileID: 0}
- target: {fileID: -8679921383154817045, guid: 5847774ba45dc754598435b50d4a0247, type: 3}
propertyPath: m_LocalRotation.x
value: -0
value: 0
objectReference: {fileID: 0}
- target: {fileID: -8679921383154817045, guid: 5847774ba45dc754598435b50d4a0247, type: 3}
propertyPath: m_LocalRotation.y
value: -0
value: 0
objectReference: {fileID: 0}
- target: {fileID: -8679921383154817045, guid: 5847774ba45dc754598435b50d4a0247, type: 3}
propertyPath: m_LocalRotation.z
value: -0
value: 0
objectReference: {fileID: 0}
- target: {fileID: -8679921383154817045, guid: 5847774ba45dc754598435b50d4a0247, type: 3}
propertyPath: m_LocalEulerAnglesHint.x

View File

@@ -1,433 +0,0 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1 &1516699870267512982
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 6453919682029617511}
- component: {fileID: 6813582908554084193}
- component: {fileID: 7974153401190947535}
m_Layer: 0
m_Name: Doc_Lobby
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &6453919682029617511
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1516699870267512982}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 8276456597194509742}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &6813582908554084193
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1516699870267512982}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 19102, guid: 0000000000000000e000000000000000, type: 0}
m_Name:
m_EditorClassIdentifier: UnityEngine.dll::UnityEngine.UIElements.UIDocument
m_PanelSettings: {fileID: 11400000, guid: 04bb65da4fe76fc4a9926df48b2ba88b, type: 2}
m_ParentUI: {fileID: 0}
sourceAsset: {fileID: 9197481963319205126, guid: 971b07b6bc60233469ca493b8f558225, type: 3}
m_SortingOrder: 0
m_Position: 0
m_WorldSpaceSizeMode: 1
m_WorldSpaceWidth: 1920
m_WorldSpaceHeight: 1080
m_PivotReferenceSize: 0
m_Pivot: 0
m_WorldSpaceCollider: {fileID: 0}
--- !u!114 &7974153401190947535
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1516699870267512982}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 9c37c552a9c18a242bcc8860a0a5212f, type: 3}
m_Name:
m_EditorClassIdentifier: Assembly-CSharp::UI.LobbyController
--- !u!1 &2410419006187484205
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 8461124296799354270}
- component: {fileID: 3626156559027302038}
- component: {fileID: 764133115834169797}
m_Layer: 0
m_Name: Doc_MainMenu
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &8461124296799354270
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2410419006187484205}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 8276456597194509742}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &3626156559027302038
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2410419006187484205}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 19102, guid: 0000000000000000e000000000000000, type: 0}
m_Name:
m_EditorClassIdentifier: UnityEngine.dll::UnityEngine.UIElements.UIDocument
m_PanelSettings: {fileID: 11400000, guid: 04bb65da4fe76fc4a9926df48b2ba88b, type: 2}
m_ParentUI: {fileID: 0}
sourceAsset: {fileID: 9197481963319205126, guid: 1e4b5a7d928d98949af5f96c310e5e05, type: 3}
m_SortingOrder: 0
m_Position: 0
m_WorldSpaceSizeMode: 1
m_WorldSpaceWidth: 1920
m_WorldSpaceHeight: 1080
m_PivotReferenceSize: 0
m_Pivot: 0
m_WorldSpaceCollider: {fileID: 0}
--- !u!114 &764133115834169797
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2410419006187484205}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 691980524acfc544f9660cfc35ce3616, type: 3}
m_Name:
m_EditorClassIdentifier: Assembly-CSharp::UI.MainMenuController
--- !u!1 &6159906463171050867
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 822770786713092587}
- component: {fileID: 8053006371428885710}
- component: {fileID: 2147182326353943992}
m_Layer: 0
m_Name: Doc_HUD
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &822770786713092587
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6159906463171050867}
serializedVersion: 2
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 8276456597194509742}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &8053006371428885710
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6159906463171050867}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 19102, guid: 0000000000000000e000000000000000, type: 0}
m_Name:
m_EditorClassIdentifier: UnityEngine.dll::UnityEngine.UIElements.UIDocument
m_PanelSettings: {fileID: 11400000, guid: 04bb65da4fe76fc4a9926df48b2ba88b, type: 2}
m_ParentUI: {fileID: 0}
sourceAsset: {fileID: 9197481963319205126, guid: b8da157d472223d4889a01228b36ef8b, type: 3}
m_SortingOrder: 0
m_Position: 0
m_WorldSpaceSizeMode: 1
m_WorldSpaceWidth: 1920
m_WorldSpaceHeight: 1080
m_PivotReferenceSize: 0
m_Pivot: 0
m_WorldSpaceCollider: {fileID: 0}
--- !u!114 &2147182326353943992
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6159906463171050867}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: e79b70607af6eeb458c8eb6605e39b56, type: 3}
m_Name:
m_EditorClassIdentifier: Assembly-CSharp::UI.HUDController
hudDocument: {fileID: 8053006371428885710}
--- !u!1 &6763625687744439349
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 7659132307210635102}
- component: {fileID: 6856417540668204016}
- component: {fileID: 1773991564882589527}
m_Layer: 0
m_Name: Doc_Profile
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &7659132307210635102
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6763625687744439349}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 8276456597194509742}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &6856417540668204016
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6763625687744439349}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 19102, guid: 0000000000000000e000000000000000, type: 0}
m_Name:
m_EditorClassIdentifier: UnityEngine.dll::UnityEngine.UIElements.UIDocument
m_PanelSettings: {fileID: 11400000, guid: 04bb65da4fe76fc4a9926df48b2ba88b, type: 2}
m_ParentUI: {fileID: 0}
sourceAsset: {fileID: 9197481963319205126, guid: 4b61efb7dda830a43ad6b05998e85a6d, type: 3}
m_SortingOrder: 0
m_Position: 0
m_WorldSpaceSizeMode: 1
m_WorldSpaceWidth: 1920
m_WorldSpaceHeight: 1080
m_PivotReferenceSize: 0
m_Pivot: 0
m_WorldSpaceCollider: {fileID: 0}
--- !u!114 &1773991564882589527
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6763625687744439349}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: fdea16b110511ef45889ed832b63560b, type: 3}
m_Name:
m_EditorClassIdentifier: Assembly-CSharp::UI.ProfileController
--- !u!1 &7591431613855332517
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1702629541674960093}
- component: {fileID: 3426083132238065776}
- component: {fileID: 8400758018383374091}
- component: {fileID: 7573251387093448480}
m_Layer: 0
m_Name: Doc_Settings
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &1702629541674960093
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 7591431613855332517}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 8276456597194509742}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &3426083132238065776
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 7591431613855332517}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 19102, guid: 0000000000000000e000000000000000, type: 0}
m_Name:
m_EditorClassIdentifier: UnityEngine.dll::UnityEngine.UIElements.UIDocument
m_PanelSettings: {fileID: 11400000, guid: 04bb65da4fe76fc4a9926df48b2ba88b, type: 2}
m_ParentUI: {fileID: 0}
sourceAsset: {fileID: 9197481963319205126, guid: b35e62e5dcc1bfb42bf0d3f630fc356d, type: 3}
m_SortingOrder: 0
m_Position: 0
m_WorldSpaceSizeMode: 1
m_WorldSpaceWidth: 1920
m_WorldSpaceHeight: 1080
m_PivotReferenceSize: 0
m_Pivot: 0
m_WorldSpaceCollider: {fileID: 0}
--- !u!114 &8400758018383374091
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 7591431613855332517}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 5534bcf4869df944883c6fd2a17a6a5a, type: 3}
m_Name:
m_EditorClassIdentifier: Assembly-CSharp::UI.SettingsController
--- !u!114 &7573251387093448480
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 7591431613855332517}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 5c17a3f09ee49ff48a0e3e2b45080257, type: 3}
m_Name:
m_EditorClassIdentifier: Assembly-CSharp::UI.LocalizationManager
--- !u!1 &7733679024748988208
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 8276456597194509742}
- component: {fileID: 5040632603729643308}
m_Layer: 0
m_Name: UIManager
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &8276456597194509742
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 7733679024748988208}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: -16135.612, y: -11645.337, z: 92.19762}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 8461124296799354270}
- {fileID: 6453919682029617511}
- {fileID: 822770786713092587}
- {fileID: 1702629541674960093}
- {fileID: 7659132307210635102}
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &5040632603729643308
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 7733679024748988208}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: bcb7b8ed439bb4546b0648c627c2ce5d, type: 3}
m_Name:
m_EditorClassIdentifier: Assembly-CSharp::UI.UIManager
screens:
- screenName: MainMenu
document: {fileID: 3626156559027302038}
isActive: 1
isOverlay: 0
customCursor: {fileID: 0}
- screenName: Lobby
document: {fileID: 6813582908554084193}
isActive: 0
isOverlay: 0
customCursor: {fileID: 0}
- screenName: HUD
document: {fileID: 8053006371428885710}
isActive: 0
isOverlay: 0
customCursor: {fileID: 0}
- screenName: Settings
document: {fileID: 3426083132238065776}
isActive: 0
isOverlay: 1
customCursor: {fileID: 0}
- screenName: Profile
document: {fileID: 6856417540668204016}
isActive: 0
isOverlay: 0
customCursor: {fileID: 0}
defaultCursor: {fileID: 0}
initialScreen: MainMenu

View File

@@ -119,7 +119,7 @@ NavMeshSettings:
debug:
m_Flags: 0
m_NavMeshData: {fileID: 0}
--- !u!1 &257796813
--- !u!1 &458228298
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
@@ -127,31 +127,59 @@ GameObject:
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 257796816}
- component: {fileID: 257796814}
- component: {fileID: 257796815}
- component: {fileID: 458228301}
- component: {fileID: 458228300}
- component: {fileID: 458228299}
m_Layer: 0
m_Name: Doc_Lounge
m_Name: UIManager
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!114 &257796814
--- !u!114 &458228299
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 257796813}
m_GameObject: {fileID: 458228298}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: bcb7b8ed439bb4546b0648c627c2ce5d, type: 3}
m_Name:
m_EditorClassIdentifier: Assembly-CSharp::Hallucinate.UI.UIManager
inputReader: {fileID: 2128442884}
gameIcon: {fileID: 0}
cursorSprite: {fileID: 21300000, guid: bf03bd4e32f382f45bd848d91517f188, type: 3}
cursorTrailSprite: {fileID: 21300000, guid: b9c4a623634019648b505c6122243b00, type: 3}
cursorSize: 57
trailLength: 15
trailSpacing: 2
enableRipples: 1
rippleColor: {r: 1, g: 1, b: 1, a: 0.5}
loginTemplate: {fileID: 9197481963319205126, guid: 4f11f2cb91fbd4748bcbc70cd0f5afe7, type: 3}
mainMenuTemplate: {fileID: 9197481963319205126, guid: 8dcbe9fd5e8c43c43921af21a6347624, type: 3}
lobbyTemplate: {fileID: 9197481963319205126, guid: 2b2480fff4320714e9b503e7d5ef2c9f, type: 3}
roomItemTemplate: {fileID: 9197481963319205126, guid: 1be64545006384b4dbaa87849f32b8ba, type: 3}
profileTemplate: {fileID: 9197481963319205126, guid: e481c7d94f843374cb57e215bf9b0624, type: 3}
settingsTemplate: {fileID: 9197481963319205126, guid: 1e24e32e93afac8449d0bb181ab5c6a9, type: 3}
hudTemplate: {fileID: 9197481963319205126, guid: b87ba33c06a8c1d46a3d9f03416ebf3f, type: 3}
--- !u!114 &458228300
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 458228298}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 19102, guid: 0000000000000000e000000000000000, type: 0}
m_Name:
m_EditorClassIdentifier: UnityEngine.dll::UnityEngine.UIElements.UIDocument
m_PanelSettings: {fileID: 11400000, guid: 04bb65da4fe76fc4a9926df48b2ba88b, type: 2}
m_PanelSettings: {fileID: 11400000, guid: c093ebe66178f9047be53f245ccc3c2d, type: 2}
m_ParentUI: {fileID: 0}
sourceAsset: {fileID: 9197481963319205126, guid: 1acf05b4c3eb7964b9b87b16b66c85f8, type: 3}
sourceAsset: {fileID: 0}
m_SortingOrder: 0
m_Position: 0
m_WorldSpaceSizeMode: 1
@@ -160,32 +188,20 @@ MonoBehaviour:
m_PivotReferenceSize: 0
m_Pivot: 0
m_WorldSpaceCollider: {fileID: 0}
--- !u!114 &257796815
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 257796813}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: ac201603ede0899488995be3d88ea0dc, type: 3}
m_Name:
m_EditorClassIdentifier: Assembly-CSharp::UI.LoungeController
--- !u!4 &257796816
--- !u!4 &458228301
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 257796813}
m_GameObject: {fileID: 458228298}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalPosition: {x: -16124.571, y: -11651.664, z: 100.93924}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 1183887570}
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &626355268
GameObject:
@@ -314,375 +330,6 @@ MonoBehaviour:
m_ShadowLayerMask: 1
m_RenderingLayers: 1
m_ShadowRenderingLayers: 1
--- !u!1 &666657091
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 666657093}
- component: {fileID: 666657092}
- component: {fileID: 666657094}
m_Layer: 0
m_Name: Doc_Profile
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!114 &666657092
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 666657091}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 19102, guid: 0000000000000000e000000000000000, type: 0}
m_Name:
m_EditorClassIdentifier: UnityEngine.dll::UnityEngine.UIElements.UIDocument
m_PanelSettings: {fileID: 11400000, guid: 04bb65da4fe76fc4a9926df48b2ba88b, type: 2}
m_ParentUI: {fileID: 0}
sourceAsset: {fileID: 9197481963319205126, guid: 4b61efb7dda830a43ad6b05998e85a6d, type: 3}
m_SortingOrder: 0
m_Position: 0
m_WorldSpaceSizeMode: 1
m_WorldSpaceWidth: 1920
m_WorldSpaceHeight: 1080
m_PivotReferenceSize: 0
m_Pivot: 0
m_WorldSpaceCollider: {fileID: 0}
--- !u!4 &666657093
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 666657091}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 1183887570}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &666657094
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 666657091}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: fdea16b110511ef45889ed832b63560b, type: 3}
m_Name:
m_EditorClassIdentifier: Assembly-CSharp::UI.ProfileController
--- !u!1 &1136953558
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1136953560}
- component: {fileID: 1136953559}
- component: {fileID: 1136953561}
m_Layer: 0
m_Name: Doc_HUD
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!114 &1136953559
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1136953558}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 19102, guid: 0000000000000000e000000000000000, type: 0}
m_Name:
m_EditorClassIdentifier: UnityEngine.dll::UnityEngine.UIElements.UIDocument
m_PanelSettings: {fileID: 11400000, guid: 04bb65da4fe76fc4a9926df48b2ba88b, type: 2}
m_ParentUI: {fileID: 0}
sourceAsset: {fileID: 9197481963319205126, guid: b8da157d472223d4889a01228b36ef8b, type: 3}
m_SortingOrder: 0
m_Position: 0
m_WorldSpaceSizeMode: 1
m_WorldSpaceWidth: 1920
m_WorldSpaceHeight: 1080
m_PivotReferenceSize: 0
m_Pivot: 0
m_WorldSpaceCollider: {fileID: 0}
--- !u!4 &1136953560
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1136953558}
serializedVersion: 2
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 1183887570}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &1136953561
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1136953558}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: e79b70607af6eeb458c8eb6605e39b56, type: 3}
m_Name:
m_EditorClassIdentifier: Assembly-CSharp::UI.HUDController
hudDocument: {fileID: 1136953559}
autoHideDelay: 5
--- !u!1 &1183887568
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1183887570}
- component: {fileID: 1183887569}
m_Layer: 0
m_Name: UIManager
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!114 &1183887569
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1183887568}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: bcb7b8ed439bb4546b0648c627c2ce5d, type: 3}
m_Name:
m_EditorClassIdentifier: Assembly-CSharp::UI.UIManager
screens:
- screenName: MainMenu
document: {fileID: 2003742651}
isOverlay: 0
isActive: 0
- screenName: Lobby
document: {fileID: 1471116802}
isOverlay: 0
isActive: 1
- screenName: Lounge
document: {fileID: 257796814}
isOverlay: 0
isActive: 0
- screenName: HUD
document: {fileID: 1136953559}
isOverlay: 0
isActive: 0
- screenName: Settings
document: {fileID: 1582124357}
isOverlay: 1
isActive: 0
- screenName: Profile
document: {fileID: 666657092}
isOverlay: 0
isActive: 0
initialScreen: MainMenu
trailSprite: {fileID: 21300000, guid: b9c4a623634019648b505c6122243b00, type: 3}
trailFadeSpeed: 3
trailCount: 15
focusRadius: 300
globalOpacity: 1
isMainMenuActive: 0
--- !u!4 &1183887570
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1183887568}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: -16135.612, y: -11645.337, z: 92.19762}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 2003742650}
- {fileID: 1471116803}
- {fileID: 257796816}
- {fileID: 1136953560}
- {fileID: 1582124358}
- {fileID: 666657093}
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &1471116801
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1471116803}
- component: {fileID: 1471116802}
- component: {fileID: 1471116804}
m_Layer: 0
m_Name: Doc_Lobby
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!114 &1471116802
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1471116801}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 19102, guid: 0000000000000000e000000000000000, type: 0}
m_Name:
m_EditorClassIdentifier: UnityEngine.dll::UnityEngine.UIElements.UIDocument
m_PanelSettings: {fileID: 11400000, guid: 04bb65da4fe76fc4a9926df48b2ba88b, type: 2}
m_ParentUI: {fileID: 0}
sourceAsset: {fileID: 9197481963319205126, guid: 971b07b6bc60233469ca493b8f558225, type: 3}
m_SortingOrder: 0
m_Position: 0
m_WorldSpaceSizeMode: 1
m_WorldSpaceWidth: 1920
m_WorldSpaceHeight: 1080
m_PivotReferenceSize: 0
m_Pivot: 0
m_WorldSpaceCollider: {fileID: 0}
--- !u!4 &1471116803
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1471116801}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 1183887570}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &1471116804
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1471116801}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 9c37c552a9c18a242bcc8860a0a5212f, type: 3}
m_Name:
m_EditorClassIdentifier: Assembly-CSharp::UI.LobbyController
--- !u!1 &1582124356
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1582124358}
- component: {fileID: 1582124357}
- component: {fileID: 1582124359}
- component: {fileID: 1582124360}
m_Layer: 0
m_Name: Doc_Settings
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!114 &1582124357
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1582124356}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 19102, guid: 0000000000000000e000000000000000, type: 0}
m_Name:
m_EditorClassIdentifier: UnityEngine.dll::UnityEngine.UIElements.UIDocument
m_PanelSettings: {fileID: 11400000, guid: 04bb65da4fe76fc4a9926df48b2ba88b, type: 2}
m_ParentUI: {fileID: 0}
sourceAsset: {fileID: 9197481963319205126, guid: b35e62e5dcc1bfb42bf0d3f630fc356d, type: 3}
m_SortingOrder: 0
m_Position: 0
m_WorldSpaceSizeMode: 1
m_WorldSpaceWidth: 1920
m_WorldSpaceHeight: 1080
m_PivotReferenceSize: 0
m_Pivot: 0
m_WorldSpaceCollider: {fileID: 0}
--- !u!4 &1582124358
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1582124356}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 1183887570}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &1582124359
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1582124356}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 5534bcf4869df944883c6fd2a17a6a5a, type: 3}
m_Name:
m_EditorClassIdentifier: Assembly-CSharp::UI.SettingsController
--- !u!114 &1582124360
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1582124356}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 5c17a3f09ee49ff48a0e3e2b45080257, type: 3}
m_Name:
m_EditorClassIdentifier: Assembly-CSharp::UI.LocalizationManager
--- !u!1 &1848374378
GameObject:
m_ObjectHideFlags: 0
@@ -820,7 +467,7 @@ MonoBehaviour:
m_VarianceClampScale: 0.9
m_ContrastAdaptiveSharpening: 0
m_Version: 2
--- !u!1 &2003742649
--- !u!1 &2128442883
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
@@ -828,74 +475,302 @@ GameObject:
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 2003742650}
- component: {fileID: 2003742651}
- component: {fileID: 2003742652}
- component: {fileID: 2128442885}
- component: {fileID: 2128442884}
- component: {fileID: 2128442886}
m_Layer: 0
m_Name: Doc_MainMenu
m_Name: InputReader
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &2003742650
--- !u!114 &2128442884
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2128442883}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 5962d8f2c8e40e240a4a4907c7b539fa, type: 3}
m_Name:
m_EditorClassIdentifier: Assembly-CSharp::OnlyScove.Scripts.InputReader
--- !u!4 &2128442885
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2003742649}
m_GameObject: {fileID: 2128442883}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalPosition: {x: -16124.571, y: -11651.664, z: 100.93924}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 1183887570}
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &2003742651
--- !u!114 &2128442886
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2003742649}
m_GameObject: {fileID: 2128442883}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 19102, guid: 0000000000000000e000000000000000, type: 0}
m_Script: {fileID: 11500000, guid: 62899f850307741f2a39c98a8b639597, type: 3}
m_Name:
m_EditorClassIdentifier: UnityEngine.dll::UnityEngine.UIElements.UIDocument
m_PanelSettings: {fileID: 11400000, guid: 04bb65da4fe76fc4a9926df48b2ba88b, type: 2}
m_ParentUI: {fileID: 0}
sourceAsset: {fileID: 9197481963319205126, guid: 1e4b5a7d928d98949af5f96c310e5e05, type: 3}
m_SortingOrder: 0
m_Position: 0
m_WorldSpaceSizeMode: 1
m_WorldSpaceWidth: 1920
m_WorldSpaceHeight: 1080
m_PivotReferenceSize: 0
m_Pivot: 0
m_WorldSpaceCollider: {fileID: 0}
--- !u!114 &2003742652
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2003742649}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 691980524acfc544f9660cfc35ce3616, type: 3}
m_Name:
m_EditorClassIdentifier: Assembly-CSharp::UI.MainMenuController
transitionDuration: 0.5
idleTimeout: 5
pulseSpeed: 2
pulseAmount: 0.1
m_EditorClassIdentifier: Unity.InputSystem::UnityEngine.InputSystem.PlayerInput
m_Actions: {fileID: -944628639613478452, guid: ac73bbdc8e64ac34c9525df400c1534f, type: 3}
m_NotificationBehavior: 2
m_UIInputModule: {fileID: 0}
m_DeviceLostEvent:
m_PersistentCalls:
m_Calls: []
m_DeviceRegainedEvent:
m_PersistentCalls:
m_Calls: []
m_ControlsChangedEvent:
m_PersistentCalls:
m_Calls: []
m_ActionEvents:
- m_PersistentCalls:
m_Calls:
- m_Target: {fileID: 0}
m_TargetAssemblyTypeName: OnlyScove.Scripts.InputReader, Assembly-CSharp
m_MethodName: OnMove
m_Mode: 0
m_Arguments:
m_ObjectArgument: {fileID: 0}
m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine
m_IntArgument: 0
m_FloatArgument: 0
m_StringArgument:
m_BoolArgument: 0
m_CallState: 2
m_ActionId: 351f2ccd-1f9f-44bf-9bec-d62ac5c5f408
m_ActionName: 'Player/Move[/Keyboard/w,/Keyboard/upArrow,/Keyboard/s,/Keyboard/downArrow,/Keyboard/a,/Keyboard/leftArrow,/Keyboard/d,/Keyboard/rightArrow]'
- m_PersistentCalls:
m_Calls:
- m_Target: {fileID: 0}
m_TargetAssemblyTypeName: OnlyScove.Scripts.InputReader, Assembly-CSharp
m_MethodName: OnLook
m_Mode: 0
m_Arguments:
m_ObjectArgument: {fileID: 0}
m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine
m_IntArgument: 0
m_FloatArgument: 0
m_StringArgument:
m_BoolArgument: 0
m_CallState: 2
m_ActionId: 6b444451-8a00-4d00-a97e-f47457f736a8
m_ActionName: 'Player/Look[/Mouse/delta]'
- m_PersistentCalls:
m_Calls:
- m_Target: {fileID: 0}
m_TargetAssemblyTypeName: OnlyScove.Scripts.InputReader, Assembly-CSharp
m_MethodName: OnAttack
m_Mode: 0
m_Arguments:
m_ObjectArgument: {fileID: 0}
m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine
m_IntArgument: 0
m_FloatArgument: 0
m_StringArgument:
m_BoolArgument: 0
m_CallState: 2
m_ActionId: 6c2ab1b8-8984-453a-af3d-a3c78ae1679a
m_ActionName: 'Player/Attack[/Mouse/leftButton,/Keyboard/enter]'
- m_PersistentCalls:
m_Calls:
- m_Target: {fileID: 0}
m_TargetAssemblyTypeName: OnlyScove.Scripts.InputReader, Assembly-CSharp
m_MethodName: OnInteract
m_Mode: 0
m_Arguments:
m_ObjectArgument: {fileID: 0}
m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine
m_IntArgument: 0
m_FloatArgument: 0
m_StringArgument:
m_BoolArgument: 0
m_CallState: 2
m_ActionId: 852140f2-7766-474d-8707-702459ba45f3
m_ActionName: 'Player/Interact[/Keyboard/e]'
- m_PersistentCalls:
m_Calls:
- m_Target: {fileID: 0}
m_TargetAssemblyTypeName: OnlyScove.Scripts.InputReader, Assembly-CSharp
m_MethodName: OnCrouch
m_Mode: 0
m_Arguments:
m_ObjectArgument: {fileID: 0}
m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine
m_IntArgument: 0
m_FloatArgument: 0
m_StringArgument:
m_BoolArgument: 0
m_CallState: 2
m_ActionId: 27c5f898-bc57-4ee1-8800-db469aca5fe3
m_ActionName: 'Player/Crouch[/Keyboard/c]'
- m_PersistentCalls:
m_Calls:
- m_Target: {fileID: 0}
m_TargetAssemblyTypeName: OnlyScove.Scripts.InputReader, Assembly-CSharp
m_MethodName: OnJump
m_Mode: 0
m_Arguments:
m_ObjectArgument: {fileID: 0}
m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine
m_IntArgument: 0
m_FloatArgument: 0
m_StringArgument:
m_BoolArgument: 0
m_CallState: 2
m_ActionId: f1ba0d36-48eb-4cd5-b651-1c94a6531f70
m_ActionName: 'Player/Jump[/Keyboard/space]'
- m_PersistentCalls:
m_Calls:
- m_Target: {fileID: 0}
m_TargetAssemblyTypeName: OnlyScove.Scripts.InputReader, Assembly-CSharp
m_MethodName: OnPrevious
m_Mode: 0
m_Arguments:
m_ObjectArgument: {fileID: 0}
m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine
m_IntArgument: 0
m_FloatArgument: 0
m_StringArgument:
m_BoolArgument: 0
m_CallState: 2
m_ActionId: 2776c80d-3c14-4091-8c56-d04ced07a2b0
m_ActionName: 'Player/Previous[/Keyboard/1]'
- m_PersistentCalls:
m_Calls:
- m_Target: {fileID: 0}
m_TargetAssemblyTypeName: OnlyScove.Scripts.InputReader, Assembly-CSharp
m_MethodName: OnNext
m_Mode: 0
m_Arguments:
m_ObjectArgument: {fileID: 0}
m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine
m_IntArgument: 0
m_FloatArgument: 0
m_StringArgument:
m_BoolArgument: 0
m_CallState: 2
m_ActionId: b7230bb6-fc9b-4f52-8b25-f5e19cb2c2ba
m_ActionName: 'Player/Next[/Keyboard/2]'
- m_PersistentCalls:
m_Calls:
- m_Target: {fileID: 0}
m_TargetAssemblyTypeName: OnlyScove.Scripts.InputReader, Assembly-CSharp
m_MethodName: OnSprint
m_Mode: 0
m_Arguments:
m_ObjectArgument: {fileID: 0}
m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine
m_IntArgument: 0
m_FloatArgument: 0
m_StringArgument:
m_BoolArgument: 0
m_CallState: 2
m_ActionId: 641cd816-40e6-41b4-8c3d-04687c349290
m_ActionName: 'Player/Sprint[/Keyboard/leftShift]'
- m_PersistentCalls:
m_Calls: []
m_ActionId: c95b2375-e6d9-4b88-9c4c-c5e76515df4b
m_ActionName: 'UI/Navigate[/Keyboard/w,/Keyboard/upArrow,/Keyboard/s,/Keyboard/downArrow,/Keyboard/a,/Keyboard/leftArrow,/Keyboard/d,/Keyboard/rightArrow]'
- m_PersistentCalls:
m_Calls: []
m_ActionId: 7607c7b6-cd76-4816-beef-bd0341cfe950
m_ActionName: 'UI/Submit[/Keyboard/enter]'
- m_PersistentCalls:
m_Calls: []
m_ActionId: 15cef263-9014-4fd5-94d9-4e4a6234a6ef
m_ActionName: 'UI/Cancel[/Keyboard/escape]'
- m_PersistentCalls:
m_Calls: []
m_ActionId: 32b35790-4ed0-4e9a-aa41-69ac6d629449
m_ActionName: 'UI/Point[/Mouse/position]'
- m_PersistentCalls:
m_Calls: []
m_ActionId: 3c7022bf-7922-4f7c-a998-c437916075ad
m_ActionName: 'UI/Click[/Mouse/leftButton]'
- m_PersistentCalls:
m_Calls: []
m_ActionId: 44b200b1-1557-4083-816c-b22cbdf77ddf
m_ActionName: 'UI/RightClick[/Mouse/rightButton]'
- m_PersistentCalls:
m_Calls: []
m_ActionId: dad70c86-b58c-4b17-88ad-f5e53adf419e
m_ActionName: 'UI/MiddleClick[/Mouse/middleButton]'
- m_PersistentCalls:
m_Calls: []
m_ActionId: 0489e84a-4833-4c40-bfae-cea84b696689
m_ActionName: 'UI/ScrollWheel[/Mouse/scroll]'
- m_PersistentCalls:
m_Calls: []
m_ActionId: 24908448-c609-4bc3-a128-ea258674378a
m_ActionName: UI/TrackedDevicePosition
- m_PersistentCalls:
m_Calls: []
m_ActionId: 9caa3d8a-6b2f-4e8e-8bad-6ede561bd9be
m_ActionName: UI/TrackedDeviceOrientation
- m_PersistentCalls:
m_Calls: []
m_ActionId: 1702ffae-5ad3-4532-9855-bf7e2a8ae749
m_ActionName: 'Player/Scroll[/Mouse/scroll]'
- m_PersistentCalls:
m_Calls: []
m_ActionId: 7e8b9416-0a2d-4652-98d8-e7368560ede9
m_ActionName: 'Player/Change View[/Keyboard/f2]'
- m_PersistentCalls:
m_Calls:
- m_Target: {fileID: 2128442884}
m_TargetAssemblyTypeName: OnlyScove.Scripts.InputReader, Assembly-CSharp
m_MethodName: OnToggleSettings
m_Mode: 0
m_Arguments:
m_ObjectArgument: {fileID: 0}
m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine
m_IntArgument: 0
m_FloatArgument: 0
m_StringArgument:
m_BoolArgument: 0
m_CallState: 1
m_ActionId: ae29d662-c797-4411-8ff3-8b5ad78427d8
m_ActionName: 'UI/ToggleSetting[/Keyboard/leftCtrl,/Keyboard/g]'
- m_PersistentCalls:
m_Calls:
- m_Target: {fileID: 2128442884}
m_TargetAssemblyTypeName: OnlyScove.Scripts.InputReader, Assembly-CSharp
m_MethodName: OnCancel
m_Mode: 0
m_Arguments:
m_ObjectArgument: {fileID: 0}
m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine
m_IntArgument: 0
m_FloatArgument: 0
m_StringArgument:
m_BoolArgument: 0
m_CallState: 1
m_ActionId: 79227a8d-6fd2-496d-8466-68f007a2c355
m_ActionName: 'UI/Escape[/Keyboard/escape]'
m_NeverAutoSwitchControlSchemes: 0
m_DefaultControlScheme:
m_DefaultActionMap: UI
m_SplitScreenIndex: -1
m_Camera: {fileID: 1848374380}
--- !u!1660057539 &9223372036854775807
SceneRoots:
m_ObjectHideFlags: 0
m_Roots:
- {fileID: 1848374381}
- {fileID: 626355270}
- {fileID: 1183887570}
- {fileID: 2128442885}
- {fileID: 458228301}

View File

@@ -1,3 +1,4 @@
#if false
using System.Collections.Generic;
using Fusion;
using TMPro;
@@ -97,3 +98,4 @@
await spawner.StartHost(roomName, SceneRef.FromIndex(1));
}
}
#endif

View File

@@ -1,6 +1,12 @@
using Fusion;
using UnityEngine;
public partial struct _PlayerInputData : INetworkInput
namespace OnlyScove.Scripts
{
public float direction;
public struct PlayerInputData : INetworkInput
{
public Vector2 Direction;
public NetworkBool sprint;
public Quaternion rot;
}
}

View File

@@ -5,98 +5,82 @@ using System.Threading.Tasks;
using Fusion;
using Fusion.Sockets;
using UnityEngine;
using OnlyScove.Scripts;
// ghi nhận các input của người chơi, ở đây chỉ có hướng di chuyển
namespace Hallucinate.UI
{
public class _BasicSpawner : MonoBehaviour, INetworkRunnerCallbacks
{
private NetworkRunner _runner { get; set; }
public _LobbyManager LobbyManager;
public event Action<List<SessionInfo>> OnSessionListUpdatedEvent;
public event Action<string> OnShutdownEvent;
public event Action OnJoinStartedEvent;
public event Action OnJoinFailedEvent;
private void Awake()
{
// dont destroy this object when loading new scenes
if (_runner == null) _runner = gameObject.AddComponent<NetworkRunner>();
DontDestroyOnLoad(gameObject);
}
// thông tin profile của player local, sẽ được tạo ra từ lobby và gửi lên host để tạo player object, ở đây tạm thời chỉ tạo 1 profile mặc định
public _PlayerProfile LocalPlayerProfile { get; private set; }
public void SetLocalPlayerProfile(_PlayerProfile _profile)
{
LocalPlayerProfile = _profile;
}
// start lobby
public async Task StartLobby()
{
if (_runner == null) _runner = gameObject.AddComponent<NetworkRunner>();
_runner.ProvideInput = true;
_runner.AddCallbacks(this);
var result = await _runner.JoinSessionLobby(SessionLobby.ClientServer);
if (result.Ok)
{
Debug.Log("Joined lobby successfully!");
}
else
{
Debug.LogError($"Failed to join lobby: {result.ShutdownReason}");
}
if (!result.Ok) Debug.LogError($"Failed to join lobby: {result.ShutdownReason}");
}
// tạo phòng
public async Task StartHost(string sessionName, SceneRef scene)
public async Task StartHost(string sessionName, string password = null)
{
OnJoinStartedEvent?.Invoke();
var customProps = new Dictionary<string, SessionProperty>();
if (!string.IsNullOrEmpty(password))
{
customProps.Add("pw", password);
}
var result = await _runner.StartGame(new StartGameArgs()
{
GameMode = GameMode.Host,
SessionName = sessionName,
Scene = scene,
SessionProperties = customProps,
PlayerCount = 2,
SceneManager = gameObject.AddComponent<NetworkSceneManagerDefault>()
});
if (result.Ok)
{
Debug.Log("Started host successfully!");
}
else
if (!result.Ok)
{
Debug.LogError($"Failed to start host: {result.ShutdownReason}");
OnJoinFailedEvent?.Invoke();
}
}
// tham gia phòng
public async Task StartClient(string sessionName)
public async Task StartClient(string sessionName, string password = null)
{
OnJoinStartedEvent?.Invoke();
var result = await _runner.StartGame(new StartGameArgs()
{
GameMode = GameMode.Client,
SessionName = sessionName,
SceneManager = gameObject.AddComponent<NetworkSceneManagerDefault>()
});
if (result.Ok) {
Debug.Log("Started client successfully!");
}
else {
Debug.LogError($"Failed to start client: {result.ShutdownReason}");
}
}
public void OnObjectExitAOI(NetworkRunner runner, NetworkObject obj, PlayerRef player)
if (!result.Ok)
{
Debug.LogError($"Failed to join client: {result.ShutdownReason}");
OnJoinFailedEvent?.Invoke();
}
public void OnObjectEnterAOI(NetworkRunner runner, NetworkObject obj, PlayerRef player)
{
}
[SerializeField] private NetworkPrefabRef _playerPrefab;
@@ -104,54 +88,28 @@ public class _BasicSpawner : MonoBehaviour, INetworkRunnerCallbacks
public void OnPlayerJoined(NetworkRunner runner, PlayerRef player)
{
// nếu là host
if (runner.IsServer)
{
Vector2 spawnPosition;
if (player == runner.LocalPlayer)
{
spawnPosition = new Vector2(-8, 0);
}
else
{
spawnPosition = new Vector2(8, 0);
}
// Create a unique position for the player
// var spawnPosition = new Vector2(Random.Range(0, 5), Random.Range(0, 5));
var networkPlayerObject = runner.Spawn(
_playerPrefab,
spawnPosition,
Quaternion.identity,
player);
// Keep track of the player avatars for easy access
_spawnedCharacters.Add(player, networkPlayerObject);
// if (runner.ActivePlayers.Count() == 2 && !_ballStarted)
// {
// var ball = FindFirstObjectByType<Ball>();
// ball.Launch();
// _ballStarted = true;
// }
}
Debug.Log("Player joined: " + player + ", is local player: " + (player == runner.LocalPlayer));
if (player == runner.LocalPlayer)
{
var pdm = FindFirstObjectByType<_PlayerDataManager>();
if (pdm == null) return;
if (pdm != null)
{
var metaData = new _PlayerMetaData()
{
Name = LocalPlayerProfile.Name,
Role = LocalPlayerProfile.Role,
IsReady = false
};
pdm.RPC_UpdatePlayerMetaData(player, metaData);
}
}
}
public void StartGame()
{
if (_runner.IsServer)
{
_runner.LoadScene("Main Scene");
}
}
public void OnPlayerLeft(NetworkRunner runner, PlayerRef player)
@@ -160,142 +118,83 @@ public class _BasicSpawner : MonoBehaviour, INetworkRunnerCallbacks
{
runner.Despawn(networkObject);
_spawnedCharacters.Remove(player);
if (runner.IsServer)
{
runner.Shutdown();
if (runner.IsServer) runner.Shutdown();
}
}
}
private bool IsGameReady(NetworkRunner runner)
{
return runner.ActivePlayers.Count() >= 2;
}
public void OnShutdown(NetworkRunner runner, ShutdownReason shutdownReason)
{
Debug.Log("Game shutdown: " + shutdownReason);
UnityEngine.SceneManagement.SceneManager.LoadScene("Lobby");
OnShutdownEvent?.Invoke(shutdownReason.ToString());
}
public void OnDisconnectedFromServer(NetworkRunner runner, NetDisconnectReason reason)
public void OnSessionListUpdated(NetworkRunner runner, List<SessionInfo> sessionList)
{
OnSessionListUpdatedEvent?.Invoke(sessionList);
}
public void OnConnectRequest(NetworkRunner runner, NetworkRunnerCallbackArgs.ConnectRequest request, byte[] token)
{
}
public void OnConnectFailed(NetworkRunner runner, NetAddress remoteAddress, NetConnectFailedReason reason)
{
}
public void OnUserSimulationMessage(NetworkRunner runner, SimulationMessagePtr message)
{
}
public void OnReliableDataReceived(NetworkRunner runner, PlayerRef player, ReliableKey key, ArraySegment<byte> data)
{
}
public void OnReliableDataProgress(NetworkRunner runner, PlayerRef player, ReliableKey key, float progress)
{
}
public void OnInput(NetworkRunner runner, NetworkInput input)
{
// collect the input and send it to the runner, which will then be sent to the server and other clients
var data = new _PlayerInputData();
data.direction = Input.GetAxis("Vertical");
var data = new PlayerInputData();
// Try to get input from the local player's InputReader
if (PlayerStateMachine.Local != null && PlayerStateMachine.Local.Input != null)
{
var inputReader = PlayerStateMachine.Local.Input;
data.Direction = inputReader.MoveInput;
data.sprint = inputReader.IsSprintHeld;
if (PlayerStateMachine.Local.Cam != null)
{
data.rot = PlayerStateMachine.Local.Cam.PlanarRotation;
}
}
else
{
// Fallback to basic input if player not spawned or InputReader missing
data.Direction = new Vector2(Input.GetAxis("Horizontal"), Input.GetAxis("Vertical"));
data.sprint = Input.GetKey(KeyCode.LeftShift);
}
input.Set(data);
}
public void OnInputMissing(NetworkRunner runner, PlayerRef player, NetworkInput input)
{
}
public void OnConnectedToServer(NetworkRunner runner)
{
}
// khi có update về danh sách phòng,
// ví dụ khi có phòng mới được tạo hoặc phòng bị xóa,
// host sẽ gửi update này cho tất cả client trong lobby
public void OnSessionListUpdated(NetworkRunner runner, List<SessionInfo> sessionList)
{
Debug.Log("Session list updated, total sessions: " + sessionList.Count);
LobbyManager.DisplayRoomList(sessionList);
}
public void OnCustomAuthenticationResponse(NetworkRunner runner, Dictionary<string, object> data)
{
}
public void OnHostMigration(NetworkRunner runner, HostMigrationToken hostMigrationToken)
{
}
public void OnConnectedToServer(NetworkRunner runner) { }
public void OnDisconnectedFromServer(NetworkRunner runner, NetDisconnectReason reason) { }
public void OnConnectRequest(NetworkRunner runner, NetworkRunnerCallbackArgs.ConnectRequest request, byte[] token) { }
public void OnConnectFailed(NetworkRunner runner, NetAddress remoteAddress, NetConnectFailedReason reason) { }
public void OnUserSimulationMessage(NetworkRunner runner, SimulationMessagePtr message) { }
public void OnReliableDataReceived(NetworkRunner runner, PlayerRef player, ReliableKey key, ArraySegment<byte> data) { }
public void OnReliableDataProgress(NetworkRunner runner, PlayerRef player, ReliableKey key, float progress) { }
public void OnInputMissing(NetworkRunner runner, PlayerRef player, NetworkInput input) { }
public void OnObjectExitAOI(NetworkRunner runner, NetworkObject obj, PlayerRef player) { }
public void OnObjectEnterAOI(NetworkRunner runner, NetworkObject obj, PlayerRef player) { }
public void OnCustomAuthenticationResponse(NetworkRunner runner, Dictionary<string, object> data) { }
public void OnHostMigration(NetworkRunner runner, HostMigrationToken hostMigrationToken) { }
public void OnSceneLoadDone(NetworkRunner runner)
{
string currentSceneName = UnityEngine.SceneManagement.SceneManager.GetActiveScene().name;
}
public void OnSceneLoadStart(NetworkRunner runner)
if (runner.IsServer && currentSceneName == "Main Scene")
{
}
public void DespawnGO(NetworkObject networkObject)
foreach (var player in runner.ActivePlayers)
{
if (_runner != null && networkObject != null)
Vector2 spawnPosition = (player == runner.LocalPlayer) ? new Vector2(-8, 0) : new Vector2(8, 0);
var networkPlayerObject = runner.Spawn(_playerPrefab, spawnPosition, Quaternion.identity, player);
_spawnedCharacters.Add(player, networkPlayerObject);
}
}
if (currentSceneName == "Main Scene")
{
_runner.Despawn(networkObject);
if (UIManager.Instance != null) UIManager.Instance.OnGameStarted();
}
}
public NetworkObject SpawnGO(NetworkPrefabRef prefabRef, Vector2 position,Quaternion rotation, PlayerRef owner = default)
else if (currentSceneName == "Lobby" || currentSceneName == "Menu")
{
if (_runner != null)
{
return _runner.Spawn(prefabRef, position, rotation, owner);
}
return null;
}
void AssignRoles(NetworkRunner runner)
{
var players = runner.ActivePlayers.ToList();
if (players.Count < 2) return;
var p1 = players[0];
var p2 = players[1];
bool random = UnityEngine.Random.value > 0.5f;
SetRole(runner, p1, random ? _Role.Seeker : _Role.Trapper);
SetRole(runner, p2, random ? _Role.Trapper : _Role.Seeker);
}
void SetRole(NetworkRunner runner, PlayerRef player, _Role role)
{
var obj = runner.GetPlayerObject(player);
var data = obj.GetComponent<_PlayerData>();
data.PlayerRole = role;
Debug.Log($"Player {player} assigned role: {role}");
if (UIManager.Instance != null) UIManager.Instance.OnBackToMenu();
}
}
public void OnSceneLoadStart(NetworkRunner runner) { }
}
}

View File

@@ -6,24 +6,30 @@ public struct _PlayerMetaData : INetworkStruct
{
public NetworkString<_16> Name;
public _Role Role;
public NetworkBool IsReady;
}
public class _PlayerDataManager : NetworkBehaviour
{
// biến này của Fusion sẽ tự động đồng bộ giữa các client và host,
// khi có thay đổi sẽ tự động cập nhật ở tất cả các bên
[Networked]
public NetworkDictionary<PlayerRef, _PlayerMetaData> Players => default;
// RPC: phương thức này sẽ được gọi từ client hoặc
// host để cập nhật thông tin player, sau đó sẽ được gửi
// đến state authority (host) để xử lý và đồng bộ lại cho tất cả các client
[Rpc(RpcSources.All, RpcTargets.StateAuthority)]
public void RPC_UpdatePlayerMetaData(PlayerRef playerRef, _PlayerMetaData metaData)
{
Players.Set(playerRef, metaData);
}
[Rpc(RpcSources.All, RpcTargets.StateAuthority)]
public void RPC_SetReady(PlayerRef playerRef, bool ready)
{
if (Players.TryGet(playerRef, out var data))
{
data.IsReady = ready;
Players.Set(playerRef, data);
}
}
public bool TryGetPlayerMetaData(PlayerRef playerRef, out _PlayerMetaData metaData)
{
return Players.TryGet(playerRef, out metaData);

View File

@@ -0,0 +1,97 @@
Elo Rating System
AI Handoff Specification — Hallucinate Game
1. B?i c?nh & M?c tiêu
Game Hallucinate là game PvP online 1v1 (real-time), dùng Photon Fusion / Unity Relay làm backend m?ng. H? th?ng Elo ???c yêu c?u ?? x?p h?ng ng??i ch?i sau m?i tr?n solo, hi?n th? trên màn hình Profile và ?i?u ph?i matchmaking.
Yêu c?u c?t lõi:
• Tính toán Elo sau m?i tr?n 1v1 hoàn thành
• K-factor ??ng theo s? tr?n và rating hi?n t?i
• Persist rating lên server (không ?? client t? tính)
• Tr? v? rating m?i cho c? 2 ng??i ch?i sau tr?n
• Hi?n th? lên ProfileController.cs qua data binding
2. Công th?c Elo
2.1. Expected Score
E(A) = 1 / (1 + 10 ^ ((RatingB - RatingA) / 400))
E(B) = 1 - E(A)
2.2. Rating m?i
NewRating(A) = OldRating(A) + K * (Result - E(A))
Trong ?ó Result: Th?ng = 1.0 | Thua = 0.0 | Hòa = 0.5
2.3. K-Factor ??ng
?i?u ki?n
K Value
Lý do
D??i 30 tr?n (Placement)
40
Rating ch?a ?n ??nh, c?n h?i t? nhanh
Rating < 1200
32
Tier th?p — thay ??i nhi?u h?n
1200 ? Rating < 2000
24
Tier trung bình — cân b?ng
Rating ? 2000
16
Tier cao — ?n ??nh, thay ??i ch?m
2.4. Ví d? tính toán
A (1500) vs B (1200), A th?ng:
E(A) = 1 / (1 + 10^((1200-1500)/400)) = 0.849
E(B) = 0.151
NewRating(A) = 1500 + 24*(1 - 0.849) = 1500 + 3.6 ? 1504
NewRating(B) = 1200 + 32*(0 - 0.151) = 1200 - 4.8 ? 1195
3. Rank Tiers
Rank
Rating Range
Màu g?i ý (UI)
Iron
< 800
#8A8A8A
Bronze
800 999
#CD7F32
Silver
1000 1199
#C0C0C0
Gold
1200 1499
#FFD700
Platinum
1500 1799
#4DC8A0
Diamond
1800 2099
#7B6EE8
Master
? 2100
#E84D8A
Rating kh?i ??u (m?c ??nh): 1000. Rating sàn (floor): 100 — không xu?ng d??i giá tr? này.
4. Placement Matches
• 30 tr?n ??u tiên là Placement Period (gamesPlayed < 30)
• K = 40 trong giai ?o?n này ?? rating h?i t? nhanh v? ?úng v? trí
• Tùy ch?n: không hi?n th? rank badge trong 30 tr?n ??u, ch? hi?n th? '?' ho?c 'Unranked'
• Sau tr?n 30, K-factor chuy?n sang b?ng ??ng ? m?c 2.3
5. Ki?n trúc & Lu?ng d? li?u
5.1. Nguyên t?c quan tr?ng
KHÔNG ?? client t? tính Elo r?i g?i lên. Ph?i tính trên Host/Server ?? tránh cheat.
5.2. Lu?ng x? lý
B??c
Th?c hi?n b?i
Mô t?
1
Client A & B
Tr?n k?t thúc, g?i k?t qu? lên Host qua RPC
2
Host (Photon Fusion)
Nh?n k?t qu?, xác minh h?p l?
3
Host
G?i EloSystem.Calculate() v?i rating c?a 2 ng??i

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 773d26e688e03024298a2a369cdcd1fe
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,186 +0,0 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Linq;
using Fusion;
using Fusion.Sockets;
using UnityEngine;
using UnityEngine.SceneManagement;
using Random = UnityEngine.Random;
// Struct input đồng bộ giữa Spawner, Movement và StateMachine
public struct PlayerInputData : INetworkInput
{
public Vector2 Direction;
public Quaternion rot;
public bool sprint;
}
public class BasicSpawner : MonoBehaviour, INetworkRunnerCallbacks
{
private NetworkRunner _runner;
private string _roomName = "Room1";
public LobbyManager LobbyManager;
[SerializeField] private NetworkPrefabRef _playerPrefab;
private Dictionary<PlayerRef, NetworkObject> _spawnedCharacters = new Dictionary<PlayerRef, NetworkObject>();
// Thông tin profile local
public PlayerProfile LocalPlayerProfile { get; private set; }
public void SetLocalPlayerProfile(PlayerProfile profile)
{
LocalPlayerProfile = profile;
}
private void Awake()
{
if (_runner == null) _runner = gameObject.AddComponent<NetworkRunner>();
DontDestroyOnLoad(gameObject);
}
// Khởi tạo Game (Host/Client)
public async Task StartGame(GameMode mode, string sessionName = "TestRoom")
{
Debug.Log($"<color=yellow>Fusion:</color> Đang khởi tạo kết nối với Mode: {mode} | Phòng: {sessionName}");
if (_runner == null) _runner = gameObject.AddComponent<NetworkRunner>();
_runner.ProvideInput = true;
var sceneManager = gameObject.GetComponent<NetworkSceneManagerDefault>();
if (sceneManager == null) sceneManager = gameObject.AddComponent<NetworkSceneManagerDefault>();
var result = await _runner.StartGame(new StartGameArgs()
{
GameMode = mode,
SessionName = sessionName,
Scene = SceneRef.FromIndex(1),
SceneManager = sceneManager
});
if (result.Ok)
{
Debug.Log($"<color=green>Fusion thành công:</color> Đã vào phòng {sessionName}");
}
else
{
Debug.LogError($"<color=red>Fusion thất bại:</color> Lý do: {result.ShutdownReason}");
if (_runner != null)
{
Destroy(_runner);
_runner = null;
}
}
}
private void OnGUI()
{
if (_runner == null || !_runner.IsRunning)
{
float width = 400;
float height = 300;
float x = (Screen.width - width) / 2f;
float y = (Screen.height - height) / 2f;
GUI.Box(new Rect(x, y, width, height), "FUSION MULTIPLAYER");
float innerX = x + 20;
float innerY = y + 40;
float contentWidth = width - 40;
GUI.Label(new Rect(innerX, innerY, 100, 30), "Tên phòng:");
_roomName = GUI.TextField(new Rect(innerX + 100, innerY, contentWidth - 100, 30), _roomName);
if (GUI.Button(new Rect(innerX, innerY + 50, contentWidth, 60), "VÀO PHÒNG\n(Tự động Host/Client)"))
{
_ = StartGame(GameMode.AutoHostOrClient, _roomName);
}
if (GUI.Button(new Rect(innerX, innerY + 120, (contentWidth / 2) - 5, 50), "Tạo phòng\n(Host)"))
{
_ = StartGame(GameMode.Host, _roomName);
}
if (GUI.Button(new Rect(innerX + (contentWidth / 2) + 5, innerY + 120, (contentWidth / 2) - 5, 50), "Tham gia\n(Client)"))
{
_ = StartGame(GameMode.Client, _roomName);
}
GUI.Label(new Rect(innerX, innerY + 180, contentWidth, 50), "Gợi ý: Nhập cùng tên phòng để chơi chung.\nNếu phòng chưa có, máy sẽ tự tạo mới.");
}
else
{
string region = (_runner.SessionInfo != null && _runner.SessionInfo.IsValid) ? _runner.SessionInfo.Region : "Connecting...";
int playerCount = 0;
foreach (var p in _runner.ActivePlayers) playerCount++;
string info = $"Mode: {_runner.GameMode} | Region: {region} | Players: {playerCount}";
GUI.Box(new Rect(10, 10, 400, 30), info);
if (GUI.Button(new Rect(10, 50, 100, 30), "Thoát"))
{
_runner.Shutdown();
}
}
}
public void OnPlayerJoined(NetworkRunner runner, PlayerRef player)
{
if (runner.IsServer)
{
Vector3 spawnPosition = new Vector3(Random.Range(-10f, 10f), 2f, Random.Range(-10f, 10f));
spawnPosition += new Vector3(player.RawEncoded % 3, 0, player.RawEncoded % 3);
var networkPlayerObject = runner.Spawn(_playerPrefab, spawnPosition, Quaternion.identity, player);
runner.SetPlayerObject(player, networkPlayerObject);
_spawnedCharacters.Add(player, networkPlayerObject);
}
}
public void OnPlayerLeft(NetworkRunner runner, PlayerRef player)
{
if (_spawnedCharacters.TryGetValue(player, out NetworkObject networkObject))
{
if (networkObject != null) runner.Despawn(networkObject);
_spawnedCharacters.Remove(player);
}
}
public void OnInput(NetworkRunner runner, NetworkInput input)
{
var data = new PlayerInputData();
// ĐỌC TRỰC TIẾP: Không dùng Buffer để tránh bị trôi phím
data.Direction = new Vector2(Input.GetAxisRaw("Horizontal"), Input.GetAxisRaw("Vertical"));
data.sprint = Input.GetKey(KeyCode.LeftShift);
if (OnlyScove.Scripts.PlayerStateMachine.Local != null)
{
var sm = OnlyScove.Scripts.PlayerStateMachine.Local;
if (sm.Cam != null) data.rot = sm.Cam.PlanarRotation;
else data.rot = sm.NetworkedCameraRotation;
}
input.Set(data);
}
public void OnSessionListUpdated(NetworkRunner runner, List<SessionInfo> sessionList)
{
if (LobbyManager != null) LobbyManager.DisplayRoomList(sessionList);
}
public void OnInputMissing(NetworkRunner runner, PlayerRef player, NetworkInput input) { }
public void OnShutdown(NetworkRunner runner, ShutdownReason shutdownReason) { }
public void OnConnectedToServer(NetworkRunner runner) { }
public void OnDisconnectedFromServer(NetworkRunner runner, NetDisconnectReason reason) { }
public void OnConnectRequest(NetworkRunner runner, NetworkRunnerCallbackArgs.ConnectRequest request, byte[] token) { }
public void OnConnectFailed(NetworkRunner runner, NetAddress remoteAddress, NetConnectFailedReason reason) { }
public void OnUserSimulationMessage(NetworkRunner runner, SimulationMessagePtr message) { }
public void OnCustomAuthenticationResponse(NetworkRunner runner, Dictionary<string, object> data) { }
public void OnHostMigration(NetworkRunner runner, HostMigrationToken hostMigrationToken) { }
public void OnSceneLoadDone(NetworkRunner runner) { }
public void OnSceneLoadStart(NetworkRunner runner) { }
public void OnObjectExitAOI(NetworkRunner runner, NetworkObject obj, PlayerRef player) { }
public void OnObjectEnterAOI(NetworkRunner runner, NetworkObject obj, PlayerRef player) { }
public void OnReliableDataReceived(NetworkRunner runner, PlayerRef player, ReliableKey key, ArraySegment<byte> data) { }
public void OnReliableDataProgress(NetworkRunner runner, PlayerRef player, ReliableKey key, float progress) { }
}

View File

@@ -1,2 +0,0 @@
fileFormatVersion: 2
guid: 44bfaa339c82069418e72a14479a0212

View File

@@ -1 +0,0 @@
// File này hiện tại không còn nội dung, có thể xóa đi hoặc để trống.

View File

@@ -1,2 +0,0 @@
fileFormatVersion: 2
guid: 2bf2c7f159565794b87d6f3ca2eb2976

View File

@@ -1,28 +0,0 @@
using System.Collections.Generic;
using Fusion;
using UnityEngine;
public class LobbyManager : MonoBehaviour
{
[Header("UI References")]
public Transform roomListContent; // Ô chứa danh sách phòng (nếu có)
public void DisplayRoomList(List<SessionInfo> sessionList)
{
Debug.Log($"<color=green>Lobby Update:</color> Đang tìm thấy {sessionList.Count} phòng.");
// Xóa danh sách cũ (nếu bạn làm UI)
/*
foreach (Transform child in roomListContent) {
Destroy(child.gameObject);
}
*/
// Hiển thị danh sách mới
foreach (var session in sessionList)
{
Debug.Log($"- Phòng: {session.Name} | Người chơi: {session.PlayerCount}/{session.MaxPlayers}");
// Ở đây bạn sẽ Instantiate các Button đại diện cho mỗi phòng
}
}
}

View File

@@ -1,2 +0,0 @@
fileFormatVersion: 2
guid: b5aeb4670d7bf41499d3aaf409820260

View File

@@ -1,17 +0,0 @@
using UnityEngine;
// Enum các loại nhân vật
public enum CharacterClass
{
Warrior,
Mage,
Archer
}
// Lớp quản lý thông tin nhân vật local
[System.Serializable]
public class PlayerProfile
{
public string Name = "Player";
public CharacterClass Class = CharacterClass.Warrior;
}

View File

@@ -1,2 +0,0 @@
fileFormatVersion: 2
guid: 8a1452ae101af8e43b94c2c778a70fe0

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 2ff5c1c7397ba8e4090cd780091147e5
guid: 1a38893b1d8574b45bce269c39824bd6
folderAsset: yes
DefaultImporter:
externalObjects: {}

View File

@@ -0,0 +1,64 @@
using UnityEngine;
using Fusion;
namespace Hallucinate.Game
{
public static class EloSystem
{
public static EloResult Calculate(
int ratingA, int ratingB,
int gamesPlayedA, int gamesPlayedB,
float resultA) // 1=win, 0=lose, 0.5=draw
{
float eA = 1f / (1f + Mathf.Pow(10f, (ratingB - ratingA) / 400f));
int kA = GetK(ratingA, gamesPlayedA);
int kB = GetK(ratingB, gamesPlayedB);
int nA = Mathf.Max(100, Mathf.RoundToInt(ratingA + kA * (resultA - eA)));
int nB = Mathf.Max(100, Mathf.RoundToInt(ratingB + kB * ((1 - resultA) - (1 - eA))));
return new EloResult(nA, nB, nA - ratingA, nB - ratingB);
}
private static int GetK(int r, int g) =>
g < 30 ? 40 : r < 1200 ? 32 : r < 2000 ? 24 : 16;
public static string GetRank(int rating)
{
if (rating < 800) return "Iron";
if (rating < 1000) return "Bronze";
if (rating < 1200) return "Silver";
if (rating < 1500) return "Gold";
if (rating < 1800) return "Platinum";
if (rating < 2100) return "Diamond";
return "Master";
}
public static string GetRankColor(int rating)
{
if (rating < 800) return "#8A8A8A";
if (rating < 1000) return "#CD7F32";
if (rating < 1200) return "#C0C0C0";
if (rating < 1500) return "#FFD700";
if (rating < 1800) return "#4DC8A0";
if (rating < 2100) return "#7B6EE8";
return "#E84D8A";
}
}
public struct EloResult : INetworkStruct
{
public int NewRatingA;
public int NewRatingB;
public int DeltaA;
public int DeltaB;
public EloResult(int nA, int nB, int dA, int dB)
{
NewRatingA = nA;
NewRatingB = nB;
DeltaA = dA;
DeltaB = dB;
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 366843378ad652a41aeb5972186ebe18

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 6aa851b2c7ee553439ee0065f77665cb
guid: f96029db35b52ba4182888a7f14d2ea7
folderAsset: yes
DefaultImporter:
externalObjects: {}

View File

@@ -0,0 +1,77 @@
using Fusion;
using UnityEngine;
using Hallucinate.Game;
using Hallucinate.UI;
using System.Linq;
namespace Hallucinate.Network
{
public class MatchResultManager : NetworkBehaviour
{
public static MatchResultManager Instance { get; private set; }
public override void Spawned()
{
if (Object.HasStateAuthority) Instance = this;
}
[Rpc(RpcSources.StateAuthority, RpcTargets.All)]
public void RPC_BroadcastResult(PlayerRef winner, EloResult eloResult)
{
Debug.Log($"Game Over! Winner: {winner}. Elo updated.");
// Update local Elo display and show Result UI
if (Runner.LocalPlayer == winner)
{
ShowResultUI(true, eloResult.DeltaA, eloResult.NewRatingA);
}
else
{
ShowResultUI(false, eloResult.DeltaB, eloResult.NewRatingB);
}
}
private void ShowResultUI(bool isWin, int delta, int newRating)
{
var hud = FindFirstObjectByType<HUDController>();
if (hud != null)
{
// In a real scenario, we might push a new Result screen
// For now, let's assume HUD has a result panel
Debug.Log($"RESULT: {(isWin ? "WIN" : "LOSS")} | Delta: {delta} | New Rating: {newRating}");
// Save to PlayerPrefs as a dummy "Server" persistence
PlayerPrefs.SetInt("EloRating", newRating);
int gamesPlayed = PlayerPrefs.GetInt("GamesPlayed", 0);
PlayerPrefs.SetInt("GamesPlayed", gamesPlayed + 1);
PlayerPrefs.Save();
}
}
public void ProcessMatchEnd(PlayerRef winner)
{
if (!Object.HasStateAuthority) return;
// Get ratings for both players
// In a real game, these would come from the server/metadata
int ratingA = PlayerPrefs.GetInt("EloRating", 1000);
int ratingB = 1000; // Placeholder for opponent
int gamesA = PlayerPrefs.GetInt("GamesPlayed", 0);
int gamesB = 0; // Placeholder
float resultA = (Runner.LocalPlayer == winner) ? 1.0f : 0.0f;
EloResult elo = EloSystem.Calculate(ratingA, ratingB, gamesA, gamesB, resultA);
RPC_BroadcastResult(winner, elo);
// Shut down runner after some delay
Invoke(nameof(ShutdownRunner), 5.0f);
}
private void ShutdownRunner()
{
Runner.Shutdown();
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 9eac0255d30a2bb40a43ff12cdcdf960

View File

@@ -6,14 +6,16 @@ namespace OnlyScove.Scripts
{
public class InputReader : MonoBehaviour
{
[SerializeField] private InputActionAsset inputActions;
public InputActionAsset InputActions => inputActions;
// Continuous Inputs
public virtual Vector2 MoveInput { get; protected set; }
public virtual Vector2 LookInput { get; protected set; }
public virtual Vector2 ScrollInput { get; protected set; }
public virtual bool IsSprintHeld { get; protected set; } // Left Shift
public virtual bool IsAttackHeld { get; protected set; } // Left Mouse Button
public virtual bool IsSprintHeld { get; protected set; }
public virtual bool IsAttackHeld { get; protected set; }
// THÊM HÀM NÀY ĐỂ ĐỒNG BỘ MẠNG
public void ApplyNetworkInput(Vector2 move, bool isSprint)
{
MoveInput = move;
@@ -21,15 +23,19 @@ namespace OnlyScove.Scripts
}
// One-shot Events
public event Action OnJumpEvent; // Space
public event Action OnDodgeEvent; // Right Mouse Button (RMB)
public event Action OnSprintEvent; // Left Shift
public event Action OnAttackEvent; // Left Mouse Button (LMB)
public event Action OnCrouchEvent; // C Key
public event Action OnInteractEvent; // E Key
public event Action OnNextInteractEvent; // R Key
public event Action OnPreviousInteractEvent; // Q Key
public event Action OnToggleViewEvent; // F2 - New event for toggling camera view
public event Action OnJumpEvent;
public event Action OnDodgeEvent;
public event Action OnSprintEvent;
public event Action OnAttackEvent;
public event Action OnCrouchEvent;
public event Action OnInteractEvent;
public event Action OnNextInteractEvent;
public event Action OnPreviousInteractEvent;
public event Action OnToggleViewEvent;
// UI Events
public event Action OnToggleSettingsEvent; // Cho Ctrl+O
public event Action OnCancelEvent; // Cho phím ESC hoặc phím đóng UI
public void OnAttack(InputAction.CallbackContext context)
{
@@ -69,13 +75,9 @@ namespace OnlyScove.Scripts
if (context.canceled) IsSprintHeld = false;
}
// New method for ToggleView input
public void OnToggleView(InputAction.CallbackContext context)
{
if (context.performed)
{
OnToggleViewEvent?.Invoke();
}
if (context.performed) OnToggleViewEvent?.Invoke();
}
public void OnJump(InputAction.CallbackContext context)
@@ -95,13 +97,7 @@ namespace OnlyScove.Scripts
public void OnInteract(InputAction.CallbackContext context)
{
Debug.Log($"[InputReader] Interaction State: {context.phase} | Started: {context.started} | Performed: {context.performed} | Canceled: {context.canceled}");
if (context.performed)
{
Debug.Log("[InputReader] Event OnInteractEvent triggered!");
OnInteractEvent?.Invoke();
}
if (context.performed) OnInteractEvent?.Invoke();
}
public void OnNext(InputAction.CallbackContext context)
@@ -113,5 +109,24 @@ namespace OnlyScove.Scripts
{
if (context.performed) OnPreviousInteractEvent?.Invoke();
}
// UI Callbacks
public void OnToggleSettings(InputAction.CallbackContext context)
{
if (context.performed)
{
Debug.Log("[InputReader] Toggle Settings Action Performed!");
OnToggleSettingsEvent?.Invoke();
}
}
public void OnCancel(InputAction.CallbackContext context)
{
if (context.performed)
{
Debug.Log("[InputReader] Cancel Action Performed (ESC)!");
OnCancelEvent?.Invoke();
}
}
}
}

View File

@@ -0,0 +1,54 @@
using UnityEngine;
using Fusion;
namespace OnlyScove.Scripts
{
public class PlayerAnimationHandler : NetworkBehaviour
{
[Header("Animator Settings")]
[SerializeField] private string speedParamName = "Speed";
[SerializeField] private string velocityXParamName = "Velocity X";
[SerializeField] private string velocityZParamName = "Velocity Z";
[SerializeField] private float animationDamping = 0.2f;
private Animator anim;
private int speedHash;
private int velocityXHash;
private int velocityZHash;
private bool hasSpeedParam;
private bool hasVelocityXParam;
private bool hasVelocityZParam;
public void Initialize(Animator animator)
{
this.anim = animator;
if (anim != null)
{
foreach (AnimatorControllerParameter param in anim.parameters)
{
if (param.name == speedParamName) hasSpeedParam = true;
if (param.name == velocityXParamName) hasVelocityXParam = true;
if (param.name == velocityZParamName) hasVelocityZParam = true;
}
}
speedHash = Animator.StringToHash(speedParamName);
velocityXHash = Animator.StringToHash(velocityXParamName);
velocityZHash = Animator.StringToHash(velocityZParamName);
}
public void UpdateAnimator(float speed, Vector2 moveInput, float deltaTime)
{
if (anim == null) return;
if (hasSpeedParam) anim.SetFloat(speedHash, speed, animationDamping, deltaTime);
if (hasVelocityXParam) anim.SetFloat(velocityXHash, moveInput.x * speed, animationDamping, deltaTime);
if (hasVelocityZParam) anim.SetFloat(velocityZHash, moveInput.y * speed, animationDamping, deltaTime);
}
public void SetSpeed(float speed)
{
if (anim != null && hasSpeedParam) anim.SetFloat(speedHash, speed);
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 965ec86f3b9695640bdc85e624d0e9e7

View File

@@ -0,0 +1,75 @@
using UnityEngine;
using Fusion;
using System.Collections.Generic;
using System;
namespace OnlyScove.Scripts
{
public class PlayerInteraction : NetworkBehaviour
{
[Header("Interaction Settings")]
[SerializeField] public float InteractionRange = 2f;
[SerializeField] public LayerMask InteractionMask;
public event Action<IInteractable> OnInteractableTargetChanged;
private List<IInteractable> interactablesNearby = new List<IInteractable>();
private int currentInteractableIndex = 0;
private EnvironmentScanner scanner;
public void Initialize(EnvironmentScanner scanner)
{
this.scanner = scanner;
}
public void UpdateInteractables()
{
if (scanner == null) return;
interactablesNearby.Clear();
IInteractable target = scanner.ScanForInteractable(InteractionRange, InteractionMask);
if (target != null) interactablesNearby.Add(target);
OnInteractableTargetChanged?.Invoke(target);
if (Object != null && Object.HasInputAuthority)
{
// UI Placeholder: Interaction UI
// Example: UI.UIEventBus.TriggerInteractionPrompt(target?.InteractionPrompt);
// Example: UI.UIEventBus.TriggerInteractionVisibility(target != null);
}
currentInteractableIndex = 0;
}
public void NextInteract()
{
if (interactablesNearby.Count <= 1) return;
currentInteractableIndex = (currentInteractableIndex + 1) % interactablesNearby.Count;
NotifyTargetChanged();
}
public void PreviousInteract()
{
if (interactablesNearby.Count <= 1) return;
currentInteractableIndex = (currentInteractableIndex - 1 + interactablesNearby.Count) % interactablesNearby.Count;
NotifyTargetChanged();
}
private void NotifyTargetChanged()
{
IInteractable target = GetInteractable();
OnInteractableTargetChanged?.Invoke(target);
if (Object != null && Object.HasInputAuthority)
{
// UI Placeholder: Update Prompt
// Example: UI.UIEventBus.TriggerInteractionPrompt(target?.InteractionPrompt);
}
}
public IInteractable GetInteractable()
{
return (interactablesNearby == null || interactablesNearby.Count == 0) ? null : interactablesNearby[currentInteractableIndex];
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 9dcff2851697b4f4c8c25ef8381665ba

View File

@@ -0,0 +1,71 @@
using UnityEngine;
using Fusion;
namespace OnlyScove.Scripts
{
public class PlayerMovement : NetworkBehaviour
{
[field: Header("Movement Settings")]
[field: SerializeField] public float WalkSpeed { get; private set; } = 3f;
[field: SerializeField] public float RunSpeed { get; private set; } = 6f;
[field: SerializeField] public float SprintSpeed { get; private set; } = 9f;
[field: SerializeField] public float SneakSpeed { get; private set; } = 1.5f;
[field: SerializeField] public float DashForce { get; private set; } = 10f;
[field: SerializeField] public float RotationSpeed { get; private set; } = 500f;
[field: Header("Airborne Settings")]
[field: SerializeField] public float JumpHeight { get; private set; } = 2f;
[field: SerializeField] public float Gravity { get; private set; } = -15f;
[field: SerializeField] public float ThrustDownwardForce { get; private set; } = -20f;
[field: Header("Ground Check")]
[field: SerializeField] public float GroundCheckRadius { get; private set; } = 0.2f;
[field: SerializeField] public Vector3 GroundCheckOffset { get; private set; }
[field: SerializeField] public LayerMask GroundMask { get; private set; }
[Networked] public bool IsGrounded { get; set; }
[Networked] public bool WasGrounded { get; set; }
[Networked] public float VelocityY { get; set; }
[Networked] public Vector3 NetworkedPosition { get; set; }
private CharacterController controller;
public void Initialize(CharacterController controller)
{
this.controller = controller;
}
public void CheckGround(Transform playerTransform)
{
if (Object == null || (!Object.HasStateAuthority && !Object.HasInputAuthority)) return;
WasGrounded = IsGrounded;
IsGrounded = Physics.CheckSphere(playerTransform.TransformPoint(GroundCheckOffset), GroundCheckRadius, GroundMask);
}
public void Move(CharacterController controller, Vector3 velocity, float deltaTime)
{
if (controller != null && controller.enabled)
{
controller.Move(velocity * deltaTime);
if (Object != null && Object.HasStateAuthority)
{
NetworkedPosition = transform.position;
}
}
}
public void Rotate(Transform playerTransform, Vector3 moveDirection, float deltaTime)
{
if (moveDirection == Vector3.zero) return;
Quaternion targetRot = Quaternion.LookRotation(moveDirection);
playerTransform.rotation = Quaternion.RotateTowards(playerTransform.rotation, targetRot, RotationSpeed * deltaTime);
}
public void SetGroundCheck(float radius, Vector3 offset)
{
GroundCheckRadius = radius;
GroundCheckOffset = offset;
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 79bbcfd4d37b7834ebe0d61bb649714d

View File

@@ -5,6 +5,8 @@ using Fusion;
namespace OnlyScove.Scripts
{
[RequireComponent(typeof(CharacterController), typeof(InputReader), typeof(Animator))]
[RequireComponent(typeof(PlayerStats), typeof(PlayerInteraction), typeof(PlayerMovement))]
[RequireComponent(typeof(PlayerAnimationHandler))]
public class PlayerStateMachine : NetworkBehaviour
{
[field: Header("References")]
@@ -14,60 +16,37 @@ namespace OnlyScove.Scripts
[field: SerializeField] public EnvironmentScanner Scanner { get; private set; }
public CameraController Cam { get; private set; }
[field: Header("Animator Settings")]
[SerializeField] private string speedParamName = "Speed";
[SerializeField] private string velocityXParamName = "Velocity X";
[SerializeField] private string velocityZParamName = "Velocity Z";
private int speedHash;
private int velocityXHash;
private int velocityZHash;
[field: Header("Movement Settings")]
[field: SerializeField] public float WalkSpeed { get; private set; } = 3f;
[field: SerializeField] public float RunSpeed { get; private set; } = 6f;
[field: SerializeField] public float SprintSpeed { get; private set; } = 9f;
[field: SerializeField] public float SneakSpeed { get; private set; } = 1.5f;
[field: SerializeField] public float DashForce { get; private set; } = 10f;
[field: SerializeField] public float RotationSpeed { get; private set; } = 500f;
[field: SerializeField] public float AnimationDamping { get; private set; } = 0.2f;
[field: Header("Airborne Settings")]
[field: SerializeField] public float JumpHeight { get; private set; } = 2f;
[field: SerializeField] public float Gravity { get; private set; } = -15f;
[field: SerializeField] public float ThrustDownwardForce { get; private set; } = -20f;
[field: Header("Ground Check")]
[field: SerializeField] public float GroundCheckRadius { get; private set; } = 0.2f;
[field: SerializeField] public Vector3 GroundCheckOffset { get; private set; }
[field: SerializeField] public LayerMask GroundMask { get; private set; }
[field: Header("Interaction")]
[field: SerializeField] public float InteractionRange { get; private set; } = 2f;
[field: SerializeField] public LayerMask InteractionMask { get; private set; }
[Header("Modules")]
public PlayerStats Stats;
public PlayerInteraction Interaction;
public PlayerMovement Movement;
public PlayerAnimationHandler AnimationHandler;
[Networked] public Quaternion NetworkedCameraRotation { get; set; }
[Networked] public Vector2 NetworkedMoveInput { get; set; }
[Networked] public float NetworkedSpeed { get; set; }
[Networked] public Vector3 NetworkedPosition { get; set; }
[Header("Player Stats")]
[Networked, OnChangedRender(nameof(OnHealthChangedRender))] public float Health { get; set; } = 100f;
[Networked, OnChangedRender(nameof(OnStaminaChangedRender))] public float Stamina { get; set; } = 100f;
[Networked, OnChangedRender(nameof(OnNoiseLevelChangedRender))] public float NoiseLevel { get; set; } = 0f;
public event System.Action<float> OnHealthChanged;
public event System.Action<float> OnStaminaChanged;
public event System.Action<float> OnNoiseLevelChanged;
public event System.Action<IInteractable> OnInteractableTargetChanged;
// Pass-through properties for State Compatibility
public Vector2 MoveInput { get; private set; }
public bool IsSprintHeld { get; private set; }
public float VelocityY { get; set; }
public bool IsGrounded { get; private set; }
public bool WasGrounded { get; private set; }
public string CurrentStateName => currentState != null ? currentState.GetType().Name : "None";
public float VelocityY { get => Movement.VelocityY; set => Movement.VelocityY = value; }
public bool IsGrounded => Movement.IsGrounded;
public bool WasGrounded => Movement.WasGrounded;
public float WalkSpeed => Movement.WalkSpeed;
public float RunSpeed => Movement.RunSpeed;
public float SprintSpeed => Movement.SprintSpeed;
public float SneakSpeed => Movement.SneakSpeed;
public float DashForce => Movement.DashForce;
public float JumpHeight => Movement.JumpHeight;
public float ThrustDownwardForce => Movement.ThrustDownwardForce;
public float Gravity => Movement.Gravity;
public float InteractionRange => Interaction.InteractionRange;
public LayerMask InteractionMask => Interaction.InteractionMask;
public static PlayerStateMachine Local { get; private set; }
public string CurrentStateName => currentState != null ? currentState.GetType().Name : "None";
public Quaternion CameraRotation
{
@@ -80,11 +59,6 @@ namespace OnlyScove.Scripts
private PlayerBaseState currentState;
private bool hasControl = true;
private bool hasSpeedParam;
private bool hasVelocityXParam;
private bool hasVelocityZParam;
private List<IInteractable> interactablesNearby = new List<IInteractable>();
private int currentInteractableIndex = 0;
private float localAnimatorSpeed;
protected virtual void Awake()
@@ -94,19 +68,14 @@ namespace OnlyScove.Scripts
Anim = GetComponentInChildren<Animator>();
Scanner = GetComponent<EnvironmentScanner>();
if (Anim != null)
{
foreach (AnimatorControllerParameter param in Anim.parameters)
{
if (param.name == speedParamName) hasSpeedParam = true;
if (param.name == velocityXParamName) hasVelocityXParam = true;
if (param.name == velocityZParamName) hasVelocityZParam = true;
}
}
Stats = GetComponent<PlayerStats>();
Interaction = GetComponent<PlayerInteraction>();
Movement = GetComponent<PlayerMovement>();
AnimationHandler = GetComponent<PlayerAnimationHandler>();
speedHash = Animator.StringToHash(speedParamName);
velocityXHash = Animator.StringToHash(velocityXParamName);
velocityZHash = Animator.StringToHash(velocityZParamName);
AnimationHandler.Initialize(Anim);
Movement.Initialize(Controller);
Interaction.Initialize(Scanner);
}
private void Start()
@@ -123,10 +92,6 @@ namespace OnlyScove.Scripts
}
}
void OnHealthChangedRender() => OnHealthChanged?.Invoke(Health);
void OnStaminaChangedRender() => OnStaminaChanged?.Invoke(Stamina);
void OnNoiseLevelChangedRender() => OnNoiseLevelChanged?.Invoke(NoiseLevel);
private void InitializePlayer()
{
if (currentState == null) SwitchState(new PlayerIdleState(this));
@@ -142,17 +107,15 @@ namespace OnlyScove.Scripts
Cam.followTarget = transform;
Cam.inputReader = Input;
}
Input.OnNextInteractEvent += OnNextInteract;
Input.OnPreviousInteractEvent += OnPreviousInteract;
Input.OnNextInteractEvent += Interaction.NextInteract;
Input.OnPreviousInteractEvent += Interaction.PreviousInteract;
if (Controller != null) Controller.enabled = true;
}
}
public void Rotate(Vector3 moveDirection, float deltaTime)
{
if (moveDirection == Vector3.zero) return;
Quaternion targetRot = Quaternion.LookRotation(moveDirection);
transform.rotation = Quaternion.RotateTowards(transform.rotation, targetRot, RotationSpeed * deltaTime);
Movement.Rotate(transform, moveDirection, deltaTime);
}
public void Move(Vector3 velocity, float animatorSpeed, float deltaTime)
@@ -160,11 +123,7 @@ namespace OnlyScove.Scripts
bool canMove = (Runner == null || !Runner.IsRunning) || Object.HasInputAuthority || Runner.IsServer;
if (!canMove) return;
if (Controller != null && Controller.enabled)
{
Controller.Move(velocity * deltaTime);
if (Object != null && Runner != null && Runner.IsRunning) NetworkedPosition = transform.position;
}
Movement.Move(Controller, velocity, deltaTime);
localAnimatorSpeed = animatorSpeed;
if (Object != null && Object.HasStateAuthority)
@@ -177,13 +136,9 @@ namespace OnlyScove.Scripts
private void UpdateAnimator(float deltaTime)
{
if (Anim == null) return;
float speedValue = (Runner == null || !Runner.IsRunning || Object.HasInputAuthority) ? localAnimatorSpeed : NetworkedSpeed;
Vector2 inputVector = (Runner == null || !Runner.IsRunning || Object.HasInputAuthority) ? MoveInput : NetworkedMoveInput;
if (hasSpeedParam) Anim.SetFloat(speedHash, speedValue, AnimationDamping, deltaTime);
if (hasVelocityXParam) Anim.SetFloat(velocityXHash, inputVector.x * speedValue, AnimationDamping, deltaTime);
if (hasVelocityZParam) Anim.SetFloat(velocityZHash, inputVector.y * speedValue, AnimationDamping, deltaTime);
AnimationHandler.UpdateAnimator(speedValue, inputVector, deltaTime);
}
public override void FixedUpdateNetwork()
@@ -191,13 +146,6 @@ namespace OnlyScove.Scripts
bool isRunning = Runner != null && Runner.IsRunning;
if (Object == null && isRunning) return;
if (isRunning && NetworkedPosition != Vector3.zero && !Object.HasInputAuthority)
{
Controller.enabled = false;
transform.position = NetworkedPosition;
Controller.enabled = true;
}
if (GetInput(out PlayerInputData data))
{
MoveInput = data.Direction;
@@ -209,26 +157,34 @@ namespace OnlyScove.Scripts
MoveInput = new Vector2(UnityEngine.Input.GetAxisRaw("Horizontal"), UnityEngine.Input.GetAxisRaw("Vertical"));
IsSprintHeld = UnityEngine.Input.GetKey(KeyCode.LeftShift);
}
else
{
MoveInput = Vector2.zero;
IsSprintHeld = false;
}
if (!isRunning || Object.HasInputAuthority || Runner.IsServer)
{
if (hasControl)
{
WasGrounded = IsGrounded;
CheckGround();
UpdateInteractablesList();
Movement.CheckGround(transform);
Interaction.UpdateInteractables();
currentState?.Tick(isRunning ? Runner.DeltaTime : Time.fixedDeltaTime);
}
}
else
}
public override void Render()
{
bool isRunning = Runner != null && Runner.IsRunning;
if (isRunning && !Object.HasInputAuthority)
{
// Smooth interpolation for proxies
if (Movement.NetworkedPosition != Vector3.zero)
{
transform.position = Vector3.Lerp(transform.position, Movement.NetworkedPosition, Runner.DeltaTime * 15f);
}
UpdateAnimator(Runner.DeltaTime);
}
else if (!isRunning)
{
UpdateAnimator(Time.deltaTime);
}
}
private void Update()
@@ -236,34 +192,8 @@ namespace OnlyScove.Scripts
if (Runner == null || !Runner.IsRunning) FixedUpdateNetwork();
}
private void CheckGround() => IsGrounded = Physics.CheckSphere(transform.TransformPoint(GroundCheckOffset), GroundCheckRadius, GroundMask);
private void UpdateInteractablesList()
{
interactablesNearby.Clear();
IInteractable target = Scanner.ScanForInteractable(InteractionRange, InteractionMask);
if (target != null) interactablesNearby.Add(target);
OnInteractableTargetChanged?.Invoke(target);
currentInteractableIndex = 0;
}
private void OnNextInteract()
{
if (interactablesNearby.Count <= 1) return;
currentInteractableIndex = (currentInteractableIndex + 1) % interactablesNearby.Count;
OnInteractableTargetChanged?.Invoke(GetInteractable());
}
private void OnPreviousInteract()
{
if (interactablesNearby.Count <= 1) return;
currentInteractableIndex = (currentInteractableIndex - 1 + interactablesNearby.Count) % interactablesNearby.Count;
OnInteractableTargetChanged?.Invoke(GetInteractable());
}
public IInteractable GetInteractable() => interactablesNearby.Count == 0 ? null : interactablesNearby[currentInteractableIndex];
public void SetGroundCheck(float radius, Vector3 offset) { GroundCheckRadius = radius; GroundCheckOffset = offset; }
public IInteractable GetInteractable() => Interaction.GetInteractable();
public void SetGroundCheck(float radius, Vector3 offset) => Movement.SetGroundCheck(radius, offset);
public void SwitchState(PlayerBaseState newState)
{
@@ -276,13 +206,14 @@ namespace OnlyScove.Scripts
{
hasControl = control;
if (Controller != null) Controller.enabled = control;
if (!control && Anim != null) Anim.SetFloat(speedHash, 0f);
if (!control) AnimationHandler.SetSpeed(0f);
}
private void OnDrawGizmosSelected()
{
if (Movement == null) return;
Gizmos.color = new Color(0, 1, 0, 0.5f);
Gizmos.DrawSphere(transform.TransformPoint(GroundCheckOffset), GroundCheckRadius);
Gizmos.DrawSphere(transform.TransformPoint(Movement.GroundCheckOffset), Movement.GroundCheckRadius);
}
}
}

View File

@@ -0,0 +1,71 @@
using UnityEngine;
using Fusion;
using System;
using Hallucinate.Network;
namespace OnlyScove.Scripts
{
public class PlayerStats : NetworkBehaviour
{
[Header("Player Stats")]
[Networked, OnChangedRender(nameof(OnHealthChangedRender))] public float Health { get; set; } = 100f;
[Networked, OnChangedRender(nameof(OnStaminaChangedRender))] public float Stamina { get; set; } = 100f;
[Networked, OnChangedRender(nameof(OnNoiseLevelChangedRender))] public float NoiseLevel { get; set; } = 0f;
public event Action<float> OnHealthChanged;
public event Action<float> OnStaminaChanged;
public event Action<float> OnNoiseLevelChanged;
public override void Spawned()
{
// Initial UI sync placeholder
UpdateUI();
}
void OnHealthChangedRender()
{
OnHealthChanged?.Invoke(Health);
if (Health <= 0 && Object.HasStateAuthority)
{
// Find the other player as winner
foreach (var player in Runner.ActivePlayers)
{
if (player != Object.InputAuthority)
{
MatchResultManager.Instance?.ProcessMatchEnd(player);
break;
}
}
}
if (Object.HasInputAuthority)
{
// UI Placeholder: Trigger Health UI Change
}
}
void OnStaminaChangedRender()
{
OnStaminaChanged?.Invoke(Stamina);
if (Object.HasInputAuthority)
{
// UI Placeholder: Trigger Stamina UI Change
}
}
void OnNoiseLevelChangedRender()
{
OnNoiseLevelChanged?.Invoke(NoiseLevel);
}
private void UpdateUI()
{
if (Object.HasInputAuthority)
{
OnHealthChangedRender();
OnStaminaChangedRender();
}
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: a1494b79b59fcdf4d9f7956dde31bc42

View File

@@ -0,0 +1,72 @@
using UnityEngine;
using UnityEngine.UIElements;
using PrimeTween;
using System.Threading.Tasks;
namespace Hallucinate.UI
{
public abstract class BaseUIController : ScriptableObject
{
protected VisualElement root;
protected UIManager uiManager;
public VisualElement Root => root; // Thêm thuộc tính này
public virtual void Initialize(VisualElement uxmlRoot, UIManager manager)
{
root = uxmlRoot;
uiManager = manager;
// Đảm bảo ban đầu ẩn hết
Hide();
}
public virtual void Show()
{
if (root != null)
{
root.style.display = DisplayStyle.Flex;
root.style.opacity = 1;
}
}
public virtual void Hide()
{
if (root != null)
{
root.style.display = DisplayStyle.None;
}
}
protected string GetLoc(string key)
{
if (LocalizationManager.Instance != null)
return LocalizationManager.Instance.GetLocalizedString(key);
return key;
}
public virtual void Update() { }
public virtual async Task PlayTransitionIn()
{
if (root == null) return;
Show();
// Reset vị trí mặc định để tránh lỗi trôi màn hình
root.style.translate = new StyleTranslate(new Translate(Length.Percent(100), 0));
await Tween.Custom(100f, 0f, duration: 0.5f, ease: Ease.OutBack,
onValueChange: val => root.style.translate = new StyleTranslate(new Translate(Length.Percent(val), 0)));
}
public virtual async Task PlayTransitionOut()
{
if (root == null) return;
await Tween.Custom(0f, -100f, duration: 0.5f, ease: Ease.InBack,
onValueChange: val => root.style.translate = new StyleTranslate(new Translate(Length.Percent(val), 0)));
Hide();
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 872f8bfaee91588488a3393579135de9

View File

@@ -0,0 +1,10 @@
using UnityEngine;
namespace Hallucinate.UI
{
[CreateAssetMenu(fileName = "FirebaseConfig", menuName = "Configs/FirebaseConfig")]
public class FirebaseConfig : ScriptableObject
{
public string baseUrl;
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 0551a27408b84c040a2e009ae17debde

View File

@@ -0,0 +1,70 @@
using System;
using System.Collections;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.Networking;
namespace Hallucinate.UI
{
public static class FirebaseService
{
private static string _baseUrl;
private static string BASE_URL
{
get
{
if (string.IsNullOrEmpty(_baseUrl))
{
// Nó sẽ tìm file tên "FirebaseConfig" trong bất kỳ folder "Resources" nào
var config = Resources.Load<FirebaseConfig>("FirebaseConfig");
if (config != null)
{
if (string.IsNullOrEmpty(config.baseUrl))
{
Debug.LogError("<color=red>[FirebaseService]</color> Base URL trong file FirebaseConfig đang trống!");
return null;
}
_baseUrl = config.baseUrl.TrimEnd('/');
}
else
{
Debug.LogError("<color=red>[FirebaseService]</color> Không tìm thấy file 'FirebaseConfig' trong folder Resources! " +
"Hãy đảm bảo bạn đã tạo file tại: Assets/.../Resources/FirebaseConfig");
return null;
}
}
return _baseUrl + "/users";
}
}
public static async Task<bool> IsUsernameTaken(string username)
{
string url = $"{BASE_URL}/{username}.json";
using (UnityWebRequest request = UnityWebRequest.Get(url))
{
var operation = request.SendWebRequest();
while (!operation.isDone) await Task.Yield();
if (request.result != UnityWebRequest.Result.Success) return false;
// Nếu kết quả trả về không phải "null" nghĩa là user đã tồn tại
return request.downloadHandler.text != "null";
}
}
public static async Task<bool> RegisterUser(string username)
{
string url = $"{BASE_URL}/{username}.json";
string jsonData = "{\"created_at\": \"" + DateTime.Now.ToString() + "\"}";
using (UnityWebRequest request = UnityWebRequest.Put(url, jsonData))
{
var operation = request.SendWebRequest();
while (!operation.isDone) await Task.Yield();
return request.result == UnityWebRequest.Result.Success;
}
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: bf13e7d21e483574882c6b687a6ae19c

View File

@@ -0,0 +1,44 @@
using UnityEngine;
using Hallucinate.UI;
using System.Threading.Tasks;
namespace Hallucinate.UI
{
public class FirebaseTest : MonoBehaviour
{
[Header("Settings")]
[SerializeField] private string testUsername = "TuanPlayer_01";
async void Start()
{
Debug.Log("<color=cyan>--- Firebase Test Started ---</color>");
// Bước 1: Kiểm tra xem username đã tồn tại chưa
Debug.Log($"[Firebase] Đang kiểm tra username: {testUsername}...");
bool isTaken = await FirebaseService.IsUsernameTaken(testUsername);
if (isTaken)
{
Debug.Log($"<color=yellow>[Firebase] Username '{testUsername}' đã tồn tại trên Database!</color>");
}
else
{
Debug.Log($"<color=green>[Firebase] Username '{testUsername}' còn trống. Tiến hành đăng ký...</color>");
// Bước 2: Thử đăng ký user mới
bool success = await FirebaseService.RegisterUser(testUsername);
if (success)
{
Debug.Log("<color=green>[Firebase] Đăng ký thành công! Hãy kiểm tra trình duyệt (Firebase Console).</color>");
}
else
{
Debug.LogError("[Firebase] Đăng ký thất bại. Kiểm tra link URL hoặc Internet.");
}
}
Debug.Log("<color=cyan>--- Firebase Test Finished ---</color>");
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: db205c30e8f41d84fa79269745feaf84

View File

@@ -1,197 +1,80 @@
using UnityEngine;
using UnityEngine.UIElements;
using OnlyScove.Scripts;
using System.Collections.Generic;
using UnityEngine.InputSystem;
using PrimeTween;
using System.Threading.Tasks;
namespace UI
namespace Hallucinate.UI
{
public class HUDController : MonoBehaviour
public class HUDController : BaseUIController
{
[Header("UI Document")]
public UIDocument hudDocument;
private VisualElement _topLeft;
private VisualElement _bottomLeft;
private VisualElement _healthFill;
private VisualElement _staminaFill;
private Label _healthText;
private VisualElement _interactionPrompt;
private Label _interactionLabel;
private ProgressBar _healthBar;
private ProgressBar _staminaBar;
private VisualElement _statsArea;
private VisualElement _inventoryArea;
private VisualElement _infoArea;
private float _lastActionTime;
private const float FADE_TIMEOUT = 5.0f;
private bool _isFaded = false;
private float _lastInputTime;
private bool _isHUDVisible = true;
public float autoHideDelay = 5f;
private void OnEnable()
public override void Initialize(VisualElement uxmlRoot, UIManager manager)
{
if (hudDocument == null)
hudDocument = GetComponent<UIDocument>();
base.Initialize(uxmlRoot, manager);
var root = hudDocument.rootVisualElement;
_topLeft = root.Q<VisualElement>("TopLeft");
_bottomLeft = root.Q<VisualElement>("BottomLeft");
_healthBar = root.Q<ProgressBar>("HealthBar");
_staminaBar = root.Q<ProgressBar>("StaminaBar");
_healthFill = root.Q<VisualElement>("health-fill");
_staminaFill = root.Q<VisualElement>("stamina-fill");
_healthText = root.Q<Label>("health-text");
_interactionPrompt = root.Q<VisualElement>("interaction-prompt");
_interactionLabel = root.Q<Label>("interaction-text");
_statsArea = root.Q<VisualElement>("hud-stats");
_inventoryArea = root.Q<VisualElement>("hud-inventory");
_infoArea = root.Q<VisualElement>("hud-info");
_lastInputTime = Time.time;
_lastActionTime = Time.time;
}
private void Update()
public void UpdateHUD(float health, float stamina)
{
if (PlayerStateMachine.Local != null)
{
SubscribeToPlayer(PlayerStateMachine.Local);
_healthBar.value = health;
_staminaBar.value = stamina;
WakeUpHUD();
}
HandleAutoHide();
HandleInventoryInput();
public void UpdateStats(int ping, int fps)
{
root.Q<Label>("PingLabel").text = $"PING: {ping}ms";
root.Q<Label>("FPSLabel").text = $"FPS: {fps}";
}
private void HandleAutoHide()
public void WakeUpHUD()
{
bool inputDetected = false;
// Check for mouse movement
if (Mouse.current != null && Mouse.current.delta.ReadValue().sqrMagnitude > 0.01f)
inputDetected = true;
// Check for any key press (including mouse buttons)
if (!inputDetected && Keyboard.current != null && Keyboard.current.anyKey.isPressed)
inputDetected = true;
if (!inputDetected && Mouse.current != null && (Mouse.current.leftButton.isPressed || Mouse.current.rightButton.isPressed))
inputDetected = true;
if (inputDetected)
_lastActionTime = Time.time;
if (_isFaded)
{
_lastInputTime = Time.time;
SetHUDVisibility(true);
}
else if (Time.time - _lastInputTime > autoHideDelay)
{
SetHUDVisibility(false);
_isFaded = false;
Tween.Custom(_topLeft.style.opacity.value, 1f, duration: 0.3f, onValueChange: val => _topLeft.style.opacity = val);
Tween.Custom(_bottomLeft.style.opacity.value, 1f, duration: 0.3f, onValueChange: val => _bottomLeft.style.opacity = val);
}
}
private void SetHUDVisibility(bool visible)
public override void Update()
{
if (_isHUDVisible == visible) return;
_isHUDVisible = visible;
float targetOpacity = visible ? 1f : 0.2f;
_statsArea.style.opacity = targetOpacity;
_inventoryArea.style.opacity = targetOpacity;
_infoArea.style.opacity = targetOpacity;
_statsArea.style.transitionProperty = new List<StylePropertyName> { "opacity" };
_statsArea.style.transitionDuration = new List<TimeValue> { new TimeValue(0.5f, TimeUnit.Second) };
_inventoryArea.style.transitionProperty = new List<StylePropertyName> { "opacity" };
_inventoryArea.style.transitionDuration = new List<TimeValue> { new TimeValue(0.5f, TimeUnit.Second) };
_infoArea.style.transitionProperty = new List<StylePropertyName> { "opacity" };
_infoArea.style.transitionDuration = new List<TimeValue> { new TimeValue(0.5f, TimeUnit.Second) };
}
private void HandleInventoryInput()
if (!_isFaded && Time.time - _lastActionTime > FADE_TIMEOUT)
{
if (Keyboard.current == null) return;
if (Keyboard.current.digit1Key.wasPressedThisFrame) SelectSlot(1);
if (Keyboard.current.digit2Key.wasPressedThisFrame) SelectSlot(2);
if (Keyboard.current.digit3Key.wasPressedThisFrame) SelectSlot(3);
_isFaded = true;
Tween.Custom(_topLeft.style.opacity.value, 0.2f, duration: 1.0f, onValueChange: val => _topLeft.style.opacity = val);
Tween.Custom(_bottomLeft.style.opacity.value, 0.2f, duration: 1.0f, onValueChange: val => _bottomLeft.style.opacity = val);
}
}
private void SelectSlot(int index)
public override Task PlayTransitionIn()
{
// Mock logic: Highlight the selected slot
var root = hudDocument.rootVisualElement;
for (int i = 1; i <= 3; i++)
Show();
_topLeft.style.opacity = 1;
_bottomLeft.style.opacity = 1;
return Task.CompletedTask;
}
public override Task PlayTransitionOut()
{
var slot = root.Q<VisualElement>($"slot-{i}");
if (slot != null)
{
float width = (i == index) ? 2f : 1f;
Color color = (i == index) ? Color.white : new Color(0.5f, 0.5f, 0.5f);
slot.style.borderTopWidth = width;
slot.style.borderBottomWidth = width;
slot.style.borderLeftWidth = width;
slot.style.borderRightWidth = width;
slot.style.borderTopColor = color;
slot.style.borderBottomColor = color;
slot.style.borderLeftColor = color;
slot.style.borderRightColor = color;
}
}
_lastInputTime = Time.time;
SetHUDVisibility(true);
}
private PlayerStateMachine _currentPlayer;
private void SubscribeToPlayer(PlayerStateMachine player)
{
if (_currentPlayer == player) return;
if (_currentPlayer != null)
{
_currentPlayer.OnHealthChanged -= UpdateHealth;
_currentPlayer.OnStaminaChanged -= UpdateStamina;
_currentPlayer.OnInteractableTargetChanged -= UpdateInteraction;
}
_currentPlayer = player;
_currentPlayer.OnHealthChanged += UpdateHealth;
_currentPlayer.OnStaminaChanged += UpdateStamina;
_currentPlayer.OnInteractableTargetChanged += UpdateInteraction;
UpdateHealth(_currentPlayer.Health);
UpdateStamina(_currentPlayer.Stamina);
}
private void UpdateHealth(float health)
{
if (_healthFill != null) _healthFill.style.width = Length.Percent(health);
_lastInputTime = Time.time;
SetHUDVisibility(true);
}
private void UpdateStamina(float stamina)
{
if (_staminaFill != null) _staminaFill.style.width = Length.Percent(stamina);
if (stamina < 99f) // Only wake up HUD if stamina is being used
{
_lastInputTime = Time.time;
SetHUDVisibility(true);
}
}
private void UpdateInteraction(IInteractable interactable)
{
if (_interactionPrompt == null) return;
if (interactable != null)
{
_interactionPrompt.style.display = DisplayStyle.Flex;
if (_interactionLabel != null) _interactionLabel.text = interactable.InteractionPrompt;
_lastInputTime = Time.time;
SetHUDVisibility(true);
}
else
{
_interactionPrompt.style.display = DisplayStyle.None;
}
Hide();
return Task.CompletedTask;
}
}
}

View File

@@ -1,75 +1,276 @@
using UnityEngine;
using UnityEngine.UIElements;
using System.Collections.Generic;
using System.Threading.Tasks;
using Fusion;
using System.Linq;
namespace UI
namespace Hallucinate.UI
{
public class LobbyController : MonoBehaviour
public class LobbyController : BaseUIController
{
private VisualElement _joinView;
private VisualElement _createView;
private VisualTreeAsset _roomItemTemplate;
private _BasicSpawner _spawner;
private _PlayerDataManager _playerDataManager;
private float _lastInteractionTime;
private bool _isCreateMode = false;
private const float AutoReturnDelay = 5f;
// Containers
private VisualElement _joinContainer, _createContainer, _loungeContainer, _passOverlay;
private void OnEnable()
// Create Room Fields
private TextField _roomIDInput, _roomNameInput, _roomPassInput;
private Toggle _passToggle;
// Join Room Fields
private ScrollView _roomList;
private TextField _joinPassInput;
private Label _joinPassError;
private SessionInfo _selectedSession;
// Lounge Elements
private VisualElement _playerListContainer;
private Button _readyBtn, _startBtn;
private Label _loungeRoomName;
public override void Initialize(VisualElement uxmlRoot, UIManager manager)
{
var root = GetComponent<UIDocument>().rootVisualElement;
base.Initialize(uxmlRoot, manager);
_spawner = Object.FindFirstObjectByType<_BasicSpawner>();
_joinView = root.Q<VisualElement>("join-view");
_createView = root.Q<VisualElement>("create-view");
// Query Elements
_joinContainer = root.Q<VisualElement>("JoinContainer");
_createContainer = root.Q<VisualElement>("CreateContainer");
_loungeContainer = root.Q<VisualElement>("LoungeContainer");
_passOverlay = root.Q<VisualElement>("PasswordOverlay");
// Back button
root.Q<Button>("btn-back")?.RegisterCallback<ClickEvent>(evt => UIManager.Instance.GoBack());
root.Q<Button>("btn-settings")?.RegisterCallback<ClickEvent>(evt => UIManager.Instance.ToggleSettings());
_roomIDInput = root.Q<TextField>("RoomIDInput");
_roomNameInput = root.Q<TextField>("RoomNameInput");
_roomPassInput = root.Q<TextField>("RoomPassInput");
_passToggle = root.Q<Toggle>("PassToggle");
_roomList = root.Q<ScrollView>("RoomList");
// Create confirm -> Lounge
root.Q<Button>("btn-create-confirm")?.RegisterCallback<ClickEvent>(evt => UIManager.Instance.ShowScreen("Lounge"));
_joinPassInput = root.Q<TextField>("JoinPassInput");
_joinPassError = root.Q<Label>("JoinPassError");
// Register Interaction Resetters
var textFields = root.Query<TextField>().ToList();
foreach (var field in textFields)
field.RegisterValueChangedCallback(evt => ResetInteractionTimer());
// Lounge Elements
_playerListContainer = root.Q<VisualElement>("PlayerList");
_readyBtn = root.Q<Button>("ReadyBtn");
_startBtn = root.Q<Button>("StartBtn");
_loungeRoomName = root.Q<Label>("LoungeRoomName");
var toggles = root.Query<Toggle>().ToList();
foreach (var t in toggles)
t.RegisterValueChangedCallback(evt => ResetInteractionTimer());
// Event Bindings
var goToCreateBtn = root.Q<Button>("GoToCreateBtn");
if (goToCreateBtn != null) goToCreateBtn.clicked += ShowCreate;
// Password Toggle Logic
var passToggle = root.Q<Toggle>("toggle-password");
var passField = root.Q<TextField>("field-password");
passToggle?.RegisterValueChangedCallback(evt => {
if(passField != null) passField.style.display = evt.newValue ? DisplayStyle.Flex : DisplayStyle.None;
var cancelCreateBtn = root.Q<Button>("CancelCreateBtn");
if (cancelCreateBtn != null) cancelCreateBtn.clicked += ShowJoin;
var backToMenuBtn = root.Q<Button>("BackToMenuBtn");
if (backToMenuBtn != null) backToMenuBtn.clicked += async () => await uiManager.Pop();
var confirmCreateBtn = root.Q<Button>("ConfirmCreateBtn");
if (confirmCreateBtn != null) confirmCreateBtn.clicked += OnCreateRoomClicked;
var confirmJoinBtn = root.Q<Button>("ConfirmJoinBtn");
if (confirmJoinBtn != null) confirmJoinBtn.clicked += OnConfirmPasswordClicked;
var closePassBtn = root.Q<Button>("ClosePassBtn");
if (closePassBtn != null) closePassBtn.clicked += () => { if(_passOverlay != null) _passOverlay.style.display = DisplayStyle.None; };
var leaveLoungeBtn = root.Q<Button>("LeaveLoungeBtn");
if (leaveLoungeBtn != null) leaveLoungeBtn.clicked += OnLeaveLoungeClicked;
if (_readyBtn != null) _readyBtn.clicked += OnReadyClicked;
if (_startBtn != null) _startBtn.clicked += OnStartClicked;
if (_passToggle != null)
{
_passToggle.RegisterValueChangedCallback(evt =>
{
if (_roomPassInput != null)
_roomPassInput.style.display = evt.newValue ? DisplayStyle.Flex : DisplayStyle.None;
});
ResetInteractionTimer();
}
private void Update()
// Đăng ký sự kiện từ Spawner
if (_spawner != null)
{
if (_isCreateMode)
_spawner.OnSessionListUpdatedEvent += UpdateRoomList;
_spawner.OnJoinFailedEvent += () => _joinPassError.style.display = DisplayStyle.Flex;
_spawner.OnJoinStartedEvent += () => { /* Show loading if needed */ };
}
}
public void SetRoomTemplate(VisualTreeAsset template) => _roomItemTemplate = template;
public override async Task PlayTransitionIn()
{
if (Time.time - _lastInteractionTime > AutoReturnDelay)
await base.PlayTransitionIn();
ShowJoin();
}
public void ShowJoin()
{
SetMode(false); // Auto return to Stage 1
_joinContainer.style.display = DisplayStyle.Flex;
_createContainer.style.display = DisplayStyle.None;
_loungeContainer.style.display = DisplayStyle.None;
_spawner?.StartLobby();
}
public void ShowCreate()
{
_joinContainer.style.display = DisplayStyle.None;
_createContainer.style.display = DisplayStyle.Flex;
}
private void ShowLounge(string roomName)
{
_joinContainer.style.display = DisplayStyle.None;
_createContainer.style.display = DisplayStyle.None;
_loungeContainer.style.display = DisplayStyle.Flex;
_loungeRoomName.text = $"Room: {roomName}";
_playerDataManager = Object.FindFirstObjectByType<_PlayerDataManager>();
}
private async void OnCreateRoomClicked()
{
string id = _roomIDInput.value.Trim();
string name = string.IsNullOrEmpty(_roomNameInput.value) ? id : _roomNameInput.value;
string pass = _passToggle.value ? _roomPassInput.value : null;
if (string.IsNullOrEmpty(id)) return;
await _spawner.StartHost(id, pass);
ShowLounge(name);
}
private void UpdateRoomList(List<SessionInfo> sessions)
{
if (_roomList == null) return;
_roomList.Clear();
foreach (var session in sessions)
{
var item = _roomItemTemplate.Instantiate();
item.Q<Label>("RoomName").text = session.Name;
item.Q<Label>("PlayerCount").text = $"{session.PlayerCount}/{session.MaxPlayers}";
bool needsPass = session.Properties.ContainsKey("pw");
item.Q<Label>("LockIcon").style.display = needsPass ? DisplayStyle.Flex : DisplayStyle.None;
var joinBtn = item.Q<Button>("JoinBtn");
joinBtn.clicked += () => OnRoomItemClicked(session);
_roomList.Add(item);
}
}
private void OnRoomItemClicked(SessionInfo session)
{
bool needsPass = session.Properties.ContainsKey("pw");
if (needsPass)
{
_selectedSession = session;
_passOverlay.style.display = DisplayStyle.Flex;
_joinPassError.style.display = DisplayStyle.None;
_joinPassInput.value = "";
}
else
{
JoinRoom(session.Name, null);
}
}
private async void OnConfirmPasswordClicked()
{
if (_selectedSession == null) return;
string pass = _joinPassInput.value;
_passOverlay.style.display = DisplayStyle.None;
await JoinRoom(_selectedSession.Name, pass);
}
private async Task JoinRoom(string sessionName, string password)
{
await _spawner.StartClient(sessionName, password);
ShowLounge(sessionName);
}
private void OnReadyClicked()
{
if (_playerDataManager != null)
{
var runner = Object.FindFirstObjectByType<NetworkRunner>();
if (runner != null)
{
_playerDataManager.TryGetPlayerMetaData(runner.LocalPlayer, out var myData);
_playerDataManager.RPC_SetReady(runner.LocalPlayer, !myData.IsReady);
}
}
}
public void SetMode(bool isCreate)
private void OnStartClicked()
{
_isCreateMode = isCreate;
if (_joinView == null) return;
_joinView.style.display = isCreate ? DisplayStyle.None : DisplayStyle.Flex;
_createView.style.display = isCreate ? DisplayStyle.Flex : DisplayStyle.None;
if (isCreate) ResetInteractionTimer();
_spawner.StartGame();
}
private void ResetInteractionTimer()
private void OnLeaveLoungeClicked()
{
_lastInteractionTime = Time.time;
var runner = Object.FindFirstObjectByType<NetworkRunner>();
runner?.Shutdown();
ShowJoin();
}
public override void Update()
{
if (_loungeContainer.style.display == DisplayStyle.Flex)
{
UpdateLoungeUI();
}
}
private void UpdateLoungeUI()
{
if (_playerDataManager == null)
{
_playerDataManager = Object.FindFirstObjectByType<_PlayerDataManager>();
return;
}
var runner = Object.FindFirstObjectByType<NetworkRunner>();
if (runner == null) return;
// Update Player List
_playerListContainer.Clear();
bool allReady = true;
int playerCount = 0;
foreach (var kvp in _playerDataManager.Players)
{
playerCount++;
var playerRef = kvp.Key;
var data = kvp.Value;
var playerItem = new VisualElement();
playerItem.style.flexDirection = FlexDirection.Row;
playerItem.style.justifyContent = Justify.SpaceBetween;
playerItem.style.paddingBottom = 5;
var nameLabel = new Label(data.Name.ToString());
var readyLabel = new Label(data.IsReady ? "READY" : "WAITING...");
readyLabel.style.color = data.IsReady ? Color.green : Color.yellow;
playerItem.Add(nameLabel);
playerItem.Add(readyLabel);
_playerListContainer.Add(playerItem);
if (!data.IsReady) allReady = false;
}
// Update Buttons
_startBtn.style.display = (runner.IsServer && allReady && playerCount >= 2) ? DisplayStyle.Flex : DisplayStyle.None;
_playerDataManager.TryGetPlayerMetaData(runner.LocalPlayer, out var myData);
_readyBtn.text = myData.IsReady ? "UNREADY" : "READY UP";
}
}
}

View File

@@ -2,25 +2,37 @@ using System;
using System.Collections.Generic;
using UnityEngine;
namespace UI
namespace Hallucinate.UI
{
public class LocalizationManager : MonoBehaviour
{
public static LocalizationManager Instance { get; private set; }
private Dictionary<string, string> _localizedText;
private Dictionary<string, string> _localizedText = new Dictionary<string, string>();
private string _currentLanguage = "en";
public event Action OnLanguageChanged;
[Serializable]
private class LocalizationData
{
public List<LocalizationEntry> items;
}
[Serializable]
private class LocalizationEntry
{
public string key;
public string value;
}
private void Awake()
{
if (Instance == null)
{
Instance = this;
if (transform.parent == null)
DontDestroyOnLoad(gameObject);
LoadLanguage(_currentLanguage);
LoadLanguage(PlayerPrefs.GetString("Language", "en"));
}
else
{
@@ -30,41 +42,55 @@ namespace UI
public void LoadLanguage(string langCode)
{
TextAsset targetFile = Resources.Load<TextAsset>($"Localization/{langCode}");
if (targetFile != null)
{
// Simple JSON parsing (For production, consider using a proper JSON library like Newtonsoft)
string json = targetFile.text;
_localizedText = ParseJson(json);
_currentLanguage = langCode;
TextAsset jsonAsset = Resources.Load<TextAsset>($"Localization/{langCode}");
if (jsonAsset != null)
{
// Vì JsonUtility không hỗ trợ Dictionary, chúng ta parse tay một chút nếu file là JSON object phẳng
// Hoặc giả định file JSON có cấu trúc phù hợp.
// Ở đây tôi sẽ dùng giải pháp parse đơn giản cho JSON phẳng { "key": "value" }
ParseFlatJson(jsonAsset.text);
PlayerPrefs.SetString("Language", langCode);
PlayerPrefs.Save();
OnLanguageChanged?.Invoke();
Debug.Log($"[Localization] Loaded language: {langCode}");
}
else
{
Debug.LogError($"[Localization] Language file not found: Localization/{langCode}");
}
}
public string Get(string key)
private void ParseFlatJson(string json)
{
if (_localizedText != null && _localizedText.ContainsKey(key))
return _localizedText[key];
return $"[{key}]";
_localizedText.Clear();
// Xóa các ký tự thừa
json = json.Trim().Trim('{', '}');
string[] pairs = json.Split(new[] { "\",", "\n" }, StringSplitOptions.RemoveEmptyEntries);
foreach (var pair in pairs)
{
string[] kv = pair.Split(new[] { "\":\"" }, StringSplitOptions.None);
if (kv.Length == 2)
{
string key = kv[0].Trim().Trim('"', ' ', '\t', '\r');
string val = kv[1].Trim().Trim('"', ' ', '\t', '\r');
_localizedText[key] = val;
}
}
}
private Dictionary<string, string> ParseJson(string json)
public string GetLocalizedString(string key)
{
// Dummy parser for demonstration, replace with JsonUtility if using wrapper class
// or Newtonsoft for direct dictionary parsing
var dict = new Dictionary<string, string>();
string[] lines = json.Split(new[] { ',', '{', '}', '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
foreach (var line in lines)
if (_localizedText != null && _localizedText.TryGetValue(key, out string value))
{
string[] parts = line.Split(':');
if (parts.Length == 2)
{
string key = parts[0].Trim(' ', '"');
string val = parts[1].Trim(' ', '"');
dict[key] = val;
}
}
return dict;
}
return value;
}
return key;
}
public string CurrentLanguage => _currentLanguage;
}
}

View File

@@ -1,2 +1,2 @@
fileFormatVersion: 2
guid: 5c17a3f09ee49ff48a0e3e2b45080257
guid: ff7ac0ce8c8c98445b895ac53a4618f1

View File

@@ -0,0 +1,91 @@
using UnityEngine;
using UnityEngine.UIElements;
using PrimeTween;
using System.Threading.Tasks;
namespace Hallucinate.UI
{
public class LoginController : BaseUIController
{
private TextField _nameInput;
private Label _errorLabel;
private Button _confirmBtn;
public override void Initialize(VisualElement uxmlRoot, UIManager manager)
{
base.Initialize(uxmlRoot, manager);
_nameInput = root.Q<TextField>("UsernameInput");
_errorLabel = root.Q<Label>("ErrorMsg");
_confirmBtn = root.Q<Button>("ConfirmBtn");
if (_confirmBtn != null)
_confirmBtn.clicked += OnConfirmClicked;
}
private async void OnConfirmClicked()
{
string username = _nameInput.value.Trim();
if (string.IsNullOrEmpty(username))
{
ShowError("Name cannot be empty!");
return;
}
_confirmBtn.SetEnabled(false);
_confirmBtn.text = "CHECKING...";
// 1. Kiểm tra trùng tên trên Firebase
bool isTaken = await FirebaseService.IsUsernameTaken(username);
if (isTaken)
{
ShowError("This name is already taken!");
_confirmBtn.SetEnabled(true);
_confirmBtn.text = "CONFIRM";
}
else
{
// 2. Đăng ký user mới
bool success = await FirebaseService.RegisterUser(username);
if (success)
{
// 3. Lưu lại và đóng popup
PlayerPrefs.SetString("Username", username);
PlayerPrefs.Save();
Debug.Log($"[Login] Registered as {username}");
// Thông báo cho UIManager biết đã login xong
uiManager.OnLoginSuccess();
await PlayTransitionOut();
}
else
{
ShowError("Connection error!");
_confirmBtn.SetEnabled(true);
_confirmBtn.text = "CONFIRM";
}
}
}
private void ShowError(string msg)
{
if (_errorLabel == null) return;
_errorLabel.text = msg;
_errorLabel.style.display = DisplayStyle.Flex;
}
public override async Task PlayTransitionIn()
{
// Login hiện ra như một overlay trung tâm
if (root != null)
{
root.style.translate = new StyleTranslate(new Translate(0, 0));
root.style.opacity = 0;
}
Show();
await Tween.Custom(0f, 1f, duration: 0.5f, onValueChange: val => root.style.opacity = val);
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: fbd606c21d317da47820446e4da1c55b

View File

@@ -1,36 +0,0 @@
using UnityEngine;
using UnityEngine.UIElements;
namespace UI
{
public class LoungeController : MonoBehaviour
{
private Toggle _readyHost;
private Toggle _readyGuest;
private Button _btnStart;
private void OnEnable()
{
var root = GetComponent<UIDocument>().rootVisualElement;
_readyHost = root.Q<Toggle>("ready-host");
_readyGuest = root.Q<Toggle>("ready-guest");
_btnStart = root.Q<Button>("btn-start");
_readyHost?.RegisterValueChangedCallback(evt => UpdateStartButton());
_readyGuest?.RegisterValueChangedCallback(evt => UpdateStartButton());
_btnStart?.RegisterCallback<ClickEvent>(evt => UIManager.Instance.ShowScreen("HUD"));
root.Q<Button>("btn-back")?.RegisterCallback<ClickEvent>(evt => UIManager.Instance.GoBack());
UpdateStartButton();
}
private void UpdateStartButton()
{
if (_btnStart == null) return;
bool bothReady = (_readyHost != null && _readyHost.value) && (_readyGuest != null && _readyGuest.value);
_btnStart.SetEnabled(bothReady);
}
}
}

View File

@@ -1,2 +0,0 @@
fileFormatVersion: 2
guid: ac201603ede0899488995be3d88ea0dc

View File

@@ -1,192 +1,256 @@
using UnityEngine;
using UnityEngine.UIElements;
using System.Collections;
using System.Collections.Generic;
using PrimeTween;
using System.Threading.Tasks;
namespace UI
namespace Hallucinate.UI
{
public class MainMenuController : MonoBehaviour
public class MainMenuController : BaseUIController
{
private VisualElement _root;
private VisualElement _logoContainer;
public enum MenuState { Idle, Ribbon }
private MenuState _currentState = MenuState.Idle;
private VisualElement _logo;
private VisualElement _ribbon;
private VisualElement _logoPlaceholder;
private bool _isActive = false;
[Header("Animation Settings")]
public float transitionDuration = 0.5f;
public float idleTimeout = 5f;
public float pulseSpeed = 2f;
public float pulseAmount = 0.05f;
private VisualElement _logoSpace;
private float _lastInteractionTime;
private int _lastClickFrame = -1;
private Coroutine _currentTransition;
private const float IDLE_TIMEOUT = 5.0f;
private bool _isFirstLoad = true;
private void OnEnable()
private Tween _pulseTween;
private Tween _rotationTween;
private Texture2D _currentIcon;
public override void Initialize(VisualElement uxmlRoot, UIManager manager)
{
_root = GetComponent<UIDocument>().rootVisualElement;
base.Initialize(uxmlRoot, manager);
_logoContainer = _root.Q<VisualElement>("beat-logo-container");
_logo = _root.Q<VisualElement>("beat-logo");
_ribbon = _root.Q<VisualElement>("menu-ribbon");
_logoPlaceholder = _root.Q<VisualElement>("logo-placeholder");
_logo = root.Q<VisualElement>("Logo");
_ribbon = root.Q<VisualElement>("Ribbon");
_logoSpace = root.Q<VisualElement>("LogoSpace");
// Đảm bảo Logo luôn có thể nhấn được
_logoContainer.pickingMode = PickingMode.Position;
_logo.pickingMode = PickingMode.Position;
_logoContainer.RegisterCallback<ClickEvent>(OnLogoClicked);
_root.RegisterCallback<MouseMoveEvent>(evt => ResetIdleTimer());
var buttons = _root.Query<Button>().ToList();
foreach (var btn in buttons)
if (_logo == null)
{
btn.RegisterCallback<PointerDownEvent>(evt => ApplyDrumHit(btn, true));
btn.RegisterCallback<PointerUpEvent>(evt => ApplyDrumHit(btn, false));
btn.RegisterCallback<ClickEvent>(evt => ResetIdleTimer());
Debug.LogError($"[MainMenuController] Element 'Logo' not found in UXML!");
return;
}
_logoContainer.RegisterCallback<PointerDownEvent>(evt => ApplyDrumHit(_logoContainer, true));
_logoContainer.RegisterCallback<PointerUpEvent>(evt => ApplyDrumHit(_logoContainer, false));
// Lắng nghe sự kiện thay đổi kích thước toàn màn hình
root.RegisterCallback<GeometryChangedEvent>(OnScreenResize);
// Routing
_root.Q<Button>("btn-create")?.RegisterCallback<ClickEvent>(ev => NavigateToLobby(true));
_root.Q<Button>("btn-join")?.RegisterCallback<ClickEvent>(ev => NavigateToLobby(false));
_root.Q<Button>("btn-settings")?.RegisterCallback<ClickEvent>(ev => UIManager.Instance.ToggleSettings());
_root.Q<Button>("btn-profile")?.RegisterCallback<ClickEvent>(ev => UIManager.Instance.ShowScreen("Profile"));
_root.Q<Button>("btn-exit")?.RegisterCallback<ClickEvent>(ev => Application.Quit());
_logo.RegisterCallback<ClickEvent>(OnLogoClicked);
ResetToIdleState();
var settingsBtn = root.Q<Button>("SettingsBtn");
if (settingsBtn != null) settingsBtn.clicked += () => uiManager.ToggleSettings();
root.Q<Button>("JoinBtn").clicked += async () => await uiManager.Push<LobbyController>();
root.Q<Button>("CreateBtn").clicked += async () => await uiManager.Push<LobbyController>();
root.Q<Button>("ProfileBtn").clicked += async () => await uiManager.Push<ProfileController>();
root.Q<Button>("ExitBtn").clicked += () => Application.Quit();
ResetLogoPosition();
StartPulse();
_lastInteractionTime = Time.time;
}
private void Update()
private void OnScreenResize(GeometryChangedEvent evt)
{
float baseScale = _isActive ? 0.35f : 1.0f;
float pulse = Mathf.Sin(Time.time * pulseSpeed) * pulseAmount;
_logo.style.scale = new Scale(new Vector3(baseScale + pulse, baseScale + pulse, 1f));
if (_isActive && _currentTransition == null)
// Khi màn hình thay đổi kích thước, nếu đang ở Ribbon thì cập nhật theo LogoSpace
if (_currentState == MenuState.Ribbon)
{
if (Time.time - _lastInteractionTime > idleTimeout)
_currentTransition = StartCoroutine(TransitionToIdle());
}
}
private void OnLogoClicked(ClickEvent evt)
{
if (Time.frameCount == _lastClickFrame) return;
_lastClickFrame = Time.frameCount;
ResetIdleTimer();
// QUAN TRỌNG: Chỉ vào Lobby nếu ĐÃ Active và KHÔNG đang chuyển cảnh
if (!_isActive) {
if (_currentTransition != null) StopCoroutine(_currentTransition);
_currentTransition = StartCoroutine(TransitionToActive());
} else if (_currentTransition == null) {
NavigateToLobby(true);
}
}
private void ApplyDrumHit(VisualElement element, bool isDown)
{
if (isDown)
{
element.style.scale = new Scale(new Vector3(0.85f, 0.85f, 1f));
element.style.transitionDuration = new List<TimeValue> { new TimeValue(0.05f, TimeUnit.Second) };
UpdateLogoToSpace();
}
else
{
element.style.scale = new Scale(Vector3.one);
element.style.transitionDuration = new List<TimeValue> { new TimeValue(0.15f, TimeUnit.Second) };
ResetLogoPosition();
}
}
private void ResetIdleTimer()
private void ResetLogoPosition()
{
if (_logo == null) return;
// Sử dụng phần trăm để luôn ở giữa bất kể độ phân giải
_logo.style.left = Length.Percent(50);
_logo.style.top = Length.Percent(50);
_logo.style.translate = new StyleTranslate(new Translate(Length.Percent(-50), Length.Percent(-50)));
_logo.style.width = 200;
_logo.style.height = 200;
}
public void SetGameIcon(Texture2D icon)
{
if (icon == null || _logo == null) return;
_currentIcon = icon;
_logo.style.backgroundImage = icon;
var radius = new StyleLength(new Length(50, LengthUnit.Percent));
_logo.style.borderTopLeftRadius = radius;
_logo.style.borderTopRightRadius = radius;
_logo.style.borderBottomLeftRadius = radius;
_logo.style.borderBottomRightRadius = radius;
_logo.style.overflow = Overflow.Hidden;
var label = _logo.Q<Label>();
if (label != null) label.style.display = DisplayStyle.None;
StartRotation();
}
private void StartRotation()
{
if (_currentIcon == null) return;
if (_rotationTween.isAlive) _rotationTween.Stop();
_rotationTween = Tween.Custom(0f, 360f, duration: 4f,
onValueChange: val => _logo.style.rotate = new StyleRotate(new Rotate(Angle.Degrees(val))),
cycles: -1,
ease: Ease.Linear);
}
public override async Task PlayTransitionIn()
{
_lastInteractionTime = Time.time;
_currentState = MenuState.Idle;
ResetLogoPosition();
if (_ribbon != null)
{
_ribbon.style.display = DisplayStyle.None;
_ribbon.style.opacity = 0;
}
StartRotation();
await base.PlayTransitionIn();
if (!_isFirstLoad) TransitionToRibbon();
else _isFirstLoad = false;
}
public override async Task PlayTransitionOut()
{
if (_rotationTween.isAlive) _rotationTween.Stop();
await base.PlayTransitionOut();
}
private async void OnLogoClicked(ClickEvent evt)
{
_lastInteractionTime = Time.time;
if (_currentState == MenuState.Idle) TransitionToRibbon();
else await uiManager.Push<LobbyController>();
}
private void TransitionToRibbon()
{
if (_currentState == MenuState.Ribbon && _ribbon.resolvedStyle.display == DisplayStyle.Flex) return;
_currentState = MenuState.Ribbon;
_lastInteractionTime = Time.time;
_ribbon.style.display = DisplayStyle.Flex;
Tween.Custom(0f, 1f, duration: 0.3f, onValueChange: val => _ribbon.style.opacity = val);
// Đợi một frame để Ribbon layout xong rồi mới lấy vị trí LogoSpace
_logoSpace.RegisterCallback<GeometryChangedEvent>(OnLogoSpaceReady);
}
private void OnLogoSpaceReady(GeometryChangedEvent evt)
{
_logoSpace.UnregisterCallback<GeometryChangedEvent>(OnLogoSpaceReady);
UpdateLogoToSpace(true);
}
private void UpdateLogoToSpace(bool animate = false)
{
Rect targetBounds = _logoSpace.worldBound;
if (targetBounds.width <= 0) return;
// Chuyển đổi tọa độ world của LogoSpace sang tọa độ local của root
Vector2 localPos = root.WorldToLocal(new Vector2(targetBounds.x, targetBounds.y));
float targetX = localPos.x + (targetBounds.width / 2f);
float targetY = localPos.y + (targetBounds.height / 2f);
// Khi ở Ribbon, chúng ta bỏ translate -50% để tính toán chính xác tâm
_logo.style.translate = new StyleTranslate(new Translate(Length.Percent(-50), Length.Percent(-50)));
if (animate)
{
Tween.Custom(_logo.resolvedStyle.left, targetX, duration: 0.5f,
onValueChange: val => _logo.style.left = val,
ease: Ease.OutQuad);
Tween.Custom(_logo.resolvedStyle.top, targetY, duration: 0.5f,
onValueChange: val => _logo.style.top = val,
ease: Ease.OutQuad);
Tween.Custom(_logo.resolvedStyle.width, 100f, duration: 0.5f,
onValueChange: val => _logo.style.width = val,
ease: Ease.OutQuad);
Tween.Custom(_logo.resolvedStyle.height, 100f, duration: 0.5f,
onValueChange: val => _logo.style.height = val,
ease: Ease.OutQuad);
}
else
{
_logo.style.left = targetX;
_logo.style.top = targetY;
_logo.style.width = 100;
_logo.style.height = 100;
}
_lastInteractionTime = Time.time;
}
private void TransitionToIdle()
{
if (_currentState == MenuState.Idle) return;
_currentState = MenuState.Idle;
// Quay lại dùng phần trăm để tự động căn giữa
Tween.Custom(_logo.resolvedStyle.width, 200f, duration: 0.5f, onValueChange: val => _logo.style.width = val, ease: Ease.OutQuad);
Tween.Custom(_logo.resolvedStyle.height, 200f, duration: 0.5f, onValueChange: val => _logo.style.height = val, ease: Ease.OutQuad);
// Animate left/top về 50%
float startLeft = _logo.resolvedStyle.left;
float startTop = _logo.resolvedStyle.top;
float targetLeft = root.resolvedStyle.width / 2f;
float targetTop = root.resolvedStyle.height / 2f;
Tween.Custom(0f, 1f, duration: 0.5f, ease: Ease.OutQuad, onValueChange: t => {
_logo.style.left = Mathf.Lerp(startLeft, targetLeft, t);
_logo.style.top = Mathf.Lerp(startTop, targetTop, t);
}).OnComplete(() => {
ResetLogoPosition(); // Đảm bảo cuối cùng dùng đơn vị Percent
});
Tween.Custom(1f, 0f, duration: 0.5f, onValueChange: val => _ribbon.style.opacity = val)
.OnComplete(() => _ribbon.style.display = DisplayStyle.None);
}
public override void Update()
{
if (Input.GetAxis("Mouse X") != 0 || Input.GetAxis("Mouse Y") != 0 || Input.anyKey)
{
_lastInteractionTime = Time.time;
}
private void NavigateToLobby(bool isCreate)
if (_currentState == MenuState.Ribbon && Time.time - _lastInteractionTime > IDLE_TIMEOUT)
{
var lobby = Object.FindFirstObjectByType<LobbyController>();
lobby?.SetMode(isCreate);
UIManager.Instance.ShowScreen("Lobby");
TransitionToIdle();
}
}
private void ResetToIdleState()
private void StartPulse()
{
_isActive = false;
UIManager.Instance.isMainMenuActive = false;
_ribbon.style.display = DisplayStyle.None;
_root.Add(_logoContainer);
_logoContainer.style.position = Position.Absolute;
_logoContainer.style.width = 300; _logoContainer.style.height = 300;
_logoContainer.style.left = Length.Percent(50);
_logoContainer.style.top = Length.Percent(50);
_logoContainer.style.translate = new Translate(Length.Percent(-50), Length.Percent(-50));
_currentTransition = null;
}
private IEnumerator TransitionToActive()
{
_isActive = true;
UIManager.Instance.isMainMenuActive = true;
ResetIdleTimer();
_ribbon.style.display = DisplayStyle.Flex;
_ribbon.style.opacity = 0;
yield return null;
_logoContainer.style.transitionProperty = new List<StylePropertyName> { "translate", "opacity" };
_logoContainer.style.transitionDuration = new List<TimeValue> { new TimeValue(transitionDuration, TimeUnit.Second) };
_ribbon.style.transitionProperty = new List<StylePropertyName> { "opacity" };
_ribbon.style.transitionDuration = new List<TimeValue> { new TimeValue(transitionDuration, TimeUnit.Second) };
// Trượt Logo từ tâm sang vị trí ribbon (#2)
_logoContainer.style.translate = new Translate(Length.Percent(-75f), Length.Percent(-50f));
_ribbon.style.opacity = 1;
yield return new WaitForSeconds(transitionDuration);
// Gán chặt vào placeholder và khóa kích thước để chống giãn
_logoPlaceholder.Add(_logoContainer);
_logoContainer.style.position = Position.Relative;
_logoContainer.style.left = StyleKeyword.Auto;
_logoContainer.style.top = StyleKeyword.Auto;
_logoContainer.style.translate = new Translate(0, 0);
// Khóa kích thước nhỏ để fit vào Ribbon
_logoContainer.style.width = 100;
_logoContainer.style.height = 100;
_currentTransition = null;
}
private IEnumerator TransitionToIdle()
{
_isActive = false;
UIManager.Instance.isMainMenuActive = false;
_root.Add(_logoContainer);
_logoContainer.style.position = Position.Absolute;
_logoContainer.style.width = 300; _logoContainer.style.height = 300;
_logoContainer.style.left = Length.Percent(50);
_logoContainer.style.top = Length.Percent(50);
_logoContainer.style.translate = new Translate(Length.Percent(-75f), Length.Percent(-50f));
yield return null;
_logoContainer.style.translate = new Translate(Length.Percent(-50f), Length.Percent(-50f));
_ribbon.style.opacity = 0;
yield return new WaitForSeconds(transitionDuration);
_ribbon.style.display = DisplayStyle.None;
_currentTransition = null;
if (_pulseTween.isAlive) _pulseTween.Stop();
_pulseTween = Tween.Custom(Vector3.one, Vector3.one * 1.1f, duration: 0.8f,
onValueChange: val => _logo.style.scale = new StyleScale(new Scale(val)),
cycles: -1,
cycleMode: CycleMode.Yoyo,
ease: Ease.InOutSine);
}
}
}

View File

@@ -1,75 +0,0 @@
using OnlyScove.Scripts;
using UnityEngine;
using UnityEngine.UI;
using TMPro;
namespace UI
{
public class MyUIDisplay : MonoBehaviour
{
[Header("References")]
public PlayerDebugProvider playerDebugProvider;
[Header("UI Prompt")]
public GameObject interactionPromptContainer;
public UnityEngine.UI.Text interactionPromptText;
private void Start()
{
//if (playerDebugProvider == null)
//playerDebugProvider = FindFirstObjectByType<PlayerDebugProvider>();
// Luôn ẩn lúc bắt đầu
if (interactionPromptContainer != null)
interactionPromptContainer.SetActive(false);
TryFindPlayer();
}
private void Update()
{
if (playerDebugProvider == null)
{
TryFindPlayer();
if (playerDebugProvider == null) return;
}
if (interactionPromptContainer == null) return;
IInteractable interactable = playerDebugProvider.GetActiveInteractable();
if (interactable != null)
{
// Hiện UI tại vị trí cố định bạn đã đặt trong Canvas
interactionPromptContainer.SetActive(true);
if (!interactionPromptContainer.activeSelf)
{
interactionPromptContainer.SetActive(true);
}
if (interactionPromptText != null)
interactionPromptText.text = interactable.InteractionPrompt;
}
else
{
if (interactionPromptContainer.activeSelf)
interactionPromptContainer.SetActive(false);
}
}
private void TryFindPlayer()
{
if (PlayerStateMachine.Local != null)
{
playerDebugProvider = PlayerStateMachine.Local.GetComponent<PlayerDebugProvider>();
}
if (playerDebugProvider == null)
{
playerDebugProvider = Object.FindFirstObjectByType<PlayerDebugProvider>();
}
}
}
}

View File

@@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: cd13c5c96000414397dd7d41a73edd62
timeCreated: 1773383951

View File

@@ -1,14 +1,37 @@
using UnityEngine;
using UnityEngine.UIElements;
using System.Threading.Tasks;
namespace UI
namespace Hallucinate.UI
{
public class ProfileController : MonoBehaviour
public class ProfileController : BaseUIController
{
private void OnEnable()
private Label _username;
private Label _rank;
private ProgressBar _winRateBar;
private Label _winRateText;
public override void Initialize(VisualElement uxmlRoot, UIManager manager)
{
var root = GetComponent<UIDocument>().rootVisualElement;
root.Q<Button>("btn-close")?.RegisterCallback<ClickEvent>(ev => UIManager.Instance.GoBack());
base.Initialize(uxmlRoot, manager);
_username = root.Q<Label>("Username");
_rank = root.Q<Label>("Rank");
_winRateBar = root.Q<ProgressBar>("WinRateBar");
_winRateText = root.Q<Label>("WinRateText");
root.Q<Button>("BackBtn").clicked += async () => await uiManager.Pop();
LoadProfileData();
}
private void LoadProfileData()
{
// Dummy data for now
_username.text = "GamerPro_2026";
_rank.text = "DIAMOND II";
_winRateBar.value = 72;
_winRateText.text = "72%";
}
}
}

View File

@@ -1,63 +1,323 @@
using UnityEngine;
using UnityEngine.UIElements;
using UnityEngine.InputSystem;
using PrimeTween;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using UnityEngine.SceneManagement;
using OnlyScove.Scripts;
namespace UI
namespace Hallucinate.UI
{
public class SettingsController : MonoBehaviour
public class SettingsController : BaseUIController
{
private VisualElement _contentGeneral;
private VisualElement _contentGraphics;
private VisualElement _contentAudio;
private VisualElement _contentControls;
private VisualElement _sidebar;
private Label _tabTitle;
private ScrollView _content;
private InputActionAsset _inputActions;
private Button _tabGeneral;
private Button _tabGraphics;
private Button _tabAudio;
private Button _tabControls;
private Dictionary<string, Button> _tabButtons = new Dictionary<string, Button>();
private string _activeTab = "GENERAL";
private void OnEnable()
public override void Initialize(VisualElement uxmlRoot, UIManager manager)
{
var root = GetComponent<UIDocument>().rootVisualElement;
base.Initialize(uxmlRoot, manager);
// Tabs
_tabGeneral = root.Q<Button>("tab-general");
_tabGraphics = root.Q<Button>("tab-graphics");
_tabAudio = root.Q<Button>("tab-audio");
_tabControls = root.Q<Button>("tab-controls");
_sidebar = root.Q<VisualElement>("Sidebar");
_tabTitle = root.Q<Label>("TabTitle");
_content = root.Q<ScrollView>("SettingsContent");
// Content
_contentGeneral = root.Q<VisualElement>("content-general");
_contentGraphics = root.Q<VisualElement>("content-graphics");
_contentAudio = root.Q<VisualElement>("content-audio");
_contentControls = root.Q<VisualElement>("content-controls");
// Register Tab Events
_tabGeneral?.RegisterCallback<ClickEvent>(evt => SwitchTab(_contentGeneral, _tabGeneral));
_tabGraphics?.RegisterCallback<ClickEvent>(evt => SwitchTab(_contentGraphics, _tabGraphics));
_tabAudio?.RegisterCallback<ClickEvent>(evt => SwitchTab(_contentAudio, _tabAudio));
_tabControls?.RegisterCallback<ClickEvent>(evt => SwitchTab(_contentControls, _tabControls));
// Close
root.Q<Button>("btn-close")?.RegisterCallback<ClickEvent>(evt => UIManager.Instance.ToggleSettings());
_inputActions = uiManager.InputReader?.InputActions;
if (_inputActions == null)
{
_inputActions = GameObject.FindAnyObjectByType<PlayerInput>()?.actions;
}
private void SwitchTab(VisualElement targetContent, Button targetTab)
root.RegisterCallback<PointerDownEvent>(evt => {
if (evt.target == root)
{
// Hide all
_contentGeneral.style.display = DisplayStyle.None;
if(_contentGraphics != null) _contentGraphics.style.display = DisplayStyle.None;
if(_contentAudio != null) _contentAudio.style.display = DisplayStyle.None;
if(_contentControls != null) _contentControls.style.display = DisplayStyle.None;
uiManager.ToggleSettings();
}
});
_tabGeneral.RemoveFromClassList("active-tab");
_tabGraphics.RemoveFromClassList("active-tab");
_tabAudio.RemoveFromClassList("active-tab");
_tabControls.RemoveFromClassList("active-tab");
SetupTab("GeneralTab", "GENERAL");
SetupTab("VideoTab", "VIDEO");
SetupTab("SoundTab", "SOUND");
SetupTab("ControlTab", "CONTROL");
// Show target
targetContent.style.display = DisplayStyle.Flex;
targetTab.AddToClassList("active-tab");
var closeBtn = root.Q<Button>("CloseSettingsBtn");
if (closeBtn != null) closeBtn.clicked += () => uiManager.ToggleSettings();
SwitchTab("GENERAL");
}
private void SetupTab(string btnName, string tabId)
{
var btn = root.Q<Button>(btnName);
if (btn != null)
{
_tabButtons[tabId] = btn;
btn.clicked += () => SwitchTab(tabId);
}
}
private void SwitchTab(string tabId)
{
_activeTab = tabId;
_tabTitle.text = tabId;
foreach (var kvp in _tabButtons)
{
if (kvp.Key == tabId) kvp.Value.AddToClassList("active-tab");
else kvp.Value.RemoveFromClassList("active-tab");
}
_content.Clear();
switch (tabId)
{
case "GENERAL":
RenderGeneralSettings();
break;
case "CONTROL":
RenderControlSettings();
break;
default:
var comingSoon = new Label($"Settings for {tabId} coming soon...");
comingSoon.AddToClassList("text-body");
_content.Add(comingSoon);
break;
}
}
private void RenderGeneralSettings()
{
// --- ACCOUNT ---
_content.Add(CreateSection(GetLoc("settings_general")));
var wipeBtn = new Button { text = "WIPE ALL USER DATA (TEST ONLY)" };
wipeBtn.AddToClassList("button-spring");
wipeBtn.AddToClassList("btn-exit");
wipeBtn.style.marginTop = 10;
wipeBtn.style.backgroundColor = new Color(0.8f, 0.2f, 0.2f, 0.8f);
wipeBtn.clicked += () => {
bool confirm = true;
#if UNITY_EDITOR
confirm = UnityEditor.EditorUtility.DisplayDialog("Wipe Data", "This will delete your local username and restart the game. Proceed?", "Yes", "Cancel");
#endif
if (confirm)
{
PlayerPrefs.DeleteAll();
PlayerPrefs.Save();
SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);
}
};
_content.Add(wipeBtn);
// --- LANGUAGE ---
_content.Add(CreateSection(GetLoc("label_language")));
var langContainer = new VisualElement();
langContainer.style.flexDirection = FlexDirection.Row;
langContainer.style.alignItems = Align.Center;
langContainer.style.marginTop = 10;
var langLabel = new Label(GetLoc("label_language"));
langLabel.AddToClassList("text-body");
langLabel.style.width = Length.Percent(40);
var langDropdown = new DropdownField(new List<string> { "English", "Tiếng Việt" }, LocalizationManager.Instance?.CurrentLanguage == "vi" ? 1 : 0);
langDropdown.style.flexGrow = 1;
langDropdown.RegisterValueChangedCallback(evt => {
string code = evt.newValue == "Tiếng Việt" ? "vi" : "en";
LocalizationManager.Instance?.LoadLanguage(code);
// Refresh current tab to update text
SwitchTab("GENERAL");
});
langContainer.Add(langLabel);
langContainer.Add(langDropdown);
_content.Add(langContainer);
// --- INTERFACE ---
_content.Add(CreateSection("INTERFACE"));
float currentScale = PlayerPrefs.GetFloat("UIScale", 1.0f);
var scaleRow = CreateSliderWithInput("UI SCALE", 0.5f, 2.0f, currentScale, (val) => {
uiManager.SetUIScale(val);
});
_content.Add(scaleRow);
_content.Add(new Label("\nNote: Some elements may require restart to align perfectly.") {
style = { fontSize = 12, color = new Color(0.6f, 0.6f, 0.6f), whiteSpace = WhiteSpace.Normal, marginTop = 20 }
});
}
private VisualElement CreateSliderWithInput(string labelText, float min, float max, float startVal, Action<float> OnValueChanged)
{
var row = new VisualElement();
row.style.flexDirection = FlexDirection.Row;
row.style.alignItems = Align.Center;
row.style.marginTop = 10;
row.style.marginBottom = 10;
var label = new Label(labelText);
label.AddToClassList("text-body");
label.style.width = Length.Percent(35);
var slider = new Slider(min, max);
slider.style.flexGrow = 1;
slider.value = startVal;
var input = new TextField();
input.style.width = 60;
input.style.marginLeft = 15;
input.value = startVal.ToString("F1");
input.AddToClassList("input-field");
input.style.marginBottom = 0; // Override default margin
input.style.height = 30;
input.style.fontSize = 14;
// Sync Slider -> Input
slider.RegisterValueChangedCallback(evt => {
float val = Mathf.Round(evt.newValue * 10f) / 10f;
// Kiểm tra xem input có đang được focus không để tránh ghi đè khi người dùng đang nhập
bool isInputFocused = input.panel?.focusController?.focusedElement == input.ElementAt(0);
if (!isInputFocused) input.value = val.ToString("F1");
OnValueChanged?.Invoke(val);
});
// Sync Input -> Slider
input.RegisterValueChangedCallback(evt => {
if (float.TryParse(evt.newValue, out float val))
{
val = Mathf.Clamp(val, min, max);
slider.value = val;
OnValueChanged?.Invoke(val);
}
});
// Format on blur
input.RegisterCallback<BlurEvent>(evt => {
if (float.TryParse(input.value, out float val))
{
input.value = Mathf.Clamp(val, min, max).ToString("F1");
}
});
row.Add(label);
row.Add(slider);
row.Add(input);
return row;
}
private void RenderControlSettings()
{
if (_inputActions == null)
{
var errorLabel = new Label("Input Actions not found. Cannot rebind.");
errorLabel.AddToClassList("text-body");
_content.Add(errorLabel);
return;
}
var playerMap = _inputActions.FindActionMap("Player");
if (playerMap == null) return;
RenderSection("MOVEMENT", playerMap, new[] { "Move", "Jump", "Sprint", "Crouch" });
RenderSection("COMBAT", playerMap, new[] { "Attack" });
RenderSection("INTERACTION", playerMap, new[] { "Interact", "Next", "Previous" });
RenderSection("VIEW", playerMap, new[] { "Look", "ToggleView", "Scroll" });
}
private void RenderSection(string header, InputActionMap map, string[] actionNames)
{
_content.Add(CreateSection(header));
foreach (var name in actionNames)
{
var action = map.FindAction(name);
if (action != null) _content.Add(CreateRebindRow(action));
}
}
private VisualElement CreateSection(string title)
{
var header = new Label(title);
header.AddToClassList("setting-section-header");
return header;
}
private VisualElement CreateRebindRow(InputAction action)
{
var row = new VisualElement();
row.AddToClassList("rebind-row");
var label = new Label(action.name.ToUpper());
label.AddToClassList("rebind-label");
var rebindBtn = new Button();
rebindBtn.AddToClassList("rebind-button");
UpdateBindingText(action, rebindBtn);
rebindBtn.clicked += () => StartRebind(action, rebindBtn);
row.Add(label);
row.Add(rebindBtn);
return row;
}
private void UpdateBindingText(InputAction action, Button btn)
{
int bindingIndex = action.GetBindingIndexForControl(action.controls[0]);
btn.text = action.GetBindingDisplayString(bindingIndex);
}
private void StartRebind(InputAction action, Button btn)
{
string oldText = btn.text;
btn.text = "...";
btn.style.color = Color.yellow;
action.Disable();
var rebindOperation = action.PerformInteractiveRebinding()
.WithControlsExcluding("<Mouse>/delta")
.WithControlsExcluding("<Mouse>/scroll")
.OnMatchWaitForAnother(0.1f)
.OnComplete(operation => {
btn.style.color = new Color(0f, 1f, 0.8f);
UpdateBindingText(action, btn);
action.Enable();
operation.Dispose();
})
.OnCancel(operation => {
btn.style.color = new Color(0f, 1f, 0.8f);
btn.text = oldText;
action.Enable();
operation.Dispose();
});
rebindOperation.Start();
}
public override async Task PlayTransitionIn()
{
if (root != null)
{
root.style.translate = new StyleTranslate(new Translate(0, 0));
root.style.display = DisplayStyle.Flex;
root.style.opacity = 1;
}
_sidebar.style.translate = new StyleTranslate(new Translate(Length.Percent(-100), 0));
await Tween.Custom(-100f, 0f, duration: 0.4f, ease: Ease.OutQuad,
onValueChange: val => _sidebar.style.translate = new StyleTranslate(new Translate(Length.Percent(val), 0)));
}
public override async Task PlayTransitionOut()
{
await Tween.Custom(0f, -100f, duration: 0.4f, ease: Ease.InQuad,
onValueChange: val => _sidebar.style.translate = new StyleTranslate(new Translate(Length.Percent(val), 0)));
Hide();
}
}
}

View File

@@ -1,246 +1,433 @@
using System.Collections;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.UIElements;
using System.Linq;
using PrimeTween;
using OnlyScove.Scripts;
#if UNITY_EDITOR
using UnityEditor;
using UnityEditor.Build;
#endif
namespace UI
namespace Hallucinate.UI
{
[RequireComponent(typeof(UIDocument))]
public class UIManager : MonoBehaviour
{
public static UIManager Instance { get; private set; }
[System.Serializable]
public class ScreenData
{
public string screenName;
public UIDocument document;
public bool isOverlay;
public bool isActive;
}
private UIDocument _uiDocument;
private VisualElement _rootElement;
private VisualElement _cursorLayer;
private VisualElement _mainCursor;
public List<ScreenData> screens = new List<ScreenData>();
public string initialScreen = "MainMenu";
private readonly Dictionary<Type, BaseUIController> _controllers = new Dictionary<Type, BaseUIController>();
private readonly Stack<BaseUIController> _history = new Stack<BaseUIController>();
[Header("Cursor & Trail Settings")]
public Sprite trailSprite;
public float trailFadeSpeed = 3f;
public int trailCount = 15;
public float focusRadius = 500f;
[Header("References")]
[SerializeField] private InputReader inputReader;
public InputReader InputReader => inputReader;
private VisualElement _customCursor;
private List<VisualElement> _trailPool = new List<VisualElement>();
private int _trailIndex = 0;
[Header("Game Metadata")]
[SerializeField] private Texture2D gameIcon;
[Header("Editor Preview")]
[Range(0f, 1f)]
public float globalOpacity = 1f;
[Header("Cursor & Effects Settings")]
[SerializeField] private Sprite cursorSprite;
[SerializeField] private Sprite cursorTrailSprite;
[SerializeField, Range(10f, 150f)] private float cursorSize = 40f;
[SerializeField, Range(5, 50)] private int trailLength = 20;
[SerializeField, Range(1, 10)] private int trailSpacing = 2;
[SerializeField] private bool enableRipples = true;
[SerializeField] private Color rippleColor = new Color(1, 1, 1, 0.4f);
private Stack<string> _navigationStack = new Stack<string>();
private string _currentScreenName;
private VisualElement _lastHoveredElement;
[Header("UI Templates")]
[SerializeField] private VisualTreeAsset loginTemplate;
[SerializeField] private VisualTreeAsset mainMenuTemplate;
[SerializeField] private VisualTreeAsset lobbyTemplate;
[SerializeField] private VisualTreeAsset roomItemTemplate;
[SerializeField] private VisualTreeAsset profileTemplate;
[SerializeField] private VisualTreeAsset settingsTemplate;
[SerializeField] private VisualTreeAsset hudTemplate;
public bool isMainMenuActive = false;
private LoginController _loginController;
private MainMenuController _mainMenuController;
private LobbyController _lobbyController;
private SettingsController _settingsController;
private List<VisualElement> _trailSegments = new List<VisualElement>();
private List<Vector2> _posHistory = new List<Vector2>();
private Vector2 _lastMousePos;
private float _trailOpacity = 1f;
private bool _isSettingsOpen = false;
private const string UI_SCALE_KEY = "UIScale";
private void Awake()
{
if (Instance == null) Instance = this;
else { Destroy(gameObject); return; }
var myDoc = GetComponent<UIDocument>();
if (myDoc != null) myDoc.sortingOrder = 1000;
SetupCursor();
foreach (var s in screens)
if (Instance != null && Instance != this)
{
if (s.document != null) s.document.rootVisualElement.style.display = DisplayStyle.None;
Destroy(gameObject);
return;
}
ShowScreen(initialScreen);
Instance = this;
DontDestroyOnLoad(gameObject);
_uiDocument = GetComponent<UIDocument>();
UnityEngine.Cursor.visible = false;
ApplySavedUIScale();
}
private void SetupCursor()
public void OnGameStarted()
{
UIDocument doc = GetComponent<UIDocument>();
if (doc == null && screens.Count > 0) doc = screens[0].document;
if (doc == null) return;
_ = Push<HUDController>();
}
var root = doc.rootVisualElement;
_customCursor = new VisualElement();
_customCursor.style.width = 25; _customCursor.style.height = 25;
_customCursor.style.backgroundColor = Color.white;
_customCursor.style.borderTopLeftRadius = 13; _customCursor.style.borderTopRightRadius = 13;
_customCursor.style.borderBottomLeftRadius = 13; _customCursor.style.borderBottomRightRadius = 13;
_customCursor.style.position = Position.Absolute;
_customCursor.pickingMode = PickingMode.Ignore;
root.Add(_customCursor);
for (int i = 0; i < trailCount; i++)
public void OnBackToMenu()
{
var trail = new VisualElement();
trail.style.width = 20; trail.style.height = 20;
if (trailSprite != null)
_ = Push<MainMenuController>();
}
public void SetUIScale(float scale)
{
trail.style.backgroundImage = new StyleBackground(trailSprite);
trail.style.backgroundColor = Color.clear;
if (_uiDocument == null || _uiDocument.panelSettings == null) return;
// Unity UI Toolkit dùng panelSettings để điều khiển tỉ lệ
// Chúng ta thay đổi scale multiplier
_uiDocument.panelSettings.scale = scale;
PlayerPrefs.SetFloat(UI_SCALE_KEY, scale);
PlayerPrefs.Save();
}
private void ApplySavedUIScale()
{
float savedScale = PlayerPrefs.GetFloat(UI_SCALE_KEY, 1.0f);
SetUIScale(savedScale);
}
private void Start()
{
if (_uiDocument == null) _uiDocument = GetComponent<UIDocument>();
if (_uiDocument == null)
{
Debug.LogError("[UIManager] UIDocument component missing!");
return;
}
_rootElement = _uiDocument.rootVisualElement;
if (_rootElement == null)
{
Debug.LogError("[UIManager] Root VisualElement is null!");
return;
}
_cursorLayer = new VisualElement();
_cursorLayer.name = "CursorLayer";
_cursorLayer.style.position = Position.Absolute;
_cursorLayer.style.width = Length.Percent(100);
_cursorLayer.style.height = Length.Percent(100);
_cursorLayer.pickingMode = PickingMode.Ignore;
_rootElement.Add(_cursorLayer);
SetupVirtualCursor();
_rootElement.RegisterCallback<PointerDownEvent>(OnGlobalClick, TrickleDown.TrickleDown);
if (inputReader != null)
{
inputReader.OnToggleSettingsEvent += ToggleSettings;
inputReader.OnCancelEvent += HandleCancel;
}
#if UNITY_EDITOR
if (gameIcon == null)
{
var icons = PlayerSettings.GetIcons(NamedBuildTarget.Unknown, IconKind.Any);
if (icons != null && icons.Length > 0) gameIcon = icons[0];
}
#endif
InitializeControllers();
CheckLoginStatus();
}
private void CheckLoginStatus()
{
string savedName = PlayerPrefs.GetString("Username", "");
if (string.IsNullOrEmpty(savedName))
{
_ = Push<LoginController>();
}
else
{
trail.style.backgroundColor = new Color(1, 1, 1, 0.4f);
trail.style.borderTopLeftRadius = 10; trail.style.borderTopRightRadius = 10;
trail.style.borderBottomLeftRadius = 10; trail.style.borderBottomRightRadius = 10;
Debug.Log($"[UIManager] Welcome back, {savedName}!");
_ = Push<MainMenuController>();
}
trail.style.position = Position.Absolute;
trail.pickingMode = PickingMode.Ignore;
root.Add(trail);
_trailPool.Add(trail);
}
_customCursor.BringToFront();
public void OnLoginSuccess()
{
_ = Push<MainMenuController>();
}
private void OnDestroy()
{
if (inputReader != null)
{
inputReader.OnToggleSettingsEvent -= ToggleSettings;
inputReader.OnCancelEvent -= HandleCancel;
}
}
private void HandleCancel()
{
if (_isSettingsOpen) ToggleSettings();
}
public async void ToggleSettings()
{
if (_settingsController == null) return;
if (!_isSettingsOpen)
{
_isSettingsOpen = true;
_settingsController.Root.BringToFront();
_cursorLayer.BringToFront();
await _settingsController.PlayTransitionIn();
}
else
{
_isSettingsOpen = false;
await _settingsController.PlayTransitionOut();
}
}
private void Update()
{
Vector2 mousePos = Input.mousePosition;
bool isMainMenu = (_currentScreenName == "MainMenu");
bool restrictY = (isMainMenu && isMainMenuActive && !_isSettingsOpen);
float targetY = restrictY ? Screen.height / 2f : mousePos.y;
Vector2 uiPos = new Vector2(mousePos.x, Screen.height - targetY);
if (_history.Count > 0) _history.Peek().Update();
UpdateCursorAndTrail();
}
bool showCursor = !isMainMenu || _isSettingsOpen;
DisplayStyle cursorDisplay = showCursor ? DisplayStyle.Flex : DisplayStyle.None;
if (_customCursor != null)
private void SetupVirtualCursor()
{
_customCursor.style.display = cursorDisplay;
_customCursor.style.left = uiPos.x - 12.5f;
_customCursor.style.top = uiPos.y - 12.5f;
}
if (_cursorLayer == null) return;
if (_trailPool.Count > 0)
_cursorLayer.Clear();
_trailSegments.Clear();
_posHistory.Clear();
if (cursorTrailSprite != null)
{
var currentTrail = _trailPool[_trailIndex];
currentTrail.style.display = cursorDisplay;
currentTrail.style.left = uiPos.x - 10;
currentTrail.style.top = uiPos.y - 10;
currentTrail.style.opacity = 0.6f;
foreach(var t in _trailPool)
for (int i = 0; i < trailLength; i++)
{
float currentOp = t.style.opacity.value;
if (currentOp > 0) t.style.opacity = Mathf.Max(0, currentOp - Time.deltaTime * trailFadeSpeed);
else t.style.display = DisplayStyle.None;
var segment = new VisualElement();
segment.style.position = Position.Absolute;
segment.style.width = cursorSize;
segment.style.height = cursorSize;
segment.style.backgroundImage = new StyleBackground(Background.FromSprite(cursorTrailSprite));
float ratio = 1f - ((float)i / trailLength);
segment.style.opacity = 0f;
segment.style.scale = new StyleScale(new Scale(new Vector3(ratio, ratio, 1f)));
segment.style.translate = new StyleTranslate(new Translate(Length.Percent(-50), Length.Percent(-50)));
segment.pickingMode = PickingMode.Ignore;
_cursorLayer.Add(segment);
_trailSegments.Add(segment);
}
_trailIndex = (_trailIndex + 1) % _trailPool.Count;
}
HandleVirtualInput(uiPos);
_mainCursor = new VisualElement();
_mainCursor.style.position = Position.Absolute;
_mainCursor.style.width = cursorSize;
_mainCursor.style.height = cursorSize;
_mainCursor.style.backgroundImage = new StyleBackground(Background.FromSprite(cursorSprite != null ? cursorSprite : cursorTrailSprite));
_mainCursor.style.translate = new StyleTranslate(new Translate(Length.Percent(-50), Length.Percent(-50)));
_mainCursor.pickingMode = PickingMode.Ignore;
_cursorLayer.Add(_mainCursor);
if ((Input.GetKey(KeyCode.LeftControl) || Input.GetKey(KeyCode.RightControl)) && Input.GetKeyDown(KeyCode.O))
ToggleSettings();
Vector2 startPos = new Vector2(Input.mousePosition.x, Screen.height - Input.mousePosition.y);
_lastMousePos = startPos;
for (int i = 0; i < trailLength * trailSpacing + 1; i++) _posHistory.Add(startPos);
}
private void HandleVirtualInput(Vector2 uiPos)
private float GetCurrentScale()
{
UIDocument activeDoc = null;
var settings = screens.Find(s => s.screenName == "Settings");
if (_isSettingsOpen) activeDoc = settings.document;
else activeDoc = screens.Find(s => s.screenName == _currentScreenName)?.document;
if (activeDoc == null) return;
if (_uiDocument != null && _uiDocument.panelSettings != null)
return _uiDocument.panelSettings.scale;
return 1.0f;
}
VisualElement bestElement = null;
float minDistance = float.MaxValue;
var interactables = activeDoc.rootVisualElement.Query<VisualElement>()
.Where(e => e.focusable && e.pickingMode != PickingMode.Ignore).ToList();
foreach (var element in interactables)
private void OnGlobalClick(PointerDownEvent evt)
{
Rect worldBounds = element.worldBound;
float dist = Vector2.Distance(uiPos, worldBounds.center);
if (dist < minDistance && dist < focusRadius) {
minDistance = dist;
bestElement = element;
}
if (!enableRipples || _cursorLayer == null) return;
var ripple = new VisualElement();
ripple.style.position = Position.Absolute;
ripple.style.width = cursorSize;
ripple.style.height = cursorSize;
ripple.style.translate = new StyleTranslate(new Translate(Length.Percent(-50), Length.Percent(-50)));
var radius = new StyleLength(new Length(50, LengthUnit.Percent));
ripple.style.borderTopLeftRadius = radius;
ripple.style.borderTopRightRadius = radius;
ripple.style.borderBottomLeftRadius = radius;
ripple.style.borderBottomRightRadius = radius;
ripple.style.borderTopColor = rippleColor;
ripple.style.borderBottomColor = rippleColor;
ripple.style.borderLeftColor = rippleColor;
ripple.style.borderRightColor = rippleColor;
ripple.style.borderTopWidth = 2;
ripple.style.borderBottomWidth = 2;
ripple.style.borderLeftWidth = 2;
ripple.style.borderRightWidth = 2;
// PointerDownEvent.localPosition đã được Unity tự động scale theo Panel
ripple.style.left = evt.localPosition.x;
ripple.style.top = evt.localPosition.y;
ripple.pickingMode = PickingMode.Ignore;
_cursorLayer.Add(ripple);
// Correct Fluent API for PrimeTween
Tween.Custom(Vector3.one, Vector3.one * 2.5f, duration: 0.4f,
onValueChange: val => ripple.style.scale = new StyleScale(new Scale(val)),
ease: Ease.OutQuad);
Tween.Custom(1f, 0f, duration: 0.4f, onValueChange: val => ripple.style.opacity = val)
.OnComplete(() => ripple.RemoveFromHierarchy());
}
if (bestElement != _lastHoveredElement)
private void UpdateCursorAndTrail()
{
_lastHoveredElement?.RemoveFromClassList("hover");
bestElement?.AddToClassList("hover");
_lastHoveredElement = bestElement;
}
if (Input.GetMouseButtonDown(0) && _lastHoveredElement != null)
if (!Application.isFocused || _cursorLayer == null)
{
using (var clickEvent = ClickEvent.GetPooled()) {
clickEvent.target = _lastHoveredElement;
_lastHoveredElement.SendEvent(clickEvent);
}
}
if (_cursorLayer != null) _cursorLayer.style.display = DisplayStyle.None;
return;
}
// --- Editor Support Methods (Restored) ---
Vector3 mousePos = Input.mousePosition;
bool isMouseInWindow = mousePos.x >= 0 && mousePos.x <= Screen.width && mousePos.y >= 0 && mousePos.y <= Screen.height;
public void SyncScreens()
if (!isMouseInWindow)
{
foreach (var screen in screens)
_cursorLayer.style.display = DisplayStyle.None;
return;
}
_cursorLayer.style.display = DisplayStyle.Flex;
// QUAN TRỌNG: Chia tọa độ pixel cho scale của UI để có tọa độ local chính xác
float scale = GetCurrentScale();
Vector2 uiPos = new Vector2(mousePos.x / scale, (Screen.height - mousePos.y) / scale);
float mouseSpeed = Vector2.Distance(uiPos, _lastMousePos);
_lastMousePos = uiPos;
if (mouseSpeed > 0.1f) _trailOpacity = Mathf.MoveTowards(_trailOpacity, 1f, Time.deltaTime * 5f);
else _trailOpacity = Mathf.MoveTowards(_trailOpacity, 0f, Time.deltaTime * 3f);
_posHistory.Insert(0, uiPos);
if (_posHistory.Count > trailLength * trailSpacing + 1)
_posHistory.RemoveAt(_posHistory.Count - 1);
if (_mainCursor != null)
{
if (screen.document != null && screen.document.rootVisualElement != null)
_mainCursor.style.left = uiPos.x;
_mainCursor.style.top = uiPos.y;
}
for (int i = 0; i < _trailSegments.Count; i++)
{
screen.document.rootVisualElement.style.display =
screen.isActive ? DisplayStyle.Flex : DisplayStyle.None;
screen.document.rootVisualElement.style.opacity = globalOpacity;
int historyIndex = (i + 1) * trailSpacing;
if (historyIndex < _posHistory.Count)
{
_trailSegments[i].style.left = _posHistory[historyIndex].x;
_trailSegments[i].style.top = _posHistory[historyIndex].y;
float baseRatio = 1f - ((float)i / trailLength);
_trailSegments[i].style.opacity = baseRatio * 0.5f * _trailOpacity;
}
}
}
public void ShowOnly(string name)
private void InitializeControllers()
{
foreach (var screen in screens)
try
{
screen.isActive = (screen.screenName == name);
}
SyncScreens();
}
_mainMenuController = RegisterController<MainMenuController>(mainMenuTemplate);
if (_mainMenuController != null && gameIcon != null) _mainMenuController.SetGameIcon(gameIcon);
// --- Runtime Logic ---
_lobbyController = RegisterController<LobbyController>(lobbyTemplate);
if (_lobbyController != null) _lobbyController.SetRoomTemplate(roomItemTemplate);
public void ShowScreen(string name)
RegisterController<ProfileController>(profileTemplate);
_settingsController = RegisterController<SettingsController>(settingsTemplate);
RegisterController<HUDController>(hudTemplate);
_loginController = RegisterController<LoginController>(loginTemplate);
}
catch (Exception e)
{
var screen = screens.Find(s => s.screenName == name);
if (screen == null) return;
Debug.LogError($"[UIManager] Failed to initialize controllers: {e}");
}
}
if (!screen.isOverlay)
private T RegisterController<T>(VisualTreeAsset template) where T : BaseUIController
{
foreach(var s in screens) if(!s.isOverlay && s.document != null) s.document.rootVisualElement.style.display = DisplayStyle.None;
_navigationStack.Push(name);
_currentScreenName = name;
}
screen.document.rootVisualElement.style.display = DisplayStyle.Flex;
screen.isActive = true;
UnityEngine.Cursor.visible = false;
}
public void GoBack()
if (template == null)
{
if (_navigationStack.Count <= 1) return;
string current = _navigationStack.Pop();
var currentData = screens.Find(s => s.screenName == current);
if (currentData != null) currentData.document.rootVisualElement.style.display = DisplayStyle.None;
_currentScreenName = _navigationStack.Peek();
var prevData = screens.Find(s => s.screenName == _currentScreenName);
if (prevData != null) prevData.document.rootVisualElement.style.display = DisplayStyle.Flex;
Debug.LogWarning($"[UIManager] Template for {typeof(T).Name} is missing in Inspector.");
return null;
}
public void ToggleSettings()
if (_rootElement == null) return null;
VisualElement instance = null;
try
{
var settings = screens.Find(s => s.screenName == "Settings");
if (settings == null) return;
_isSettingsOpen = settings.document.rootVisualElement.style.display == DisplayStyle.None;
settings.document.rootVisualElement.style.display = _isSettingsOpen ? DisplayStyle.Flex : DisplayStyle.None;
if (_isSettingsOpen) settings.document.sortingOrder = 999;
instance = template.Instantiate();
}
catch (Exception e)
{
Debug.LogError($"[UIManager] Failed to instantiate template for {typeof(T).Name}: {e.Message}");
return null;
}
if (instance == null) return null;
instance.style.flexGrow = 1;
instance.style.position = Position.Absolute;
instance.style.width = Length.Percent(100);
instance.style.height = Length.Percent(100);
instance.style.display = DisplayStyle.None;
_rootElement.Add(instance);
if (_cursorLayer != null) _cursorLayer.BringToFront();
var controller = ScriptableObject.CreateInstance<T>();
controller.Initialize(instance, this);
_controllers[typeof(T)] = controller;
return controller;
}
public async Task Push<T>() where T : BaseUIController
{
if (!_controllers.TryGetValue(typeof(T), out var newScreen)) return;
if (_history.Count > 0 && _history.Peek() == newScreen) return;
if (_history.Count > 0) await _history.Peek().PlayTransitionOut();
_history.Push(newScreen);
await newScreen.PlayTransitionIn();
if (_cursorLayer != null) _cursorLayer.BringToFront();
}
public async Task Pop()
{
if (_history.Count <= 1) return;
await _history.Pop().PlayTransitionOut();
if (_history.Count > 0) await _history.Peek().PlayTransitionIn();
if (_cursorLayer != null) _cursorLayer.BringToFront();
}
}
}

View File

@@ -60,11 +60,11 @@ MonoBehaviour:
- folder: {fileID: 102900000, guid: 8c41df02b38b2ee40b792b146c0493f2, type: 3}
folderIcon: {fileID: 2800000, guid: 9687b8a9002844d4b8ece997ce390043, type: 3}
overlayIcon: {fileID: 0}
- folder: {fileID: 102900000, guid: 4e6e9b4a0c2e35242b749c3b025c2b6d, type: 3}
folderIcon: {fileID: 2800000, guid: 45c44e19279856a4084f599ece9e9f38, type: 3}
- folder: {fileID: 102900000, guid: 55d9223ee943a5248a49f0c45b440900, type: 3}
folderIcon: {fileID: 2800000, guid: f98ab23e70af0464ba10b820ef66cf70, type: 3}
overlayIcon: {fileID: 0}
- folder: {fileID: 102900000, guid: e4342b7ac2b8c524bbfd5ed650d13a32, type: 3}
folderIcon: {fileID: 2800000, guid: e73175098a6e2ea4db2ac2e6530f2b19, type: 3}
folderIcon: {fileID: 2800000, guid: cba11d42cc7f1fd45a740047c8016d44, type: 3}
overlayIcon: {fileID: 0}
- folder: {fileID: 102900000, guid: b7be1da6c24fb324cb1b67eb7a5e6426, type: 3}
folderIcon: {fileID: 2800000, guid: dc0e2c4d9ca1811469d02371b37c0693, type: 3}
@@ -72,3 +72,9 @@ MonoBehaviour:
- folder: {fileID: 102900000, guid: 00000000000000001000000000000000, type: 3}
folderIcon: {fileID: 2800000, guid: 615cb913a7bddfa49bcf0bef5dea245a, type: 3}
overlayIcon: {fileID: 0}
- folder: {fileID: 102900000, guid: 9d1a7116f40f1104f853146b8e5a2a3a, type: 3}
folderIcon: {fileID: 2800000, guid: 8e97b26161ff4e84aa195cf32afe6cd5, type: 3}
overlayIcon: {fileID: 0}
- folder: {fileID: 102900000, guid: d2a193aae7ad2c940be4fc9041026670, type: 3}
folderIcon: {fileID: 2800000, guid: 7ecaaef7f2ae9bb449e7e189dd9f8d4a, type: 3}
overlayIcon: {fileID: 0}

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 49cba557032e781419d81381bf53f535
guid: c2f5816569229d948ab054c5a0e7008a
folderAsset: yes
DefaultImporter:
externalObjects: {}

View File

@@ -0,0 +1,15 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 0551a27408b84c040a2e009ae17debde, type: 3}
m_Name: FirebaseConfig
m_EditorClassIdentifier: Assembly-CSharp::Hallucinate.UI.FirebaseConfig
baseUrl: https://hallucination-303-default-rtdb.asia-southeast1.firebasedatabase.app/

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: a32ff21294cb0854181fe2ea1602ab9f
guid: 987ed1314b9242c4d8c84deaf9bb8ea0
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000

View File

@@ -21,7 +21,7 @@ TextureImporter:
heightScale: 0.25
normalMapFilter: 0
flipGreenChannel: 0
isReadable: 0
isReadable: 1
streamingMipmaps: 0
streamingMipmapsPriority: 0
vTOnly: 0

View File

@@ -21,7 +21,7 @@ TextureImporter:
heightScale: 0.25
normalMapFilter: 0
flipGreenChannel: 0
isReadable: 0
isReadable: 1
streamingMipmaps: 0
streamingMipmapsPriority: 0
vTOnly: 0

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 381 KiB

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: e73175098a6e2ea4db2ac2e6530f2b19
guid: 7ecaaef7f2ae9bb449e7e189dd9f8d4a
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
@@ -43,7 +43,7 @@ TextureImporter:
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 2
spriteMode: 1
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
@@ -69,10 +69,10 @@ TextureImporter:
platformSettings:
- serializedVersion: 4
buildTarget: DefaultTexturePlatform
maxTextureSize: 128
maxTextureSize: 16384
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
textureCompression: 2
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
@@ -113,7 +113,7 @@ TextureImporter:
customData:
physicsShape: []
bones: []
spriteID:
spriteID: 5e97eb03825dee720800000000000000
internalID: 0
vertices: []
indices:

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 80 KiB

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 45c44e19279856a4084f599ece9e9f38
guid: f98ab23e70af0464ba10b820ef66cf70
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
@@ -43,7 +43,7 @@ TextureImporter:
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 2
spriteMode: 1
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
@@ -69,10 +69,10 @@ TextureImporter:
platformSettings:
- serializedVersion: 4
buildTarget: DefaultTexturePlatform
maxTextureSize: 128
maxTextureSize: 16384
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
textureCompression: 2
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
@@ -113,7 +113,7 @@ TextureImporter:
customData:
physicsShape: []
bones: []
spriteID:
spriteID: 5e97eb03825dee720800000000000000
internalID: 0
vertices: []
indices:

Binary file not shown.

After

Width:  |  Height:  |  Size: 399 KiB

View File

@@ -0,0 +1,130 @@
fileFormatVersion: 2
guid: 8e97b26161ff4e84aa195cf32afe6cd5
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 13
mipmaps:
mipMapMode: 0
enableMipMap: 0
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
flipGreenChannel: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
vTOnly: 0
ignoreMipmapLimit: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: 1
aniso: 1
mipBias: 0
wrapU: 1
wrapV: 1
wrapW: 0
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 1
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 8
textureShape: 1
singleChannelComponent: 0
flipbookRows: 1
flipbookColumns: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
ignorePngGamma: 0
applyGammaDecoding: 0
swizzle: 50462976
cookieLightType: 0
platformSettings:
- serializedVersion: 4
buildTarget: DefaultTexturePlatform
maxTextureSize: 16384
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 2
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 4
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 4
buildTarget: Android
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
customData:
physicsShape: []
bones: []
spriteID: 5e97eb03825dee720800000000000000
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
spriteCustomMetadata:
entries: []
nameFileIdTable: {}
mipmapLimitGroupName:
pSDRemoveMatte: 0
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 4e6e9b4a0c2e35242b749c3b025c2b6d
guid: 55d9223ee943a5248a49f0c45b440900
folderAsset: yes
DefaultImporter:
externalObjects: {}

Some files were not shown because too many files have changed in this diff Show More