Compare commits

...

19 Commits

Author SHA1 Message Date
2b22cc92a8 Readme添加语言badge
Readme排版修正
2024-01-24 17:02:48 +09:00
96914d39b0 Readme图片排版修改,日本語Readme追加 2024-01-24 13:29:42 +09:00
37c193ba6a 添加PlayMode一键初始化camera位置功能
修改PlayerCamera参数为private
2024-01-09 19:18:16 +09:00
173aff5137 Observation多处修复
Observation显示UI修正对应新的Rotation
修正targetState长度错误,优化TargetController的Play模式
修改TargetPosition坐标从TargetBlock坐标为Firebases坐标
修改45s超时动作从加载train scene为退出游戏
2024-01-05 03:46:52 +09:00
481794dcc3 修改面向方位Observation,删除TargetStates中的归属状态
修改对应上述Readme文件
2023-12-31 09:46:27 +09:00
142c0e44b5 Readme修正
Readme针对上一个commit进行修正,Onehot编码控制从MLAgentsCustomController转到CommonParameterContainer。
2023-12-31 09:16:18 +09:00
bf1d1d8d3b Onehot功能完善,修正
OneHot功能完善,更改TaySensor探测到Tag的index表示。与之前不通用!
修正PlayMode中的scenePrefabSet未定位错误
修正Raysensor中TagToInt不包含rayTagResult中的-1
2023-12-31 07:49:58 +09:00
f3c5f539ec first readme commit 2023-12-29 23:51:05 +09:00
96f297d114 V3.5 修正Level生成概率在Scene之间的传递方法,修正Level probability Panel在Train scene中不能继承StartScene数据问题和不修改LevelProbs的问题。 2023-11-17 15:44:22 +09:00
d83d026fea 修正Level生成概率在Scene之间的传递方法,修正Level probability Panel在Train scene中不能继承StartScene数据问题和不修改LevelProbs的问题。 2023-11-17 13:44:07 +09:00
c2eaa8cbfc 取消使用StartSceneData来跨Scene传输数据,改用CommonParameterContainer Singleton来统一保存所需数据。 2023-11-16 01:03:54 +09:00
726ce450ab 提高inAreaRewardDefault。
整理Script位置。
2023-11-15 16:48:33 +09:00
90cf429893 修复M键不能及时反映解锁Mouse 2023-11-05 01:29:09 +09:00
ba27cab015 CommonParameterContainer改为Singleton模式 2023-11-03 12:56:44 +09:00
779897c874 解决在commit 03267d2 中添加goto模式的facing reward未对play mode适配的问题。 2023-10-25 04:05:50 +09:00
9087a8c552 分离所有RewardFunction相关到单独的一个Script里。 2023-10-24 03:34:15 +09:00
6091dca65d 分离Parameter为Common Parameter和会随着游戏State改变的Parameter。
将不需要public的一些变量改为private。
2023-10-23 01:54:30 +09:00
6603b23eb2 向Train Mode中添加LevelPanel调整
创建UI滑动进入和收回动画控制
创建一个通用的LevelProbabilityPanel而不是Start页面专用
将AddEventTrigger作为Extension添加到EventTrigger上
修改LevelPanel的Material为UniversalBlur
2023-10-21 09:05:23 +09:00
39a7a340b8 修复Canvas大小变更时UI不随之移动错误。使用UIColorContainer来储存Color信息。
(cherry picked from commit 5ccaeefa5c)
2023-10-20 03:08:46 +09:00
67 changed files with 23545 additions and 35834 deletions

View File

@ -144,8 +144,10 @@ private void CalculateCurrentIncrease(bool moving)
private void Update() private void Update()
{ {
if (Input.GetKey(KeyCode.M)) if (Input.GetKeyDown(KeyCode.M))
{
_active = !_active; _active = !_active;
}
if (!_active) if (!_active)
{ {

View File

@ -1 +1 @@
{"count":1,"self":6.6978924,"total":6.7403838,"children":{"InitializeActuators":{"count":2,"self":0.002,"total":0.002,"children":null},"InitializeSensors":{"count":2,"self":0.001,"total":0.001,"children":null},"AgentSendState":{"count":96,"self":0.0014992999999999999,"total":0.010006899999999999,"children":{"CollectObservations":{"count":96,"self":0.0050103,"total":0.0050103,"children":null},"WriteActionMask":{"count":96,"self":0.0014992,"total":0.0014992,"children":null},"RequestDecision":{"count":96,"self":0.0019981,"total":0.0019981,"children":null}}},"DecideAction":{"count":96,"self":0.0029998,"total":0.0029998,"children":null},"AgentAct":{"count":96,"self":0.0259858,"total":0.0259858,"children":null}},"gauges":{},"metadata":{"timer_format_version":"0.1.0","start_time_seconds":"1696776760","unity_version":"2021.3.14f1","command_line_arguments":"C:\\Program Files\\Unity\\Hub\\Editor\\2021.3.14f1\\Editor\\Unity.exe -projectpath C:\\Users\\UCUNI\\OneDrive\\Unity\\ML-Agents\\Aimbot-ParallelEnv -useHub -hubIPC -cloudEnvironment production -licensingIpc LicenseClient-XEerV7kYNt9lW-ScfLTdo -hubSessionId d21180ac-2b2e-4464-bc29-90cd6d320fc3 -accessToken FUlk05mLlb2dcwVANd09HxpJmsCNwwFXO6GIY0FY5_c00ef","communication_protocol_version":"1.5.0","com.unity.ml-agents_version":"2.0.1","scene_name":"Play","end_time_seconds":"1696776767"}} {"count":1,"self":13.296357599999999,"total":13.6899074,"children":{"InitializeActuators":{"count":2,"self":0.0015034999999999998,"total":0.0015034999999999998,"children":null},"InitializeSensors":{"count":2,"self":0.0010003,"total":0.0010003,"children":null},"AgentSendState":{"count":433,"self":0.0045045,"total":0.2859497,"children":{"CollectObservations":{"count":433,"self":0.2078226,"total":0.2078226,"children":null},"WriteActionMask":{"count":433,"self":0.0009994,"total":0.0009994,"children":null},"RequestDecision":{"count":433,"self":0.0726232,"total":0.0726232,"children":null}}},"DecideAction":{"count":433,"self":0.0019984,"total":0.0019984,"children":null},"AgentAct":{"count":433,"self":0.1020973,"total":0.1020973,"children":null}},"gauges":{},"metadata":{"timer_format_version":"0.1.0","start_time_seconds":"1704690165","unity_version":"2021.3.14f1","command_line_arguments":"C:\\Program Files\\Unity\\Hub\\Editor\\2021.3.14f1\\Editor\\Unity.exe -projectpath C:\\Users\\UCUNI\\OneDrive\\Unity\\ML-Agents\\Aimbot-ParallelEnv -useHub -hubIPC -cloudEnvironment production -licensingIpc LicenseClient-bbQe3pofOXaeruEXc-2O8 -hubSessionId fa8ba95e-3ad3-4e58-bbf6-617d74b7cdd4 -accessToken dLDx_lE1nZ6RAtxwNKiPge42G5i8CvH-Sv_7EIEhm2000ef","communication_protocol_version":"1.5.0","com.unity.ml-agents_version":"2.0.1","scene_name":"Play","end_time_seconds":"1704690179"}}

View File

@ -1 +1 @@
{"count":1,"self":10.2447512,"total":10.2987626,"children":{"InitializeActuators":{"count":2,"self":0.0009994,"total":0.0009994,"children":null},"InitializeSensors":{"count":2,"self":0.00099859999999999988,"total":0.00099859999999999988,"children":null},"AgentSendState":{"count":169,"self":0.0025004,"total":0.009501299999999999,"children":{"CollectObservations":{"count":169,"self":0.0050025999999999994,"total":0.0050025999999999994,"children":null},"WriteActionMask":{"count":169,"self":0.0004994,"total":0.0004994,"children":null},"RequestDecision":{"count":169,"self":0.0014988999999999998,"total":0.0014988999999999998,"children":null}}},"DecideAction":{"count":169,"self":0.0025041,"total":0.0025041,"children":null},"AgentAct":{"count":169,"self":0.0400077,"total":0.0400077,"children":null}},"gauges":{},"metadata":{"timer_format_version":"0.1.0","start_time_seconds":"1696963654","unity_version":"2021.3.14f1","command_line_arguments":"C:\\Program Files\\Unity\\Hub\\Editor\\2021.3.14f1\\Editor\\Unity.exe -projectpath C:\\Users\\UCUNI\\OneDrive\\Unity\\ML-Agents\\Aimbot-ParallelEnv -useHub -hubIPC -cloudEnvironment production -licensingIpc LicenseClient-UCUNI -hubSessionId 7c3dcd5a-daae-43b1-a2e8-4bb346bbb4e5 -accessToken G6W4ifPeN-JJvIEsustzRofGrXpwOepV108yPK_cjPA00ef","communication_protocol_version":"1.5.0","com.unity.ml-agents_version":"2.0.1","scene_name":"StartScene","end_time_seconds":"1696963665"}} {"count":1,"self":103.5483392,"total":107.75784449999999,"children":{"InitializeActuators":{"count":12,"self":0.001004,"total":0.001004,"children":null},"InitializeSensors":{"count":12,"self":0,"total":0,"children":null},"AgentSendState":{"count":1424,"self":0.0280132,"total":2.6909213,"children":{"CollectObservations":{"count":8544,"self":2.640354,"total":2.640354,"children":null},"WriteActionMask":{"count":8544,"self":0.0060129,"total":0.0060129,"children":null},"RequestDecision":{"count":8544,"self":0.0165412,"total":0.0165412,"children":null}}},"DecideAction":{"count":1424,"self":0.0235409,"total":0.0235409,"children":null},"AgentAct":{"count":1424,"self":1.4940384,"total":1.4940384,"children":null}},"gauges":{},"metadata":{"timer_format_version":"0.1.0","start_time_seconds":"1704689262","unity_version":"2021.3.14f1","command_line_arguments":"C:\\Program Files\\Unity\\Hub\\Editor\\2021.3.14f1\\Editor\\Unity.exe -projectpath C:\\Users\\UCUNI\\OneDrive\\Unity\\ML-Agents\\Aimbot-ParallelEnv -useHub -hubIPC -cloudEnvironment production -licensingIpc LicenseClient-bbQe3pofOXaeruEXc-2O8 -hubSessionId fa8ba95e-3ad3-4e58-bbf6-617d74b7cdd4 -accessToken dLDx_lE1nZ6RAtxwNKiPge42G5i8CvH-Sv_7EIEhm2000ef","communication_protocol_version":"1.5.0","com.unity.ml-agents_version":"2.0.1","scene_name":"StartScene","end_time_seconds":"1704689369"}}

View File

@ -1 +1 @@
{"count":1,"self":66.9065984,"total":71.9882009,"children":{"InitializeActuators":{"count":16,"self":0.0009969,"total":0.0009969,"children":null},"InitializeSensors":{"count":16,"self":0.0009994,"total":0.0009994,"children":null},"AgentSendState":{"count":3334,"self":0.044007,"total":0.43848919999999997,"children":{"CollectObservations":{"count":26672,"self":0.3689863,"total":0.3689863,"children":null},"WriteActionMask":{"count":26672,"self":0.0044905,"total":0.0044905,"children":null},"RequestDecision":{"count":26672,"self":0.0210054,"total":0.0210054,"children":null}}},"DecideAction":{"count":3334,"self":0.0480142,"total":0.0480142,"children":null},"AgentAct":{"count":3334,"self":4.5931028,"total":4.5931029,"children":null}},"gauges":{"AKMAgent.CumulativeReward":{"count":18,"max":4761.187,"min":-3316.413,"runningAverage":119.63308,"value":4761.187,"weightedAverage":2609.449}},"metadata":{"timer_format_version":"0.1.0","start_time_seconds":"1697400022","unity_version":"2021.3.14f1","command_line_arguments":"C:\\Program Files\\Unity\\Hub\\Editor\\2021.3.14f1\\Editor\\Unity.exe -projectpath C:\\Users\\UCUNI\\OneDrive\\Unity\\ML-Agents\\Aimbot-ParallelEnv -useHub -hubIPC -cloudEnvironment production -licensingIpc LicenseClient-UCUNI -hubSessionId e4e811a4-b1b9-40c9-bb87-1f58481c4f0b -accessToken gZraEFpga1zyWWe2F_cgXvA55kRNGoKgEeraCZAmspA00ef","communication_protocol_version":"1.5.0","com.unity.ml-agents_version":"2.0.1","scene_name":"Train","end_time_seconds":"1697400094"}} {"count":1,"self":8.4565711999999991,"total":9.2154213,"children":{"InitializeActuators":{"count":12,"self":0.0009975,"total":0.0009975,"children":null},"InitializeSensors":{"count":12,"self":0.0010008999999999999,"total":0.0010008999999999999,"children":null},"AgentSendState":{"count":241,"self":0.0034963999999999998,"total":0.46725839999999996,"children":{"CollectObservations":{"count":1446,"self":0.460256,"total":0.460256,"children":null},"WriteActionMask":{"count":1446,"self":0.0010002,"total":0.0010002,"children":null},"RequestDecision":{"count":1446,"self":0.0025058,"total":0.0025058,"children":null}}},"DecideAction":{"count":241,"self":0.0050033,"total":0.0050033,"children":null},"AgentAct":{"count":241,"self":0.28359049999999997,"total":0.28359049999999997,"children":null}},"gauges":{},"metadata":{"timer_format_version":"0.1.0","start_time_seconds":"1704689378","unity_version":"2021.3.14f1","command_line_arguments":"C:\\Program Files\\Unity\\Hub\\Editor\\2021.3.14f1\\Editor\\Unity.exe -projectpath C:\\Users\\UCUNI\\OneDrive\\Unity\\ML-Agents\\Aimbot-ParallelEnv -useHub -hubIPC -cloudEnvironment production -licensingIpc LicenseClient-bbQe3pofOXaeruEXc-2O8 -hubSessionId fa8ba95e-3ad3-4e58-bbf6-617d74b7cdd4 -accessToken dLDx_lE1nZ6RAtxwNKiPge42G5i8CvH-Sv_7EIEhm2000ef","communication_protocol_version":"1.5.0","com.unity.ml-agents_version":"2.0.1","scene_name":"Train","end_time_seconds":"1704689387"}}

View File

@ -1005,8 +1005,8 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
m_Name: m_Name:
m_EditorClassIdentifier: m_EditorClassIdentifier:
m_Material: {fileID: 2100000, guid: f6d46f1e916b3486c90a448a441fac6a, type: 2} m_Material: {fileID: 0}
m_Color: {r: 1, g: 1, b: 1, a: 0.392} m_Color: {r: 1, g: 1, b: 1, a: 0}
m_RaycastTarget: 1 m_RaycastTarget: 1
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1 m_Maskable: 1

View File

@ -14,7 +14,7 @@ GameObject:
- component: {fileID: 5589415219770305708} - component: {fileID: 5589415219770305708}
- component: {fileID: 5589415219770305697} - component: {fileID: 5589415219770305697}
m_Layer: 5 m_Layer: 5
m_Name: SingleTargetLevelProbabilityPanel m_Name: SingleTargetProbabilityPanel
m_TagString: Untagged m_TagString: Untagged
m_Icon: {fileID: 0} m_Icon: {fileID: 0}
m_NavMeshLayer: 0 m_NavMeshLayer: 0
@ -60,8 +60,8 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
m_Name: m_Name:
m_EditorClassIdentifier: m_EditorClassIdentifier:
m_Material: {fileID: 0} m_Material: {fileID: 2100000, guid: f6d46f1e916b3486c90a448a441fac6a, type: 2}
m_Color: {r: 1, g: 1, b: 1, a: 0.392} m_Color: {r: 0.8862745, g: 0.8862745, b: 0.8862745, a: 1}
m_RaycastTarget: 1 m_RaycastTarget: 1
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1 m_Maskable: 1
@ -92,6 +92,8 @@ MonoBehaviour:
m_EditorClassIdentifier: m_EditorClassIdentifier:
singleLevelProbabilityPanel: {fileID: 6536015492050286218, guid: 81d4d787c82b5174caf00af00e9a3cd1, type: 3} singleLevelProbabilityPanel: {fileID: 6536015492050286218, guid: 81d4d787c82b5174caf00af00e9a3cd1, type: 3}
targetTitleText: {fileID: 8396012208200061614, guid: 8a180acb9a0ba8b4aacd888419f082ed, type: 3} targetTitleText: {fileID: 8396012208200061614, guid: 8a180acb9a0ba8b4aacd888419f082ed, type: 3}
singleLevelPanelsObjs: []
singleLevelPanels: []
--- !u!114 &5589415219770305697 --- !u!114 &5589415219770305697
MonoBehaviour: MonoBehaviour:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0

View File

@ -0,0 +1,42 @@
%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: 3fef23608d0a5d242a781d8ca28ed23b, type: 3}
m_Name: UIColors
m_EditorClassIdentifier:
normal:
text:
serializedVersion: 2
rgba: 4293717228
bg:
serializedVersion: 2
rgba: 16777215
highLight:
text:
serializedVersion: 2
rgba: 3861457193
bg:
serializedVersion: 2
rgba: 1744830463
pressed:
text:
serializedVersion: 2
rgba: 4026531840
bg:
serializedVersion: 2
rgba: 2701131775
disabled:
text:
serializedVersion: 2
rgba: 1354020020
bg:
serializedVersion: 2
rgba: 16777215

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: c75edf08eba25eb40896936387c07e89
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

View File

@ -488,11 +488,11 @@ MonoBehaviour:
m_GameObject: {fileID: 237721381} m_GameObject: {fileID: 237721381}
m_Enabled: 1 m_Enabled: 1
m_EditorHideFlags: 0 m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 0195eb0e734c7e747bb7f8b669c80fe5, type: 3} m_Script: {fileID: 11500000, guid: 44d064c42ee56374e94671f4f9f9d650, type: 3}
m_Name: m_Name:
m_EditorClassIdentifier: m_EditorClassIdentifier:
singleTargetLevelProbabilityPanel: {fileID: 5589415219770305710, guid: 324d8e84c24cdd04ba087763705db1d0, type: 3} singleTargetLevelProbabilityPanel: {fileID: 5589415219770305710, guid: 324d8e84c24cdd04ba087763705db1d0, type: 3}
startSceneData: {fileID: 1072325866} startSceneData: {fileID: 0}
targetLevelProbabilityPanel: [] targetLevelProbabilityPanel: []
--- !u!1 &294404779 --- !u!1 &294404779
GameObject: GameObject:
@ -942,7 +942,7 @@ RectTransform:
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 1} m_AnchorMin: {x: 0, y: 1}
m_AnchorMax: {x: 0, y: 1} m_AnchorMax: {x: 0, y: 1}
m_AnchoredPosition: {x: -61, y: 215} m_AnchoredPosition: {x: 411.6, y: -24.599976}
m_SizeDelta: {x: 200, y: 50} m_SizeDelta: {x: 200, y: 50}
m_Pivot: {x: 0.5, y: 0.5} m_Pivot: {x: 0.5, y: 0.5}
--- !u!114 &431112176 --- !u!114 &431112176
@ -1763,6 +1763,88 @@ CanvasRenderer:
m_PrefabAsset: {fileID: 0} m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 852513428} m_GameObject: {fileID: 852513428}
m_CullTransparentMesh: 1 m_CullTransparentMesh: 1
--- !u!1 &968918527
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 968918529}
- component: {fileID: 968918528}
m_Layer: 0
m_Name: CommonParameterContainer
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!114 &968918528
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 968918527}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 34839c2831b759d4a8347ab655b00f36, type: 3}
m_Name:
m_EditorClassIdentifier:
lockMouse: 0
damage: 50
fireRate: 0.5
timeLimit: 30
lockCameraX: 0
lockCameraY: 1
oneHotRayTag: 1
spawnAgentInAllMap: 1
spinRecordMax: 40
spinPenaltyThreshold: 10
facingInviewEnemyDisCOEF: 0.5
group1Tag: Player
group2Tag: Enemy
hitTargetRewardDefault: 25
killTargetEnemyRewardDefault: 25
inAreaRewardDefault: 25
freeTimeBonusPerSec: 1
targetTimeBonusPerSec: 0.5
areaTimeBonusPerSec: 0.2
distanceReward: 50
facingTargetReward: 10
goWinRewardDefault: 999
attackWinRewardDefault: 999
defenceWinRewardDefault: 999
freeWinRewardDefault: 999
nonReward: -1
loseReward: -999
shootReward: -0.5
hitNonTargetReward: -5
killNonTargetReward: -5
shootWithoutReadyReward: -1.15
killBonusReward: 0
facingReward: 5
shootTargetAreaReward: 10
movePenalty: 0.1
spinPenalty: 0.08
mousePenalty: 0.06
scenePrefabSet: {fileID: 11400000, guid: 6ebbd27eb466c4a41bd2584c1b9c2e1f, type: 2}
--- !u!4 &968918529
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 968918527}
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: 0}
m_RootOrder: 5
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &1064099385 --- !u!1 &1064099385
GameObject: GameObject:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@ -2044,107 +2126,6 @@ RectTransform:
m_AnchoredPosition: {x: -100, y: -7} m_AnchoredPosition: {x: -100, y: -7}
m_SizeDelta: {x: 160, y: 30} m_SizeDelta: {x: 160, y: 30}
m_Pivot: {x: 0.5, y: 0.5} m_Pivot: {x: 0.5, y: 0.5}
--- !u!1 &1072325866
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1072325868}
- component: {fileID: 1072325867}
m_Layer: 0
m_Name: StartSceneDataTransfer
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!114 &1072325867
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1072325866}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 52ba7faaa6129cf418f26c5933d4ea0e, type: 3}
m_Name:
m_EditorClassIdentifier:
gameMode: 0
scenePrefabSet: {fileID: 11400000, guid: 6ebbd27eb466c4a41bd2584c1b9c2e1f, type: 2}
attackProb: 0
attackLevelProbs: []
gotoProb: 0
gotoLevelProbs: []
defenceProb: 0
defenceLevelProbs: []
--- !u!4 &1072325868
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1072325866}
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: 0}
m_RootOrder: 4
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &1129476375
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1129476376}
- component: {fileID: 1129476377}
m_Layer: 5
m_Name: UIColorContainer
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &1129476376
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1129476375}
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: 1144208399}
m_RootOrder: 10
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: 0, y: 0}
m_SizeDelta: {x: 100, y: 100}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!114 &1129476377
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1129476375}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 3fef23608d0a5d242a781d8ca28ed23b, type: 3}
m_Name:
m_EditorClassIdentifier:
--- !u!1 &1144208395 --- !u!1 &1144208395
GameObject: GameObject:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@ -2247,7 +2228,6 @@ RectTransform:
- {fileID: 1614969824} - {fileID: 1614969824}
- {fileID: 1899537997} - {fileID: 1899537997}
- {fileID: 237721382} - {fileID: 237721382}
- {fileID: 1129476376}
m_Father: {fileID: 0} m_Father: {fileID: 0}
m_RootOrder: 0 m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
@ -2298,7 +2278,7 @@ Transform:
m_ConstrainProportionsScale: 0 m_ConstrainProportionsScale: 0
m_Children: [] m_Children: []
m_Father: {fileID: 0} m_Father: {fileID: 0}
m_RootOrder: 5 m_RootOrder: 4
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &1273196676 --- !u!1 &1273196676
GameObject: GameObject:
@ -2623,7 +2603,6 @@ MonoBehaviour:
m_EditorClassIdentifier: m_EditorClassIdentifier:
waitTimeLimit: 45 waitTimeLimit: 45
sceneLoaderObj: {fileID: 1206568295} sceneLoaderObj: {fileID: 1206568295}
startSceneDataObj: {fileID: 1072325866}
targetLevelProbabilityPanelOBJ: {fileID: 237721381} targetLevelProbabilityPanelOBJ: {fileID: 237721381}
messageTextObj: {fileID: 294404781} messageTextObj: {fileID: 294404781}
waitTimeTextObj: {fileID: 431112176} waitTimeTextObj: {fileID: 431112176}
@ -2645,10 +2624,10 @@ MonoBehaviour:
gotoButton: {fileID: 1614969818} gotoButton: {fileID: 1614969818}
freeButton: {fileID: 1899537996} freeButton: {fileID: 1899537996}
animeDuration: 0.2 animeDuration: 0.2
mixDestination: {x: -85, y: 29, z: 0} animeMoveXDistance: 5
attackDestination: {x: -100, y: 0, z: 0} animeMoveYDistance: 10
gotoDestination: {x: -115, y: -29, z: 0} animeScaleX: 3
freeDestination: {x: -130, y: -58, z: 0} animeScaleY: 3
maskScaleX: 1 maskScaleX: 1
maskScaleY: 0.4 maskScaleY: 0.4
--- !u!114 &1432557595 --- !u!114 &1432557595
@ -2670,32 +2649,9 @@ MonoBehaviour:
unclickableButton: unclickableButton:
- {fileID: 850190065} - {fileID: 850190065}
- {fileID: 546575679} - {fileID: 546575679}
normalTextColor:
serializedVersion: 2
rgba: 4293717228
normalBGColor:
serializedVersion: 2
rgba: 16777215
highLightTextColor:
serializedVersion: 2
rgba: 3861457193
highLightBGColor:
serializedVersion: 2
rgba: 1744830463
pressedTextColor:
serializedVersion: 2
rgba: 4026531840
pressedBGColor:
serializedVersion: 2
rgba: 2701131775
disableTextColor:
serializedVersion: 2
rgba: 1354020020
disableBGColor:
serializedVersion: 2
rgba: 16777215
colorChangeSpeed: 0.1 colorChangeSpeed: 0.1
clickable: 1 clickable: 1
uiColor: {fileID: 11400000, guid: c75edf08eba25eb40896936387c07e89, type: 2}
--- !u!1 &1575146385 --- !u!1 &1575146385
GameObject: GameObject:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@ -2729,9 +2685,9 @@ RectTransform:
m_Father: {fileID: 1144208399} m_Father: {fileID: 1144208399}
m_RootOrder: 2 m_RootOrder: 2
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 0.5} m_AnchorMin: {x: 0, y: 1}
m_AnchorMax: {x: 0.5, y: 0.5} m_AnchorMax: {x: 0, y: 1}
m_AnchoredPosition: {x: 0, y: 0} m_AnchoredPosition: {x: 50, y: -50}
m_SizeDelta: {x: 100, y: 100} m_SizeDelta: {x: 100, y: 100}
m_Pivot: {x: 0.5, y: 0.5} m_Pivot: {x: 0.5, y: 0.5}
--- !u!1 &1614969818 --- !u!1 &1614969818
@ -3403,7 +3359,7 @@ RectTransform:
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 1} m_AnchorMin: {x: 0, y: 1}
m_AnchorMax: {x: 0, y: 1} m_AnchorMax: {x: 0, y: 1}
m_AnchoredPosition: {x: -372, y: 211} m_AnchoredPosition: {x: 100.6, y: -28.6}
m_SizeDelta: {x: 200, y: 50} m_SizeDelta: {x: 200, y: 50}
m_Pivot: {x: 0.5, y: 0.5} m_Pivot: {x: 0.5, y: 0.5}
--- !u!114 &2145851918 --- !u!114 &2145851918

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,15 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
public static class EventTriggerExtensions
{
public static void AddEventTrigger(this EventTrigger trigger, EventTriggerType type, UnityEngine.Events.UnityAction<BaseEventData> action)
{
EventTrigger.Entry entry = new EventTrigger.Entry();
entry.eventID = type;
entry.callback.AddListener(action);
trigger.triggers.Add(entry);
}
}

View File

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

View File

@ -0,0 +1,11 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public static class Vector3PositionExtensions
{
public static Vector3 FixCanvas(this Vector3 position,Vector3 originalVanvas,Vector3 nowVanvas)
{
return position + nowVanvas - originalVanvas;
}
}

View File

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

View File

@ -2,7 +2,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine; using UnityEngine;
public static class targetTypeExtensions public static class TargetTypeExtensions
{ {
public static int ToIndex(this Targets targetType) public static int ToIndex(this Targets targetType)
{ {

View File

@ -5,14 +5,7 @@
public class AgentController : MonoBehaviour public class AgentController : MonoBehaviour
{ {
public GameObject parameterContainerObj; [SerializeField] public Camera fpsCam;
public GameObject environmentObj;
public GameObject enemyContainerObj;
public GameObject sceneBlockContainerObj;
public GameObject environmentUIControlObj;
public GameObject targetControllerObj;
public GameObject HUDObj;
public Camera fpsCam;
[Header("GetAxis() Simulate")] [Header("GetAxis() Simulate")]
public float moveSpeed = 9.0f; public float moveSpeed = 9.0f;
@ -25,48 +18,36 @@ public class AgentController : MonoBehaviour
public float mouseYSensitivity = 200; public float mouseYSensitivity = 200;
public float yRotation = 0.1f;//定义一个浮点类型的量记录围绕X轴旋转的角度 public float yRotation = 0.1f;//定义一个浮点类型的量记录围绕X轴旋转的角度
private List<float> spinRecord = new List<float>();
private bool lockMouse; private bool lockMouse;
private float damage;
private float fireRate; private float fireRate;
private bool lockCameraX; private bool lockCameraX;
private bool lockCameraY; private bool lockCameraY;
// environment // environment
private float lastShootTime = 0.0f; public float lastShootTime = 0.0f;
private int enemyKillCount = 0; public int enemyKillCount = 0;
private Vector3 killEnemyPosition; public Vector3 killEnemyPosition;
public bool defaultTPCamera = true; public bool defaultTPCamera = true;
[System.NonSerialized] public bool gunReadyToggle = true; [System.NonSerialized] public bool gunReadyToggle = true;
private string myTag = ""; public string myTag = "";
private float lastEnemyFacingDistance = 0f; // record last enemy facing minimum distance
private float lastTargetFacingDistance = 0f; // record last target facing minimum distance
// scripts
private RaySensors raySensors;
private CharacterController playerController; private CharacterController playerController;
private ParameterContainer paramContainer; private CommonParameterContainer commonPramCon;
private SceneBlockContainer blockContainer;
private TargetController targetCon;
private void Start() private void Start()
{ {
// initialize scripts // initialize scripts
paramContainer = parameterContainerObj.GetComponent<ParameterContainer>(); commonPramCon = CommonParameterContainer.Instance;
blockContainer = sceneBlockContainerObj.GetComponent<SceneBlockContainer>(); playerController = transform.GetComponent<CharacterController>();
targetCon = targetControllerObj.GetComponent<TargetController>();
raySensors = GetComponent<RaySensors>();
playerController = this.transform.GetComponent<CharacterController>();
// initialize Environment parameters // initialize Environment parameters
lockMouse = paramContainer.lockMouse; lockMouse = commonPramCon.lockMouse;
damage = paramContainer.damage; fireRate = commonPramCon.fireRate;
fireRate = paramContainer.fireRate; lockCameraX = commonPramCon.lockCameraX;
lockCameraX = paramContainer.lockCameraX; lockCameraY = commonPramCon.lockCameraY;
lockCameraY = paramContainer.lockCameraY;
// initialize remainTime // initialize remainTime
// this agent's tag // this agent's tag
@ -191,234 +172,7 @@ public void CameraControl(float Mouse_X, float Mouse_Y)
#endregion Camera Control #endregion Camera Control
#region Reward Functions // Got Kill point
// ballistic 射击弹道处理并返回获得reward
private float Ballistic(int shootState)
{
Vector3 point = new Vector3(fpsCam.pixelWidth / 2, fpsCam.pixelHeight / 2, 0);//发射位置
Ray ray = fpsCam.ScreenPointToRay(point);
RaycastHit hit;
// Debug.DrawRay(centerRay.origin, centerRay.direction * 100, Color.blue);
//按下鼠标左键
if (shootState != 0 && gunReadyToggle == true)
{
lastShootTime = Time.time;
if (Physics.Raycast(ray, out hit, 100))
{
if (hit.collider.tag != myTag && hit.collider.tag != "Wall" && hit.collider.tag != "Untagged")
{
// kill enemy
GameObject gotHitObj = hit.transform.gameObject;//获取受到Ray撞击的对象
gotHitObj.GetComponent<States>().ReactToHit(damage, gameObject);
shootState = 0;
return targetCon.HitEnemyReward(gotHitObj.transform.position);
}
}
if (targetCon.targetTypeInt == (int)Targets.Attack)
{
// while if attack mode
float targetDis = Vector3.Distance(blockContainer.nowBlock.transform.position, transform.position);
if (targetDis <= raySensors.viewDistance)
{
// Debug.DrawRay(new Vector3(0,0,0), viewPoint, Color.red);
if (Vector3.Distance(ray.origin + (ray.direction * targetDis), blockContainer.nowBlock.transform.position) <= blockContainer.nowBlock.firebasesAreaDiameter / 2)
{
// im shooting at target but didn't hit enemy
// Debug.DrawRay(centerRay.origin, viewPoint-centerRay.origin, Color.blue);
return paramContainer.shootTargetAreaReward;
}
}
}
shootState = 0;
return paramContainer.shootReward;
}
else if (shootState != 0 && gunReadyToggle == false)
{
// shoot without ready
shootState = 0;
return paramContainer.shootWithoutReadyReward;
}
else
{
// do not shoot
shootState = 0;
return paramContainer.nonReward;
}
}
private float FacingReward()
{
float nowReward = 0;
bool isFacingtoEnemy = false;
float enemyFacingDistance = 0f;
Vector3 screenCenter = new Vector3(fpsCam.pixelWidth / 2, fpsCam.pixelHeight / 2, 0);
Vector3 screenLeft = new Vector3(0, fpsCam.pixelHeight / 2, 0);
Ray centerRay = fpsCam.ScreenPointToRay(screenCenter);
Ray leftRay = fpsCam.ScreenPointToRay(screenLeft);
// target fireBaseArea Position, turen y to camera's y
Vector3 fireBaseArea = blockContainer.nowBlock.fireBasesAreaObj.transform.position;
fireBaseArea.y = fpsCam.transform.position.y;
// my position, turn y to camera's y
// Debug.DrawRay(fpsCam.transform.position, centerRay.direction * 100, Color.blue);
Vector3 myposition = transform.position;
myposition.y = fpsCam.transform.position.y;
// Target to Agent distance
//Debug.DrawLine(fireBaseArea, myposition, Color.red);
float targetDis = Vector3.Distance(fireBaseArea, myposition);
// point in centerRay and leftRay which distance is targetDis from camera center
Vector3 pointInCenterRay = fpsCam.transform.position + (centerRay.direction * targetDis);
Vector3 pointInLeftRay = fpsCam.transform.position + (leftRay.direction * targetDis);
// center of screen to target's distance
// Debug.DrawLine(pointInCenterRay, fireBaseArea,Color.green);
float camCenterToTarget = Vector3.Distance(pointInCenterRay, fireBaseArea);
// left of screen to target's distance
// Debug.DrawLine(pointInLeftRay, pointInCenterRay, Color.yellow);
float camCenterToViewEdge = Vector3.Distance(pointInLeftRay, pointInCenterRay);
switch (targetCon.targetTypeInt)
{
case (int)Targets.Free:
//free mode
RaycastHit hit;
if (Physics.Raycast(centerRay, out hit, 100))
{
// facing to an enemy
if (hit.collider.tag != myTag && hit.collider.tag != "Wall")
{
nowReward = paramContainer.facingReward;
isFacingtoEnemy = true;
}
}
if (raySensors.inViewEnemies.Count > 0 && !isFacingtoEnemy)
{
// have enemy in view
List<float> projectionDis = new List<float>();
foreach (GameObject theEnemy in raySensors.inViewEnemies)
{
// for each enemy in view
Vector3 projection = Vector3.Project(theEnemy.transform.position - transform.position, (centerRay.direction * 10));
Vector3 verticalToRay = transform.position + projection - theEnemy.transform.position;
projectionDis.Add(verticalToRay.magnitude);
// Debug.Log("enemy!" + verticalToRay.magnitude);
// Debug.DrawRay(transform.position, (centerRay.direction * 100), Color.cyan);
// Debug.DrawRay(transform.position, theEnemy.transform.position - transform.position, Color.yellow);
// Debug.DrawRay(transform.position, projection, Color.blue);
// Debug.DrawRay(theEnemy.transform.position, verticalToRay, Color.magenta);
}
enemyFacingDistance = projectionDis.Min();
if (enemyFacingDistance <= lastEnemyFacingDistance)
{
// closing to enemy
nowReward = 1 / MathF.Sqrt(paramContainer.facingInviewEnemyDisCOEF * enemyFacingDistance + 0.00001f);
}
else
{
nowReward = 0;
}
// enemy in view Reward
lastEnemyFacingDistance = enemyFacingDistance;
if (nowReward >= paramContainer.facingReward) nowReward = paramContainer.facingReward; // limit
if (nowReward <= -paramContainer.facingReward) nowReward = -paramContainer.facingReward; // limit
// Debug.Log("ninimum = " + nowReward);
}
break;
case (int)Targets.Attack:
// attack mode
if (targetDis <= raySensors.viewDistance)
{
// Debug.DrawRay(new Vector3(0,0,0), viewPoint, Color.red);
// while center of screen between target's distance is lower than firebasesAreaDiameter
// while facing to target
if (camCenterToTarget <= blockContainer.nowBlock.firebasesAreaDiameter / 2)
{
// Debug.DrawRay(centerRay.origin, viewPoint-centerRay.origin, Color.blue);
nowReward = paramContainer.facingReward;
}
else
{
// while not facing to target
nowReward = (lastTargetFacingDistance - camCenterToTarget) * paramContainer.facingTargetReward;
}
}
// update lastTargetFacingDistance
lastTargetFacingDistance = camCenterToTarget;
break;
case (int)Targets.Go:
// goto mode
if (camCenterToTarget <= camCenterToViewEdge)
{
// fireArea is in view
nowReward = paramContainer.facingReward;
}
else
{
nowReward = 0;
}
break;
default:
Debug.LogError("Wrong target type");
break;
}
return nowReward;
}
public float RewardCalculate(float sceneReward, float mouseX, float movement, int shootState)
{
float epreward = 0f;
// 击杀reward判断
if (enemyKillCount > 0)
{
for (int i = 0; i < enemyKillCount; i++)
{
// get
epreward += targetCon.KillReward(killEnemyPosition);
}
enemyKillCount = 0;
}
else
{
enemyKillCount = 0;
}
// 射击动作reward判断
epreward += Ballistic(shootState) + sceneReward;
// facing reward
epreward += FacingReward();
// Penalty
// spin penalty
spinRecord.Add(mouseX);
if (spinRecord.Count >= paramContainer.spinRecordMax)
{
spinRecord.RemoveAt(0);
}
float spinPenaltyReward = Math.Abs(spinRecord.ToArray().Sum() * paramContainer.spinPenalty);
if (spinPenaltyReward >= paramContainer.spinPenaltyThreshold)
{
epreward -= spinPenaltyReward;
}
else
{
epreward -= Math.Abs(mouseX) * paramContainer.mousePenalty;
}
// move penalty
if (movement != 0)
{
epreward -= paramContainer.movePenalty;
}
return epreward;
}
#endregion Reward Functions
// GotKill 获得击杀时用于被呼出
public void KillRecord(Vector3 killEnemyPosition) public void KillRecord(Vector3 killEnemyPosition)
{ {
enemyKillCount += 1; enemyKillCount += 1;

View File

@ -2,9 +2,9 @@
public class EnemyContainer : MonoBehaviour public class EnemyContainer : MonoBehaviour
{ {
public GameObject enemyPrefab; [SerializeField] public GameObject enemyPrefab;
public GameObject environmentObj; [SerializeField] private GameObject environmentObj;
public GameObject targetControllerObj; [SerializeField] private GameObject targetControllerObj;
private TargetController targetCon; private TargetController targetCon;

View File

@ -0,0 +1,121 @@
using System;
using System.Collections.Generic;
using TMPro;
using UnityEngine;
public class CommonParameterContainer : Singleton<CommonParameterContainer>
{
[Header("Env")]
public bool lockMouse = false;
public float damage = 50; // damage to enemy
public float fireRate = 0.5f;
public int timeLimit = 30;
public bool lockCameraX = false;
public bool lockCameraY = true;
public bool oneHotRayTag = true;
public bool spawnAgentInAllMap = true;
public int spinRecordMax = 40;
public float spinPenaltyThreshold = 10;
public float facingInviewEnemyDisCOEF = 0.5f;
public string group1Tag = "Player";
public string group2Tag = "Enemy";
[Header("Dynamic Defaut Rewards")]
//[Tooltip("Hit Enemy reward")]
//public float hitRewardDefault = 60.0f;
[Tooltip("Free mode Hit Enemy reward")]
public float hitTargetRewardDefault = 25f;
//[Tooltip("Enemy down reward")]
//public float killRewardDefault = 60.0f;
[Tooltip("Enemy down in area Reward")]
public float killTargetEnemyRewardDefault = 25f;
[Tooltip("stay in firebasesArea reward")]
public float inAreaRewardDefault = 25.0f;
[Tooltip("free left time bonus reward. ALLR + leftTime * r")]
public float freeTimeBonusPerSec = 1.0f;
[Tooltip("target left time bonus reward. ALLR + leftTime * r")]
public float targetTimeBonusPerSec = 0.5f;
[Tooltip("in area left time bonus reward. ALLR + leftTime * r")]
public float areaTimeBonusPerSec = 0.2f;
[Tooltip("distance reward reward = r*(1-(nowDis/startDis))")]
public float distanceReward = 50.0f;
[Tooltip("facing to Target distance reward reward = r*(1-(nowDis/startDis))")]
public float facingTargetReward = 10.0f;
[Space(10)]
[Tooltip("Goto Win reward")]
public float goWinRewardDefault = 999f;
[Tooltip("Attack Win reward")]
public float attackWinRewardDefault = 999f;
[Tooltip("Defence Win reward")]
public float defenceWinRewardDefault = 999f;
[Tooltip("free Win reward")]
public float freeWinRewardDefault = 999f;
[Header("Static Rewards")]
[Tooltip("Nothing happened reward")]
public float nonReward = -1f;
[Tooltip("Episode Lose reward")]
public float loseReward = -999f;
[Tooltip("Agent Do shoot action reward")]
public float shootReward = -0.5f;
[Tooltip("Hit Not target Enemy reward")]
public float hitNonTargetReward = -5f;
[Tooltip("Not Target Enemy down reward")]
public float killNonTargetReward = -5f;
[Tooltip("Agent Do shoot action but gun is not read")]
public float shootWithoutReadyReward = -1.15f;
[Tooltip("Kill bonus reward stack to nothing happend reward")]
public float killBonusReward = 0.0f;
[Tooltip("Facing to enemy's reward")]
public float facingReward = 5f;
[Tooltip("Shoot at target area but didn't hit enemy")]
public float shootTargetAreaReward = 10f;
[Header("Penalty Rewards")]
[Tooltip("move Penalty Reward")]
public float movePenalty = 0.1f;
[Tooltip("spiiiiiiin Panalty Reward")]
public float spinPenalty = 0.08f;
[Tooltip("while move mouse a little bit's penalty")]
public float mousePenalty = 0.06f;
public SceneBlocksSet scenePrefabSet;
[NonSerialized] public int gameMode; // 0 = trainning mode, 1 = play mode
[NonSerialized] public float attackProb = 0f;
[NonSerialized] public float gotoProb = 0f;
[NonSerialized] public float defenceProb = 0f;
public Dictionary<Targets, List<float>> levelProbs = new Dictionary<Targets, List<float>>();
protected override void Awake()
{
base.Awake();
scenePrefabSet.InitializeSceneBlocksSet();
InitializeLevelProbs();
}
private void Start()
{
Instance.KeepThroughSceneChange();
}
// Initialize Common Parameters
private void InitializeLevelProbs()
{
for(int i = 0; i< scenePrefabSet.targetLevels.Length; i++)
{
Targets nowTarget = scenePrefabSet.targets[i];
levelProbs[nowTarget] = new List<float>();
float levelNum = scenePrefabSet.GetLevelNumber(nowTarget);
float averageProbability = 1f / levelNum;
float lastLevelProbability = 1f - averageProbability * (levelNum - 1);
for (int j = 0; j < levelNum-1; j++)
{
levelProbs[nowTarget].Add(averageProbability);
}
levelProbs[nowTarget].Add(lastLevelProbability);
}
}
}

View File

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

View File

@ -7,19 +7,18 @@
public class MLAgentsCustomController : Agent public class MLAgentsCustomController : Agent
{ {
public GameObject paramContainerObj; [SerializeField] private GameObject paramContainerObj;
public GameObject targetControllerObj; [SerializeField] private GameObject targetControllerObj;
public GameObject environmentUIObj; [SerializeField] private GameObject environmentUIObj;
public GameObject sideChannelObj; [SerializeField] private GameObject sideChannelObj;
public GameObject hudUIObj; [SerializeField] private GameObject worldUIControllerObj;
[SerializeField] private GameObject hudObj;
[Header("Env")]
public bool oneHotRayTag = true;
// script // script
private AgentController agentController; private AgentController agentController;
private ParameterContainer paramContainer; private ParameterContainer paramContainer;
private CommonParameterContainer commonParamCon;
private TargetController targetController; private TargetController targetController;
private EnvironmentUIControl envUIController; private EnvironmentUIControl envUIController;
private HUDController hudController; private HUDController hudController;
@ -27,42 +26,41 @@ public class MLAgentsCustomController : Agent
private RaySensors raySensors; private RaySensors raySensors;
private MessageBoxController messageBoxController; private MessageBoxController messageBoxController;
private AimBotSideChannelController sideChannelController; private AimBotSideChannelController sideChannelController;
private WorldUIController worldUICon;
private RewardFunction rewardFunction;
// observation // observation
private float[] myObserve = new float[4]; private float[] myObserve = new float[5];
private float[] rayTagResult; private float[] rayTagResult;
private float[] rayTagResultOnehot; private float[] rayTagResultOnehot;
private float[] rayDisResult; private float[] rayDisResult;
private float[] targetStates;
private float remainTime; private float remainTime;
private float inAreaState; private float inFireBaseState;
private int finishedState; private int endTypeInt;
private int step = 0;
private int EP = 0;
private void Start() private void Start()
{ {
agentController = transform.GetComponent<AgentController>(); agentController = transform.GetComponent<AgentController>();
raySensors = transform.GetComponent<RaySensors>(); raySensors = transform.GetComponent<RaySensors>();
paramContainer = paramContainerObj.GetComponent<ParameterContainer>(); paramContainer = paramContainerObj.GetComponent<ParameterContainer>();
commonParamCon = CommonParameterContainer.Instance;
targetController = targetControllerObj.GetComponent<TargetController>(); targetController = targetControllerObj.GetComponent<TargetController>();
envUIController = environmentUIObj.GetComponent<EnvironmentUIControl>(); envUIController = environmentUIObj.GetComponent<EnvironmentUIControl>();
hudController = hudUIObj.GetComponent<HUDController>(); hudController = hudObj.GetComponent<HUDController>();
targetUIController = hudUIObj.GetComponent<TargetUIController>(); targetUIController = hudObj.GetComponent<TargetUIController>();
messageBoxController = hudUIObj.GetComponent<MessageBoxController>(); messageBoxController = hudObj.GetComponent<MessageBoxController>();
sideChannelController = sideChannelObj.GetComponent<AimBotSideChannelController>(); sideChannelController = sideChannelObj.GetComponent<AimBotSideChannelController>();
rewardFunction = gameObject.GetComponent<RewardFunction>();
worldUICon = worldUIControllerObj.GetComponent<WorldUIController>();
} }
#region On episode begin function
public override void OnEpisodeBegin() public override void OnEpisodeBegin()
{ {
step = 0;
agentController.UpdateLockMouse(); agentController.UpdateLockMouse();
paramContainer.ResetTimeBonusReward(); paramContainer.ResetTimeBonusReward();
if (paramContainer.gameMode == 0) if (commonParamCon.gameMode == 0)
{ {
// train mode // train mode
Debug.Log("MLAgentCustomController.OnEpisodeBegin: train mode start"); Debug.Log("MLAgentCustomController.OnEpisodeBegin: train mode start");
@ -72,7 +70,7 @@ public override void OnEpisodeBegin()
{ {
Debug.Log("MLAgentCustomController.OnEpisodeBegin: play mode start"); Debug.Log("MLAgentCustomController.OnEpisodeBegin: play mode start");
// play mode // play mode
targetController.PlayInitialize(); targetController.PlayModeInitialize();
// reset target UI // reset target UI
targetUIController.ClearGamePressed(); targetUIController.ClearGamePressed();
} }
@ -85,10 +83,6 @@ public override void OnEpisodeBegin()
raySensors.UpdateRayInfo(); // update raycast raySensors.UpdateRayInfo(); // update raycast
} }
#endregion On episode begin function
#region Observation sensor function
public override void CollectObservations(VectorSensor sensor) public override void CollectObservations(VectorSensor sensor)
{ {
//List<float> enemyLDisList = RaySensors.enemyLDisList;// All Enemy Lside Distances //List<float> enemyLDisList = RaySensors.enemyLDisList;// All Enemy Lside Distances
@ -97,35 +91,45 @@ public override void CollectObservations(VectorSensor sensor)
myObserve[1] = transform.localPosition.y / raySensors.viewDistance; myObserve[1] = transform.localPosition.y / raySensors.viewDistance;
myObserve[2] = transform.localPosition.z / raySensors.viewDistance; myObserve[2] = transform.localPosition.z / raySensors.viewDistance;
myObserve[3] = transform.eulerAngles.y / 360f;**/ myObserve[3] = transform.eulerAngles.y / 360f;**/
float obsNum = 0f;
float angleInRadians = transform.eulerAngles.y * Mathf.Deg2Rad;
myObserve[0] = transform.localPosition.x; myObserve[0] = transform.localPosition.x;
myObserve[1] = transform.localPosition.y; myObserve[1] = transform.localPosition.y;
myObserve[2] = transform.localPosition.z; myObserve[2] = transform.localPosition.z;
myObserve[3] = transform.eulerAngles.y / 36f; myObserve[3] = MathF.Sin(angleInRadians);
rayTagResult = raySensors.rayTagResult;// 探测用RayTag结果 float[](raySensorNum,1) myObserve[4] = MathF.Cos(angleInRadians);
rayTagResultOnehot = raySensors.rayTagResultOneHot.ToArray(); // 探测用RayTagonehot结果 List<int>[](raySensorNum*Tags,1) rayTagResult = raySensors.rayTagResult;// 探测用RayTag类型结果 float[](raySensorNum,1)
rayDisResult = raySensors.rayDisResult; // 探测用RayDis结果 float[](raySensorNum,1) rayTagResultOnehot = raySensors.rayTagResultOneHot; // 探测用RayTagonehot结果 List<int>[](raySensorNum*Tags,1)
targetStates = targetController.targetState; // (6) targettype, target x,y,z, firebasesAreaDiameter rayDisResult = raySensors.rayDisResult; // 探测用RayDis距离结果 float[](raySensorNum,1)
remainTime = targetController.leftTime; remainTime = targetController.leftTime;
inAreaState = targetController.GetInAreaState(); inFireBaseState = targetController.GetInAreaState();
agentController.UpdateGunState(); agentController.UpdateGunState();
//float[] focusEnemyObserve = RaySensors.focusEnemyInfo;// 最近的Enemy情报 float[](3,1) MinEnemyIndex,x,z //float[] focusEnemyObserve = RaySensors.focusEnemyInfo;// 最近的Enemy情报 float[](3,1) MinEnemyIndex,x,z
//sensor.AddObservation(allEnemyNum); // 敌人数量 int //sensor.AddObservation(allEnemyNum); // 敌人数量 int
sensor.AddObservation(targetStates);// (6) targettype, target x,y,z, firebasesAreaDiameter sensor.AddObservation(targetController.targetState);// (5) targettype, target x,y,z, firebasesAreaDiameter
sensor.AddObservation(inAreaState); // (1) sensor.AddObservation(inFireBaseState); // (1)
sensor.AddObservation(remainTime); // (1) sensor.AddObservation(remainTime); // (1)
sensor.AddObservation(agentController.gunReadyToggle); // (1) save gun is ready? sensor.AddObservation(agentController.gunReadyToggle); // (1) save gun is ready?
sensor.AddObservation(myObserve); // (4)自机位置xyz+朝向 float[](4,1) sensor.AddObservation(myObserve); // (5)自机位置xyz+朝向 float[](5,1)
if (oneHotRayTag) // count observation number
obsNum = targetController.targetState.Length+1+1+1+myObserve.Length;
Debug.Log(obsNum);
if (commonParamCon.oneHotRayTag)
{ {
sensor.AddObservation(rayTagResultOnehot); // 探测用RayTag结果 float[](raySensorNum,1) sensor.AddObservation(rayTagResultOnehot); // 探测用RayTag结果 float[](raySensorNum,1)
obsNum += rayTagResultOnehot.Length;
} }
else else
{ {
sensor.AddObservation(rayTagResult); sensor.AddObservation(rayTagResult);
obsNum += rayTagResult.Length;
} }
sensor.AddObservation(rayDisResult); // 探测用RayDis结果 float[](raySensorNum,1) Debug.Log(obsNum);
envUIController.UpdateStateText(targetStates, inAreaState, remainTime, agentController.gunReadyToggle, myObserve, rayTagResultOnehot, rayDisResult); sensor.AddObservation(rayDisResult); // 探测用RayDis距离结果 float[](raySensorNum,1)
obsNum += rayDisResult.Length;
envUIController.UpdateStateText(targetController.targetState, inFireBaseState, remainTime, agentController.gunReadyToggle, myObserve, rayTagResultOnehot, rayDisResult);
Debug.Log(obsNum);
/*foreach(float aaa in rayDisResult) /*foreach(float aaa in rayDisResult)
{ {
Debug.Log(aaa); Debug.Log(aaa);
@ -136,10 +140,6 @@ public override void CollectObservations(VectorSensor sensor)
//sensor.AddObservation(remainTime); // RemainTime int //sensor.AddObservation(remainTime); // RemainTime int
} }
#endregion Observation sensor function
#region Action received function
public override void OnActionReceived(ActionBuffers actionBuffers) public override void OnActionReceived(ActionBuffers actionBuffers)
{ {
//获取输入 //获取输入
@ -158,27 +158,27 @@ public override void OnActionReceived(ActionBuffers actionBuffers)
//判断结束 //判断结束
float sceneReward = 0f; float sceneReward = 0f;
float endReward = 0f; float endReward = 0f;
(finishedState, sceneReward, endReward) = targetController.CheckOverAndRewards(); (endTypeInt, sceneReward, endReward) = rewardFunction.CheckOverAndRewards();
float nowRoundReward = agentController.RewardCalculate(sceneReward + endReward, Mouse_X, Math.Abs(vertical) + Math.Abs(horizontal), mouseShoot); float nowReward = rewardFunction.RewardCalculate(sceneReward + endReward, Mouse_X, Math.Abs(vertical) + Math.Abs(horizontal), mouseShoot);
if (hudController.chartOn) if (hudController.chartOn)
{ {
envUIController.UpdateChart(nowRoundReward); envUIController.UpdateChart(nowReward);
} }
else else
{ {
envUIController.RemoveChart(); envUIController.RemoveChart();
} }
//Debug.Log("reward = " + nowRoundReward); worldUICon.UpdateChart(targetController.targetType, endTypeInt);
if (finishedState != (int)TargetController.EndType.Running) //Debug.Log("reward = " + nowReward);
if (endTypeInt != (int)TargetController.EndType.Running)
{ {
// Win or lose Finished // Win or lose Finished
Debug.Log("Finish reward = " + nowRoundReward); Debug.Log("Finish reward = " + nowReward);
EP += 1; string targetString = Enum.GetName(typeof(Targets), targetController.targetType);
string targetString = Enum.GetName(typeof(Targets), targetController.targetTypeInt); switch (endTypeInt)
switch (finishedState)
{ {
case (int)TargetController.EndType.Win: case (int)TargetController.EndType.Win:
sideChannelController.SendSideChannelMessage("Result",targetString+ "|Win"); sideChannelController.SendSideChannelMessage("Result", targetString + "|Win");
messageBoxController.PushMessage( messageBoxController.PushMessage(
new List<string> { "Game Win" }, new List<string> { "Game Win" },
new List<string> { "green" }); new List<string> { "green" });
@ -195,21 +195,16 @@ public override void OnActionReceived(ActionBuffers actionBuffers)
Debug.LogWarning("TypeError"); Debug.LogWarning("TypeError");
break; break;
} }
SetReward(nowRoundReward); SetReward(nowReward);
EndEpisode(); EndEpisode();
} }
else else
{ {
// game not over yet // game not over yet
step += 1;
} }
SetReward(nowRoundReward); SetReward(nowReward);
} }
#endregion Action received function
#region Heuristic function
public override void Heuristic(in ActionBuffers actionsOut) public override void Heuristic(in ActionBuffers actionsOut)
{ {
//-------------------BUILD //-------------------BUILD
@ -267,6 +262,4 @@ public override void Heuristic(in ActionBuffers actionsOut)
//continuousActions[2] = timeLimit; //continuousActions[2] = timeLimit;
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^continuous-Control^^^^^^^^^^^^^^^^^^^^^^ //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^continuous-Control^^^^^^^^^^^^^^^^^^^^^^
} }
#endregion Heuristic function
} }

View File

@ -3,110 +3,16 @@
public class ParameterContainer : MonoBehaviour public class ParameterContainer : MonoBehaviour
{ {
public GameObject targetConObj; [SerializeField] private GameObject targetConObj;
public GameObject blockConObj; [SerializeField] private GameObject blockConObj;
public GameObject agentObj; [SerializeField] private GameObject agentObj;
public GameObject hudObj; [SerializeField] private GameObject hudObj;
private TargetController targetCon; private TargetController targetCon;
private SceneBlockContainer blockCont; private SceneBlockContainer blockCont;
private StartSeneData startSceneData; private CommonParameterContainer commonParamCont;
private MessageBoxController messageCon;
private float agentDistance;
private int agentInArea; private int agentInArea;
[Header("Env")]
public bool lockMouse = false;
public float damage = 50; // damage to enemy
public float fireRate = 0.5f;
public int timeLimit = 30;
public bool lockCameraX = false;
public bool lockCameraY = true;
public bool spawnAgentInAllMap = true;
public int spinRecordMax = 40;
public float spinPenaltyThreshold = 10;
public float facingInviewEnemyDisCOEF = 0.5f;
[Header("Dynamic Defaut Rewards")]
//[Tooltip("Hit Enemy reward")]
//public float hitRewardDefault = 60.0f;
[Tooltip("Free mode Hit Enemy reward")]
public float hitTargetRewardDefault = 25f;
//[Tooltip("Enemy down reward")]
//public float killRewardDefault = 60.0f;
[Tooltip("Enemy down in area Reward")]
public float killTargetEnemyRewardDefault = 25f;
[Tooltip("stay in firebasesArea reward")]
public float inAreaRewardDefault = 12f;
[Tooltip("free left time bonus reward. ALLR + leftTime * r")]
public float freeTimeBonusPerSec = 1.0f;
[Tooltip("target left time bonus reward. ALLR + leftTime * r")]
public float targetTimeBonusPerSec = 0.5f;
[Tooltip("in area left time bonus reward. ALLR + leftTime * r")]
public float areaTimeBonusPerSec = 0.2f;
[Tooltip("distance reward reward = r*(1-(nowDis/startDis))")]
public float distanceReward = 50.0f;
[Tooltip("facing to Target distance reward reward = r*(1-(nowDis/startDis))")]
public float facingTargetReward = 10.0f;
[Space(10)]
[Tooltip("Goto Win reward")]
public float goWinRewardDefault = 999f;
[Tooltip("Attack Win reward")]
public float attackWinRewardDefault = 999f;
[Tooltip("Defence Win reward")]
public float defenceWinRewardDefault = 999f;
[Tooltip("free Win reward")]
public float freeWinRewardDefault = 999f;
[Header("Static Rewards")]
[Tooltip("Nothing happened reward")]
public float nonReward = -1f;
[Tooltip("Episode Lose reward")]
public float loseReward = -999f;
[Tooltip("Agent Do shoot action reward")]
public float shootReward = -0.5f;
[Tooltip("Hit Not target Enemy reward")]
public float hitNonTargetReward = -5f;
[Tooltip("Not Target Enemy down reward")]
public float killNonTargetReward = -5f;
[Tooltip("Agent Do shoot action but gun is not read")]
public float shootWithoutReadyReward = -1.15f;
[Tooltip("Kill bonus reward stack to nothing happend reward")]
public float killBonusReward = 0.0f;
[Tooltip("Facing to enemy's reward")]
public float facingReward = 5f;
[Tooltip("Shoot at target area but didn't hit enemy")]
public float shootTargetAreaReward = 10f;
[Header("Penalty Rewards")]
[Tooltip("move Penalty Reward")]
public float movePenalty = 0.1f;
[Tooltip("spiiiiiiin Panalty Reward")]
public float spinPenalty = 0.08f;
[Tooltip("while move mouse a little bit's penalty")]
public float mousePenalty = 0.06f;
[Header("Dynamic Rewards")] [Header("Dynamic Rewards")]
[Tooltip("Free mode Hit Enemy reward")] [Tooltip("Free mode Hit Enemy reward")]
public float hitTargetReward = 60.0f; public float hitTargetReward = 60.0f;
@ -130,63 +36,45 @@ public class ParameterContainer : MonoBehaviour
[Tooltip("free Win reward")] [Tooltip("free Win reward")]
public float freeWinReward = 50.0f; public float freeWinReward = 50.0f;
[Tooltip("Scene Prefab Set")]
public SceneBlocksSet scenePrefabSet;
private float targetTimeBonus = 0f; private float targetTimeBonus = 0f;
private float areaTimeBonus = 0f; private float areaTimeBonus = 0f;
private float freeTimeBonus = 0f; private float freeTimeBonus = 0f;
private float targetInAreaTime = 0f; private float targetInAreaTime = 0f;
private float lastFrameTime = 0f; private float lastFrameTime = 0f;
[System.NonSerialized] public int gameMode; // 0 = trainning mode, 1 = play mode private float areaTimeBonusPerSec;
[System.NonSerialized] public float attackProb = 0f; private float freeTimeBonusPerSec;
[System.NonSerialized] public List<float> attackLevelProbs = new List<float>(); private float targetTimeBonusPerSec;
[System.NonSerialized] public float gotoProb = 0f; private int timeLimit = 30;
[System.NonSerialized] public List<float> gotoLevelProbs = new List<float>();
[System.NonSerialized] public float defenceProb = 0f;
[System.NonSerialized] public List<float> defenceLevelProbs = new List<float>();
private void Start() private void Start()
{ {
targetCon = targetConObj.GetComponent<TargetController>(); targetCon = targetConObj.GetComponent<TargetController>();
blockCont = blockConObj.GetComponent<SceneBlockContainer>(); blockCont = blockConObj.GetComponent<SceneBlockContainer>();
messageCon = hudObj.GetComponent<MessageBoxController>(); commonParamCont = CommonParameterContainer.Instance;
areaTimeBonusPerSec = commonParamCont.areaTimeBonusPerSec;
freeTimeBonusPerSec = commonParamCont.freeTimeBonusPerSec;
targetTimeBonusPerSec = commonParamCont.targetTimeBonusPerSec;
timeLimit = commonParamCont.timeLimit;
areaTimeBonus = areaTimeBonusPerSec * timeLimit; areaTimeBonus = areaTimeBonusPerSec * timeLimit;
freeTimeBonus = freeTimeBonusPerSec * timeLimit; freeTimeBonus = freeTimeBonusPerSec * timeLimit;
targetTimeBonus = targetTimeBonusPerSec * timeLimit; targetTimeBonus = targetTimeBonusPerSec * timeLimit;
try
{ // Win Rewards
// try get start scene data goWinReward = commonParamCont.goWinRewardDefault;
startSceneData = GameObject.Find("StartSceneDataTransfer").GetComponent<StartSeneData>(); attackWinReward = commonParamCont.attackWinRewardDefault;
messageCon.PushMessage( defenceWinReward = commonParamCont.defenceWinRewardDefault;
new List<string> { "ParameterContainer:", "StartSceneDataTransfer found!" }, freeWinReward = commonParamCont.freeWinRewardDefault;
new List<string> { "green", "white" });
}
catch
{
// if not found, find dummy StartSeneData
startSceneData = GameObject.Find("StartSceneDataTransferDummy").GetComponent<StartSeneData>();
messageCon.PushMessage(
new List<string> { "ParameterContainer:", "StartSceneDataTransfer not found!Use Dummy." },
new List<string> { "orange" });
}
gameMode = startSceneData.gameMode;
attackProb = startSceneData.attackProb;
attackLevelProbs = startSceneData.attackLevelProbs;
gotoProb = startSceneData.gotoProb;
gotoLevelProbs = startSceneData.gotoLevelProbs;
defenceProb = startSceneData.defenceProb;
defenceLevelProbs = startSceneData.defenceLevelProbs;
scenePrefabSet = startSceneData.scenePrefabSet;
} }
private void Update() private void Update()
{ {
// get target distance and in area // get target distance and in area
if (targetCon.targetTypeInt is (int)Targets.Go or (int)Targets.Attack) if (targetCon.targetType is Targets.Go or Targets.Attack)
{ {
(agentDistance, agentInArea) = blockCont.GetAgentTargetDistanceAndInside(agentObj.transform.position); (_, agentInArea) = blockCont.GetAgentTargetDistanceAndInside(agentObj.transform.position);
// attack goto or defence target // attack goto or defence target
if (agentInArea == 1) if (agentInArea == 1)
{ {
@ -206,15 +94,9 @@ private void Update()
targetTimeBonus = targetTimeBonusPerSec * targetCon.leftTime; targetTimeBonus = targetTimeBonusPerSec * targetCon.leftTime;
} }
hitTargetReward = hitTargetRewardDefault + targetTimeBonus; hitTargetReward = commonParamCont.hitTargetRewardDefault + targetTimeBonus;
killTargetEnemyReward = killTargetEnemyRewardDefault + targetTimeBonus; killTargetEnemyReward = commonParamCont.killTargetEnemyRewardDefault + targetTimeBonus;
inAreaReward = inAreaRewardDefault + areaTimeBonus; inAreaReward = commonParamCont.inAreaRewardDefault + areaTimeBonus;
// Win Rewards
goWinReward = goWinRewardDefault;
attackWinReward = attackWinRewardDefault;
defenceWinReward = defenceWinRewardDefault;
freeWinReward = freeWinRewardDefault;
} }
public void ResetTimeBonusReward() public void ResetTimeBonusReward()

View File

@ -6,11 +6,11 @@
public class RaySensors : MonoBehaviour public class RaySensors : MonoBehaviour
{ {
public Camera agentCam; [SerializeField] private Camera agentCam;
public Camera TPSCam; [SerializeField] private Camera TPSCam;
public Material lineMeterial; [SerializeField] private Material lineMeterial;
public GameObject rayInfoPrefab; [SerializeField] private GameObject rayInfoPrefab;
public GameObject agentCanvas; [SerializeField] private GameObject agentCanvas;
[SerializeField, Range(0, 500)] public float viewDistance = 100; // how long the ray can detect [SerializeField, Range(0, 500)] public float viewDistance = 100; // how long the ray can detect
@ -30,7 +30,7 @@ public class RaySensors : MonoBehaviour
[Header("RayCastResult")] [Header("RayCastResult")]
public float[] rayTagResult; public float[] rayTagResult;
public List<float> rayTagResultOneHot; public float[] rayTagResultOneHot;
public float[] rayDisResult; public float[] rayDisResult;
[System.NonSerialized] public int totalRayNum; [System.NonSerialized] public int totalRayNum;
@ -49,6 +49,7 @@ private void Start()
totalRayNum = halfOuterRayNum * 2 + focusRayNum; totalRayNum = halfOuterRayNum * 2 + focusRayNum;
rayTagResult = new float[totalRayNum]; rayTagResult = new float[totalRayNum];
rayDisResult = new float[totalRayNum]; rayDisResult = new float[totalRayNum];
rayTagResultOneHot = new float[totalRayNum*ObjectTags.Tags.Count];
linesOBJ = new GameObject[totalRayNum]; linesOBJ = new GameObject[totalRayNum];
lineRenderers = new LineRenderer[totalRayNum]; lineRenderers = new LineRenderer[totalRayNum];
rayInfoOBJ = new GameObject[totalRayNum]; rayInfoOBJ = new GameObject[totalRayNum];
@ -70,85 +71,60 @@ private void Start()
} }
} }
public int TagToInt(string tag) private void SingleRaycastUpdate(Ray ray,int rayIndex)
{
switch (tag)
{
case "Wall":
return 1;
default:
if (tag != myTag)
{
return 2;
}
return 0;
}
}
private void SingleRaycastUpdate(Ray ray, LineRenderer lineRenderer, RayInfoUI rayInfoUI, out float rayTagResult, out float rayDisResult)
{ {
// get Raycast hit infomation and return Tag and distance // get Raycast hit infomation and return Tag and distance
RaycastHit nowHit; RaycastHit nowHit;
Color rayColor = Color.cyan; Color rayColor = Color.gray;
float lineLength = viewDistance; float lineLength = viewDistance;
string rayInfoText = ""; string rayInfoText = "";
Vector3 rayInfoPosition; Vector3 rayInfoPosition;
if (Physics.Raycast(ray, out nowHit, viewDistance)) // 若在viewDistance范围内有碰撞 if (Physics.Raycast(ray, out nowHit, viewDistance)) // 若在viewDistance范围内有碰撞
{ {
rayInfoText = nowHit.collider.tag; // Tag
rayTagResult = TagToInt(rayInfoText); string thisTag = nowHit.collider.tag;
rayTagResultOneHot.AddRange(oneHotTags.Encoder(rayInfoText)); // result update
rayDisResult = nowHit.distance; rayTagResult[rayIndex] = ObjectTags.TagToInt(thisTag);
lineLength = rayDisResult; rayDisResult[rayIndex] = nowHit.distance;
rayInfoText += "\n" + Convert.ToString(rayDisResult); int oneHotIndex = rayIndex * ObjectTags.Tags.Count + ObjectTags.TagToInt(thisTag);
// rayDisResult = rayDisResult / viewDistance; // Normalization! rayTagResultOneHot[oneHotIndex] = 1f;
// 输出log if (rayTagResult[rayIndex] == ObjectTags.TagToInt("Enemy"))
switch (rayTagResult)
{ {
case 1:// Wall inViewEnemies.Add(nowHit.transform.gameObject);
rayColor = Color.white;
break;
case 2: // Enemy
rayColor = Color.red;
inViewEnemies.Add(nowHit.transform.gameObject);
break;
case -1: // Hit Nothing
rayColor = Color.gray;
break;
default: // default,got wrong
rayColor = Color.cyan;
break;
} }
// ingame info update
lineLength = nowHit.distance;
rayInfoText = thisTag + "\n" + Convert.ToString(nowHit.distance);
rayColor = ObjectTags.TagToCololr(thisTag);
} }
else // 若在viewDistance范围无碰撞 else // 若在viewDistance范围无碰撞
{ {
rayTagResultOneHot.AddRange(oneHotTags.Encoder()); // Result update
rayTagResult = -1f; // rayTagResultOneHot keep zero
rayDisResult = -1f; rayTagResult[rayIndex] = -1;
//输出log rayDisResult[rayIndex] = -1;
//Debug.Log(0); // Info
//Debug.Log(0); rayInfoText = "Empty";
} }
// draw Info In Game
rayInfoPosition = ray.origin + (ray.direction * lineLength); rayInfoPosition = ray.origin + (ray.direction * lineLength);
if (showInGameRay) if (showInGameRay)
{ {
DrawLine(ray, lineLength, lineRenderer, rayColor); DrawLine(ray, lineLength, lineRenderers[rayIndex], rayColor);
} }
else else
{ {
TurnOffLine(lineRenderer, rayColor); TurnOffLine(lineRenderers[rayIndex], rayColor);
} }
// drawRay in game // drawRay in game
if (showInGameRayInfo) rayInfoUI.UpdateInfo(rayInfoText, rayInfoPosition, rayColor, TPSCam); if (showInGameRayInfo) rayInfoUIs[rayIndex].UpdateInfo(rayInfoText, rayInfoPosition, rayColor, TPSCam);
// Show log // Show log
if (showDebugRay) Debug.DrawRay(ray.origin, ray.direction * viewDistance, rayColor); // drawRay in debug if (showDebugRay) Debug.DrawRay(ray.origin, ray.direction * viewDistance, rayColor); // drawRay in debug
// Debug.Log(ray.origin + ray.direction); // Debug.Log(ray.origin + ray.direction);
// Debug.Log(rayTagResult); // Debug.Log(thisRayTagResult);
// Debug.Log(tagToInt(nowHit.collider.tag)); // Debug.Log(tagToInt(nowHit.collider.thisTag));
} }
private void DrawLine(Ray ray, float lineLength, LineRenderer lineRenderer, Color lineColor) private void DrawLine(Ray ray, float lineLength, LineRenderer lineRenderer, Color lineColor)
@ -177,24 +153,31 @@ public void UpdateRayInfo()
float focusREdge = agentCam.pixelWidth * (1 + focusRange) / 2; float focusREdge = agentCam.pixelWidth * (1 + focusRange) / 2;
float camPixelHeight = agentCam.pixelHeight; float camPixelHeight = agentCam.pixelHeight;
inViewEnemies.Clear(); inViewEnemies.Clear();
rayTagResultOneHot.Clear(); ClearResult();
for (int i = 0; i < halfOuterRayNum; i++) // create left outside rays; 0 ~ focusLeftEdge for (int i = 0; i < halfOuterRayNum; i++) // create left outside rays; 0 ~ focusLeftEdge
{ {
Vector3 point = new Vector3(i * focusLEdge / (halfOuterRayNum - 1), camPixelHeight / 2, 0); Vector3 point = new Vector3(i * focusLEdge / (halfOuterRayNum - 1), camPixelHeight / 2, 0);
Ray nowRay = agentCam.ScreenPointToRay(point); Ray nowRay = agentCam.ScreenPointToRay(point);
SingleRaycastUpdate(nowRay, lineRenderers[i], rayInfoUIs[i], out rayTagResult[i], out rayDisResult[i]); SingleRaycastUpdate(nowRay,i);
} }
for (int i = 0; i < halfOuterRayNum; i++) // create right outside rays; focusRightEdge ~ MaxPixelHeight for (int i = 0; i < halfOuterRayNum; i++) // create right outside rays; focusRightEdge ~ MaxPixelHeight
{ {
Vector3 point = new Vector3(focusREdge + (i * focusLEdge / (halfOuterRayNum - 1)), camPixelHeight / 2, 0); Vector3 point = new Vector3(focusREdge + (i * focusLEdge / (halfOuterRayNum - 1)), camPixelHeight / 2, 0);
Ray nowRay = agentCam.ScreenPointToRay(point); Ray nowRay = agentCam.ScreenPointToRay(point);
SingleRaycastUpdate(nowRay, lineRenderers[halfOuterRayNum + i], rayInfoUIs[halfOuterRayNum + i], out rayTagResult[halfOuterRayNum + i], out rayDisResult[halfOuterRayNum + i]); SingleRaycastUpdate(nowRay, halfOuterRayNum + i);
} }
for (int i = 0; i < focusRayNum; i++) // create center focus rays; focusLeftEdge ~ focusLeftEdge for (int i = 0; i < focusRayNum; i++) // create center focus rays; focusLeftEdge ~ focusLeftEdge
{ {
Vector3 point = new Vector3(focusLEdge + ((i + 1) * (focusREdge - focusLEdge) / (focusRayNum + 1)), camPixelHeight / 2, 0); Vector3 point = new Vector3(focusLEdge + ((i + 1) * (focusREdge - focusLEdge) / (focusRayNum + 1)), camPixelHeight / 2, 0);
Ray nowRay = agentCam.ScreenPointToRay(point); Ray nowRay = agentCam.ScreenPointToRay(point);
SingleRaycastUpdate(nowRay, lineRenderers[halfOuterRayNum * 2 + i], rayInfoUIs[halfOuterRayNum * 2 + i], out rayTagResult[halfOuterRayNum * 2 + i], out rayDisResult[halfOuterRayNum * 2 + i]); SingleRaycastUpdate(nowRay, halfOuterRayNum * 2 + i);
} }
} }
private void ClearResult()
{
rayTagResult = new float[totalRayNum];
rayDisResult = new float[totalRayNum];
rayTagResultOneHot = new float[totalRayNum * ObjectTags.Tags.Count];
}
} }

View File

@ -0,0 +1,615 @@
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
public class RewardFunction : MonoBehaviour
{
public enum EndType
{ Win, Lose, Running, Num };
[SerializeField] private GameObject parameterContainerObj;
[SerializeField] private GameObject sceneBlockContainerObj;
[SerializeField] private GameObject targetControllerObj;
[SerializeField] private GameObject environmentUIObj;
[SerializeField] private GameObject enemyContainerObj;
private GameObject agentObj;
private Camera fpsCam;
private CommonParameterContainer commonParamCon;
private SceneBlockContainer sceneBlockCon;
private ParameterContainer paramCon;
private TargetController targetCon;
private EnvironmentUIControl envUICon;
private AgentController agentCon;
private RaySensors raySensors;
private bool firstRewardFlag = false;
private float lastDistance;
private float lastEnemyFacingDistance = 0f; // record last enemy facing minimum distance
private float lastTargetFacingDistance = 0f; // record last target facing minimum distance
private List<float> spinRecord = new List<float>();
private void Start()
{
agentObj = gameObject;
agentCon = agentObj.GetComponent<AgentController>();
fpsCam = agentCon.fpsCam;
commonParamCon = CommonParameterContainer.Instance;
paramCon = parameterContainerObj.GetComponent<ParameterContainer>();
sceneBlockCon = sceneBlockContainerObj.GetComponent<SceneBlockContainer>();
targetCon = targetControllerObj.GetComponent<TargetController>();
envUICon = environmentUIObj.GetComponent<EnvironmentUIControl>();
raySensors = GetComponent<RaySensors>();
}
/// <summary>
/// Calculates the reward value.
/// </summary>
/// <param name="sceneReward">Reward value from the scene.</param>
/// <param name="mouseX">Movement amount of the mouse along the X-axis.</param>
/// <param name="movement">Movement of discrete.</param>
/// <param name="shootState">State of the shooting action.</param>
/// <returns>Returns the calculated total reward value.</returns>
/// <remarks>
/// This method calculates the total reward based on the provided parameters,
/// taking into account rewards for enemy kills, shooting actions, facing reward,
/// and penalties such as spin and movement.
/// </remarks>
public float RewardCalculate(float sceneReward, float mouseX, float movement, int shootState)
{
float epreward = 0f;
// Got kill point reward
if (agentCon.enemyKillCount > 0)
{
for (int i = 0; i < agentCon.enemyKillCount; i++)
{
// get
epreward += KillReward(agentCon.killEnemyPosition);
}
agentCon.enemyKillCount = 0;
}
else
{
agentCon.enemyKillCount = 0;
}
// Shoot action reward
epreward += Ballistic(shootState) + sceneReward;
// facing reward
epreward += FacingReward();
// Penalty
// spin penalty
spinRecord.Add(mouseX);
if (spinRecord.Count >= commonParamCon.spinRecordMax)
{
spinRecord.RemoveAt(0);
}
float spinPenaltyReward = Math.Abs(spinRecord.ToArray().Sum() * commonParamCon.spinPenalty);
if (spinPenaltyReward >= commonParamCon.spinPenaltyThreshold)
{
epreward -= spinPenaltyReward;
}
else
{
epreward -= Math.Abs(mouseX) * commonParamCon.mousePenalty;
}
// move penalty
if (movement != 0)
{
epreward -= commonParamCon.movePenalty;
}
return epreward;
}
/// <summary>
/// Calculates the reward value for shooting actions.
/// </summary>
/// <param name="shootState">State value of the shooting action.</param>
/// <returns>Returns the reward value associated with shooting.</returns>
/// <remarks>
/// This method calculates the reward value based on the shooting state and other related conditions,
/// such as whether the enemy was hit, whether the shot was towards the target area, and whether the gun was ready to shoot.
/// </remarks>
private float Ballistic(int shootState)
{
Vector3 point = new Vector3(fpsCam.pixelWidth / 2, fpsCam.pixelHeight / 2, 0);// start position
Ray ray = fpsCam.ScreenPointToRay(point);
RaycastHit hit;
// Debug.DrawRay(centerRay.origin, centerRay.direction * 100, Color.blue);
// Mouse Pressed
if (shootState != 0 && agentCon.gunReadyToggle == true)
{
agentCon.lastShootTime = Time.time;
if (Physics.Raycast(ray, out hit, 100))
{
if (hit.collider.tag != agentCon.myTag && hit.collider.tag != "Wall" && hit.collider.tag != "Untagged")
{
// kill enemy
GameObject gotHitObj = hit.transform.gameObject;
gotHitObj.GetComponent<States>().ReactToHit(commonParamCon.damage, gameObject);
shootState = 0;
return HitEnemyReward(gotHitObj.transform.position);
}
}
if (targetCon.targetType == Targets.Attack)
{
// while if attack mode
float targetDis = Vector3.Distance(sceneBlockCon.nowBlock.transform.position, transform.position);
if (targetDis <= raySensors.viewDistance)
{
// Debug.DrawRay(new Vector3(0,0,0), viewPoint, Color.red);
if (Vector3.Distance(ray.origin + (ray.direction * targetDis), sceneBlockCon.nowBlock.transform.position) <= sceneBlockCon.nowBlock.firebasesAreaDiameter / 2)
{
// im shooting at target but didn't hit enemy
// Debug.DrawRay(centerRay.origin, viewPoint-centerRay.origin, Color.blue);
return commonParamCon.shootTargetAreaReward;
}
}
}
shootState = 0;
return commonParamCon.shootReward;
}
else if (shootState != 0 && agentCon.gunReadyToggle == false)
{
// shoot without ready
shootState = 0;
return commonParamCon.shootWithoutReadyReward;
}
else
{
// do not shoot
shootState = 0;
return commonParamCon.nonReward;
}
}
/// <summary>
/// Retrieves the reward value based on the character's facing direction.
/// </summary>
/// <returns>Returns the reward value for the facing direction.</returns>
/// <remarks>
/// This method calculates a reward value based on the relationship between the character's facing direction and the target.
/// in free mode, if the character is facing an enemy, the reward is a fixed value
/// in attack mode, the reward depends on the distance between the character and the target, among other factors.
/// </remarks>
private float FacingReward()
{
Vector3 screenCenter = new Vector3(fpsCam.pixelWidth / 2, fpsCam.pixelHeight / 2, 0);
Vector3 screenLeft = new Vector3(0, fpsCam.pixelHeight / 2, 0);
Ray centerRay = fpsCam.ScreenPointToRay(screenCenter);
Ray leftRay = fpsCam.ScreenPointToRay(screenLeft);
switch (targetCon.targetType)
{
case Targets.Free:
return FacingRewardFree(centerRay);
case Targets.Attack:
return FacingRewardAttack(centerRay, leftRay);
case Targets.Go:
return FacingRewardGo(centerRay, leftRay);
case Targets.Stay:
// stay mode has no facing reward
return 0f;
default:
Debug.LogError("Wrong target type");
return 0f;
}
}
private float FacingRewardFree(Ray centerRay)
{
float nowReward = 0;
float enemyFacingDistance = 0f;
bool isFacingtoEnemy = false;
RaycastHit hit;
if (Physics.Raycast(centerRay, out hit, 100))
{
// facing to an enemy
if (hit.collider.tag != agentCon.myTag && hit.collider.tag != "Wall")
{
nowReward = commonParamCon.facingReward;
isFacingtoEnemy = true;
}
}
if (raySensors.inViewEnemies.Count > 0 && !isFacingtoEnemy)
{
// have enemy in view
List<float> projectionDis = new List<float>();
foreach (GameObject theEnemy in raySensors.inViewEnemies)
{
// for each enemy in view
Vector3 projection = Vector3.Project(theEnemy.transform.position - transform.position, (centerRay.direction * 10));
Vector3 verticalToRay = transform.position + projection - theEnemy.transform.position;
projectionDis.Add(verticalToRay.magnitude);
// Debug.Log("enemy!" + verticalToRay.magnitude);
// Debug.DrawRay(transform.position, (centerRay.direction * 100), Color.cyan);
// Debug.DrawRay(transform.position, theEnemy.transform.position - transform.position, Color.yellow);
// Debug.DrawRay(transform.position, projection, Color.blue);
// Debug.DrawRay(theEnemy.transform.position, verticalToRay, Color.magenta);
}
enemyFacingDistance = projectionDis.Min();
if (enemyFacingDistance <= lastEnemyFacingDistance)
{
// closing to enemy
nowReward = 1 / MathF.Sqrt(commonParamCon.facingInviewEnemyDisCOEF * enemyFacingDistance + 0.00001f);
}
else
{
nowReward = 0;
}
// enemy in view Reward
lastEnemyFacingDistance = enemyFacingDistance;
if (nowReward >= commonParamCon.facingReward) nowReward = commonParamCon.facingReward; // limit
if (nowReward <= -commonParamCon.facingReward) nowReward = -commonParamCon.facingReward; // limit
// Debug.Log("ninimum = " + nowReward);
}
return nowReward;
}
private float FacingRewardGo(Ray centerRay, Ray leftRay)
{
float nowReward = 0;
float camCenterToFireBase;
float camCenterToViewEdge;
(camCenterToFireBase, camCenterToViewEdge, _) = CameraCenterToFireBaseAndViewEdge(centerRay, leftRay);
// goto mode
if (camCenterToFireBase <= camCenterToViewEdge)
{
// fireArea is in view
nowReward = commonParamCon.facingReward;
}
else
{
nowReward = 0;
}
return nowReward;
}
private float FacingRewardAttack(Ray centerRay, Ray leftRay)
{
float nowReward = 0;
float camCenterToFireBase;
float targetDis;
(camCenterToFireBase, _, targetDis) = CameraCenterToFireBaseAndViewEdge(centerRay, leftRay);
// attack mode
if (targetDis <= raySensors.viewDistance)
{
// Debug.DrawRay(new Vector3(0,0,0), viewPoint, Color.red);
// while center of screen between target's distance is lower than firebasesAreaDiameter
// while facing to target
if (camCenterToFireBase <= sceneBlockCon.nowBlock.firebasesAreaDiameter / 2)
{
// Debug.DrawRay(centerRay.origin, viewPoint-centerRay.origin, Color.blue);
nowReward = commonParamCon.facingReward;
}
else
{
// while not facing to target
nowReward = (lastTargetFacingDistance - camCenterToFireBase) * commonParamCon.facingTargetReward;
}
}
// update lastTargetFacingDistance
lastTargetFacingDistance = camCenterToFireBase;
return nowReward;
}
private (float, float, float) CameraCenterToFireBaseAndViewEdge(Ray centerRay, Ray leftRay)
{
// target fireBaseArea Position, turen y to camera's y
Vector3 fireBaseArea = sceneBlockCon.nowBlock.fireBasesAreaObj.transform.position;
fireBaseArea.y = fpsCam.transform.position.y;
// my position, turn y to camera's y
// Debug.DrawRay(fpsCam.transform.position, centerRay.direction * 100, Color.blue);
Vector3 myposition = transform.position;
myposition.y = fpsCam.transform.position.y;
// Target to Agent distance
//Debug.DrawLine(fireBaseArea, myposition, Color.red);
float targetDis = Vector3.Distance(fireBaseArea, myposition);
// point in centerRay and leftRay which distance is targetDis from camera center
Vector3 pointInCenterRay = fpsCam.transform.position + (centerRay.direction * targetDis);
Vector3 pointInLeftRay = fpsCam.transform.position + (leftRay.direction * targetDis);
// center of screen to target's distance
// Debug.DrawLine(pointInCenterRay, fireBaseArea,Color.green);
float camCenterToFireBase = Vector3.Distance(pointInCenterRay, fireBaseArea);
// left of screen to target's distance
// Debug.DrawLine(pointInLeftRay, pointInCenterRay, Color.yellow);
float camCenterToViewEdge = Vector3.Distance(pointInLeftRay, pointInCenterRay);
return (camCenterToFireBase, camCenterToViewEdge, targetDis);
}
/// <summary>
/// Checks the game's end state and retrieves rewards.
/// </summary>
/// <returns>A tuple containing the game's end type, current reward, and final reward.
/// 1 = success,2 = overtime,0 = notover</returns>
public (int, float, float) CheckOverAndRewards()
{
int endTypeInt = 0;
float nowReward = 0;
float endReward = 0;
switch (targetCon.targetType)
{
case Targets.Go:
// goto
(endTypeInt, nowReward, endReward) = CheckOverAndRewardsGo();
break;
case Targets.Attack:
// attack
(endTypeInt, nowReward, endReward) = CheckOverAndRewardsAttack();
break;
case Targets.Defence:
//defence
(endTypeInt, nowReward, endReward) = CheckOverAndRewardsDefence();
break;
case Targets.Stay:
// Stay
// endless
nowReward = 0;
endReward = 0;
endTypeInt = (int)EndType.Running;
break;
default:
//free kill
(endTypeInt, nowReward, endReward) = CheckOverAndRewardsFreeKill();
break;
}
envUICon.ShowResult(endTypeInt);
return (endTypeInt, nowReward, endReward);
}
private (int, float, float) CheckOverAndRewardsGo()
{
int endTypeInt = 0;
float nowReward = 0;
float endReward = 0;
float nowDistance = 0;
(nowDistance, targetCon.inArea) = sceneBlockCon.GetAgentTargetDistanceAndInside(agentObj.transform.position);
envUICon.UpdateTargetGauge(sceneBlockCon.nowBlock.firebasesBelong, sceneBlockCon.nowBlock.belongMaxPoint);
float areaTargetReward = GetDistanceReward(nowDistance, targetCon.inArea);
//if(inArea != 0)
if (sceneBlockCon.nowBlock.firebasesBelong >= sceneBlockCon.nowBlock.belongMaxPoint)
{
// win
// let the area belongs to me
nowReward = areaTargetReward;
endReward = paramCon.goWinReward;
//nowReward = (paramCon.inAreaReward * inArea) + getDistanceReward(nowDistance);
endTypeInt = (int)EndType.Win;
}
else if (targetCon.leftTime <= 0)
{
// time out lose
nowReward = areaTargetReward;
endReward = commonParamCon.loseReward;
endTypeInt = (int)EndType.Lose;
}
else
{
// keep on keeping on!
nowReward = areaTargetReward;
endReward = 0;
endTypeInt = (int)EndType.Running;
}
return (endTypeInt, nowReward, endReward);
}
private (int, float, float) CheckOverAndRewardsAttack()
{
int endTypeInt = 0;
float nowReward = 0;
float endReward = 0;
float nowDistance = 0;
(nowDistance, targetCon.inArea) = sceneBlockCon.GetAgentTargetDistanceAndInside(agentObj.transform.position);
envUICon.UpdateTargetGauge(sceneBlockCon.nowBlock.firebasesBelong, sceneBlockCon.nowBlock.belongMaxPoint);
if (sceneBlockCon.nowBlock.GetInAreaNumber(commonParamCon.group2Tag) <= 0 && targetCon.targetEnemySpawnFinish)
{
// win
// let the area belongs to me and kill every enmy in this area.
nowReward = 0;
endReward = paramCon.attackWinReward;
//nowReward = (paramCon.inAreaReward * inArea) + getSceneReward(nowDistance);
endTypeInt = (int)EndType.Win;
targetCon.targetEnemySpawnFinish = false;
}
else if (targetCon.leftTime <= 0 && targetCon.targetEnemySpawnFinish)
{
// time out lose
nowReward = 0;
endReward = commonParamCon.loseReward;
//nowReward = (paramCon.inAreaReward * inArea) + getSceneReward(nowDistance);
endTypeInt = (int)EndType.Lose;
targetCon.targetEnemySpawnFinish = false;
}
else
{
// keep on keeping on!
// nowReward = (paramCon.inAreaReward * inArea) + getDistanceReward(nowDistance);
nowReward = 0;
endReward = 0;
targetCon.targetEnemySpawnFinish = true;
endTypeInt = (int)EndType.Running;
}
return (endTypeInt, nowReward, endReward);
}
private (int, float, float) CheckOverAndRewardsDefence()
{
// !!! NOT FINISHED YET!!!
int endTypeInt = 0;
float nowReward = 0;
float endReward = 0;
float nowDistance = 0;
(nowDistance, targetCon.inArea) = sceneBlockCon.GetAgentTargetDistanceAndInside(agentObj.transform.position);
envUICon.UpdateTargetGauge(sceneBlockCon.nowBlock.firebasesBelong, sceneBlockCon.nowBlock.belongMaxPoint);
if (targetCon.leftTime <= 0 && sceneBlockCon.nowBlock.firebasesBelong >= 0f)
{
// win
// time over and the area still mine
nowReward = paramCon.defenceWinReward;
//nowReward = (paramCon.inAreaReward * inArea) + getSceneReward(nowDistance);
endTypeInt = (int)EndType.Win;
}
else if (sceneBlockCon.nowBlock.firebasesBelong <= sceneBlockCon.nowBlock.belongMaxPoint)
{
// lost area lose
nowReward = commonParamCon.loseReward;
//nowReward = (paramCon.inAreaReward * inArea) + getSceneReward(nowDistance);
endTypeInt = (int)EndType.Lose;
}
else
{
// keep on keeping on!
// nowReward = (paramCon.inAreaReward * inArea) + getDistanceReward(nowDistance);
endTypeInt = (int)EndType.Running;
}
return (endTypeInt, nowReward, endReward);
}
private (int, float, float) CheckOverAndRewardsFreeKill()
{
int endTypeInt = 0;
float nowReward = 0;
float endReward = 0;
if (enemyContainerObj.transform.childCount <= 0)
{
// win
// nowReward = paramCon.winReward + (paramCon.timeBonusPerSecReward * leftTime);
nowReward = 0;
endReward = paramCon.freeWinReward;
endTypeInt = (int)EndType.Win;
}
else if (targetCon.leftTime <= 0)
{
// lose
//nowReward = paramCon.loseReward;
nowReward = 0;
endReward = commonParamCon.loseReward;
endTypeInt = (int)EndType.Lose;
}
else
{
// keep on keeping on!
nowReward = 0;
endReward = 0;
endTypeInt = (int)EndType.Running;
}
return (endTypeInt, nowReward, endReward);
}
/// <summary>
/// Calculates scene reward based on distance, granting higher rewards for being closer to the target.
/// </summary>
/// <param name="nowDistance">The current distance.</param>
/// <param name="inarea">Whether inside an area.</param>
/// <returns>The reward value calculated based on distance.</returns>
private float GetDistanceReward(float nowDistance, int inarea)
{
if (firstRewardFlag)
{
// first distance record
(lastDistance, _) = sceneBlockCon.GetAgentTargetDistanceAndInside(agentObj.transform.position);
firstRewardFlag = false;
}
float nowSeneReward = 0f;
if (inarea != 0)
{
// in area
nowSeneReward = paramCon.inAreaReward;
}
else
{
// out of area
// nowSeneReward = paramCon.distanceReward * Math.Clamp(lastDistance - nowDistance, 0, 100);
nowSeneReward = commonParamCon.distanceReward * (lastDistance - nowDistance);
}
lastDistance = nowDistance;
return nowSeneReward;
}
/// <summary>
/// Calculates kill reward based on the position of the killed enemy.
/// </summary>
/// <param name="enemyPosition">The position of the killed enemy.</param>
/// <returns>The reward value calculated based on the kill position.</returns>
public float KillReward(Vector3 enemyPosition)
{
float nowKillReward = 0f;
if (targetCon.targetType == Targets.Attack)
{
// attack mode
(_, int isInArea) = sceneBlockCon.nowBlock.GetDistInArea(enemyPosition);
if (isInArea == 1)
{
// kill in area enemy
nowKillReward = paramCon.killTargetEnemyReward;
}
else
{
nowKillReward = commonParamCon.killNonTargetReward;
}
}
else if (targetCon.targetType == Targets.Free)
{
// free mode hit
nowKillReward = paramCon.killTargetEnemyReward;
}
else
{
// goto & defence
nowKillReward = commonParamCon.killNonTargetReward;
}
return nowKillReward;
}
/// <summary>
/// Calculates hit reward based on the position of the hit enemy and the current mode.
/// </summary>
/// <param name="enemyPosition">The position of the hit enemy.</param>
/// <returns>The reward value calculated based on the hit position and mode.</returns>
public float HitEnemyReward(Vector3 enemyPosition)
{
float nowHitReward = 0f;
if (targetCon.targetType == Targets.Attack)
{
// attack mode
(_, int isInArea) = sceneBlockCon.nowBlock.GetDistInArea(enemyPosition);
if (isInArea == 1)
{
// hit in area enemy
nowHitReward = paramCon.hitTargetReward;
}
else
{
// hit not in area enemy
nowHitReward = commonParamCon.hitNonTargetReward;
}
}
else if (targetCon.targetType == Targets.Free)
{
// free mode hit
nowHitReward = paramCon.hitTargetReward;
}
else
{
// goto & defence
nowHitReward = commonParamCon.hitNonTargetReward;
}
return nowHitReward;
}
}

View File

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

View File

@ -109,7 +109,7 @@ public void InitBlock(GameObject envObj)
// Debug.Log("SceneBlock.Start: enemyContainerObj not found, get it by name"); // Debug.Log("SceneBlock.Start: enemyContainerObj not found, get it by name");
enemyContainerObj = transform.Find("EnemyContainer").gameObject; enemyContainerObj = transform.Find("EnemyContainer").gameObject;
} }
firebasesAreaPosition = transform.position + fireBasesAreaObj.transform.position; firebasesAreaPosition = fireBasesAreaObj.transform.position;
firebasesAreaScale = fireBasesAreaObj.transform.localScale.x; firebasesAreaScale = fireBasesAreaObj.transform.localScale.x;
firebasesAreaDiameter = firebasesAreaScale * blockSize; firebasesAreaDiameter = firebasesAreaScale * blockSize;
firebasesBelong = -belongMaxPoint; firebasesBelong = -belongMaxPoint;

View File

@ -2,10 +2,12 @@
public class SceneBlockContainer : MonoBehaviour public class SceneBlockContainer : MonoBehaviour
{ {
public float sceneSize = 10f; [SerializeField]
public GameObject environmentObj; private float sceneSize = 10f;
public GameObject parameterContainerObj; [SerializeField]
public GameObject hudObj; private GameObject environmentObj;
[SerializeField]
private GameObject hudObj;
// public GameObject[] attackBlockPrefabs = new GameObject[1]; // public GameObject[] attackBlockPrefabs = new GameObject[1];
// public GameObject[] goBlockPrefabs = new GameObject[1]; // public GameObject[] goBlockPrefabs = new GameObject[1];
@ -13,11 +15,11 @@ public class SceneBlockContainer : MonoBehaviour
public SceneBlock nowBlock; public SceneBlock nowBlock;
private GameObject nowBlockObj; private GameObject nowBlockObj;
private ParameterContainer paramCon; private CommonParameterContainer commonParamCon;
private void Start() private void Start()
{ {
paramCon = parameterContainerObj.GetComponent<ParameterContainer>(); commonParamCon = CommonParameterContainer.Instance;
} }
/// <summary> /// <summary>
@ -40,7 +42,7 @@ public void CreateNewBlock(Targets targetType, int level, int blockType, Vector3
DestroyBlock(); DestroyBlock();
} }
// choose target type // choose target type
nowBlockObj = Instantiate(paramCon.scenePrefabSet.GetPrefab(level, blockType, targetType), blockPosition + environmentObj.transform.position, Quaternion.identity, transform); nowBlockObj = Instantiate(commonParamCon.scenePrefabSet.GetPrefab(level, blockType, targetType), blockPosition + environmentObj.transform.position, Quaternion.identity, transform);
nowBlock = nowBlockObj.GetComponent<SceneBlock>(); nowBlock = nowBlockObj.GetComponent<SceneBlock>();
nowBlock.group1Tag = tag1; nowBlock.group1Tag = tag1;
nowBlock.group2Tag = tag2; nowBlock.group2Tag = tag2;

View File

@ -5,14 +5,12 @@
public class TargetController : MonoBehaviour public class TargetController : MonoBehaviour
{ {
public GameObject environmentObj; [SerializeField] private GameObject environmentObj;
public GameObject agentObj; [SerializeField] private GameObject agentObj;
public GameObject HUDObj; [SerializeField] private GameObject HUDObj;
public GameObject sceneBlockContainerObj; [SerializeField] private GameObject sceneBlockContainerObj;
public GameObject enemyContainerObj; [SerializeField] private GameObject enemyContainerObj;
public GameObject parameterContainerObj; [SerializeField] private GameObject environmentUIObj;
public GameObject environmentUIObj;
public GameObject worldUIObj;
// area // area
public GameObject edgeUp; public GameObject edgeUp;
@ -22,11 +20,6 @@ public class TargetController : MonoBehaviour
public GameObject edgeRight; public GameObject edgeRight;
public GameObject edgeAgent_Enemy; public GameObject edgeAgent_Enemy;
//group
public string group1Tag = "Player";
public string group2Tag = "Enemy";
public float minEnemyAreaX; public float minEnemyAreaX;
[System.NonSerialized] public float maxEnemyAreaX; [System.NonSerialized] public float maxEnemyAreaX;
[System.NonSerialized] public float minEnemyAreaZ; [System.NonSerialized] public float minEnemyAreaZ;
@ -42,10 +35,10 @@ public class TargetController : MonoBehaviour
[SerializeField, Range(0f, 1f)] public float gotoProb = 0.2f; [SerializeField, Range(0f, 1f)] public float gotoProb = 0.2f;
[SerializeField, Range(0f, 1f)] public float defenceProb = 0.2f; [SerializeField, Range(0f, 1f)] public float defenceProb = 0.2f;
[System.NonSerialized] public int targetTypeInt; [System.NonSerialized] public Targets targetType;
[System.NonSerialized] public int gotoLevelNum; [System.NonSerialized] public int gotoLevelNum;
[System.NonSerialized] public int attackLevelNum; [System.NonSerialized] public int attackLevelNum;
public float[] targetState = new float[6]; [System.NonSerialized] public float[] targetState = new float[5];
public enum EndType public enum EndType
{ Win, Lose, Running, Num }; { Win, Lose, Running, Num };
@ -53,21 +46,20 @@ public enum EndType
[System.NonSerialized] public int targetNum = 0; [System.NonSerialized] public int targetNum = 0;
private Dictionary<int, float[]> oneHotRarget = new Dictionary<int, float[]>(); private Dictionary<int, float[]> oneHotRarget = new Dictionary<int, float[]>();
private int inArea = 0;
private float freeProb; private float freeProb;
private float sceneBlockSize; private float sceneBlockSize;
private float lastDistance;
private int randBlockType = 0; private int randBlockType = 0;
private int randLevel = 0; private int randLevel = 0;
public int inArea = 0;
public Vector3 targetPosition; public Vector3 targetPosition;
private bool firstRewardFlag = true; private bool firstRewardFlag = true;
private bool targetEnemySpawnFinish = false; public bool targetEnemySpawnFinish = false;
private SceneBlockContainer sceneBlockCon; private SceneBlockContainer sceneBlockCon;
private EnemyContainer enemyCon; private EnemyContainer enemyCon;
private EnvironmentUIControl envUICon; private EnvironmentUIControl envUICon;
private ParameterContainer paramCon; private CommonParameterContainer commonParamCon;
private CharacterController agentCharaCon; private CharacterController agentCharaCon;
private WorldUIController worldUICon;
private HUDController hudCon; private HUDController hudCon;
private MessageBoxController messageBoxCon; private MessageBoxController messageBoxCon;
@ -77,20 +69,19 @@ public enum EndType
// Start is called before the first frame update // Start is called before the first frame update
private void Start() private void Start()
{ {
commonParamCon = CommonParameterContainer.Instance;
sceneBlockCon = sceneBlockContainerObj.GetComponent<SceneBlockContainer>(); sceneBlockCon = sceneBlockContainerObj.GetComponent<SceneBlockContainer>();
envUICon = environmentUIObj.GetComponent<EnvironmentUIControl>(); envUICon = environmentUIObj.GetComponent<EnvironmentUIControl>();
enemyCon = enemyContainerObj.GetComponent<EnemyContainer>(); enemyCon = enemyContainerObj.GetComponent<EnemyContainer>();
agentCharaCon = agentObj.GetComponent<CharacterController>(); agentCharaCon = agentObj.GetComponent<CharacterController>();
paramCon = parameterContainerObj.GetComponent<ParameterContainer>();
worldUICon = worldUIObj.GetComponent<WorldUIController>();
hudCon = HUDObj.GetComponent<HUDController>(); hudCon = HUDObj.GetComponent<HUDController>();
messageBoxCon = HUDObj.GetComponent<MessageBoxController>(); messageBoxCon = HUDObj.GetComponent<MessageBoxController>();
// get parameter from ParameterContainer // get parameter from ParameterContainer
gamemode = paramCon.gameMode; gamemode = commonParamCon.gameMode;
attackProb = paramCon.attackProb; attackProb = commonParamCon.attackProb;
gotoProb = paramCon.gotoProb; gotoProb = commonParamCon.gotoProb;
defenceProb = paramCon.defenceProb; defenceProb = commonParamCon.defenceProb;
// initialize spawn area // initialize spawn area
minEnemyAreaX = edgeLeft.transform.localPosition.x + 1.0f; minEnemyAreaX = edgeLeft.transform.localPosition.x + 1.0f;
@ -105,8 +96,8 @@ private void Start()
freeProb = 1 - attackProb - gotoProb - defenceProb; freeProb = 1 - attackProb - gotoProb - defenceProb;
targetNum = (int)Targets.Num; targetNum = (int)Targets.Num;
gotoLevelNum = paramCon.scenePrefabSet.GetLevelNumber(Targets.Go); gotoLevelNum = commonParamCon.scenePrefabSet.GetLevelNumber(Targets.Go);
attackLevelNum = paramCon.scenePrefabSet.GetLevelNumber(Targets.Attack); attackLevelNum = commonParamCon.scenePrefabSet.GetLevelNumber(Targets.Attack);
if (freeProb < 0) if (freeProb < 0)
{ {
Debug.LogError("TargetController.Start: target percentage wrong"); Debug.LogError("TargetController.Start: target percentage wrong");
@ -130,13 +121,13 @@ private void Update()
// if gamemode is play, then time will keep paramCon.timeLimit // if gamemode is play, then time will keep paramCon.timeLimit
if (gamemode == 1) if (gamemode == 1)
{ {
leftTime = paramCon.timeLimit; leftTime = commonParamCon.timeLimit;
// print out time // print out time
// Debug.Log("Playing Time: " + leftTime); // Debug.Log("Playing Time: " + leftTime);
} }
else else
{ {
leftTime = paramCon.timeLimit - Time.time + startTime; leftTime = commonParamCon.timeLimit - Time.time + startTime;
} }
} }
@ -152,13 +143,13 @@ private void Update()
public void RollNewScene() public void RollNewScene()
{ {
startTime = Time.time;// Reset StartTime as now time startTime = Time.time;// Reset StartTime as now time
leftTime = paramCon.timeLimit - Time.time + startTime; leftTime = commonParamCon.timeLimit - Time.time + startTime;
float randTargetType = UnityEngine.Random.Range(0f, 1f); float randTargetType = UnityEngine.Random.Range(0f, 1f);
if (randTargetType <= gotoProb) if (randTargetType <= gotoProb)
{ {
// goto target spawn // goto target spawn
Debug.Log("GOTO THIS TARGET!"); Debug.Log("GOTO THIS TARGET!");
targetTypeInt = (int)Targets.Go; targetType = Targets.Go;
RandomSpawnSceneBlock(Targets.Go); RandomSpawnSceneBlock(Targets.Go);
// set startDistance // set startDistance
firstRewardFlag = true; firstRewardFlag = true;
@ -167,7 +158,7 @@ public void RollNewScene()
{ {
// attack target spawn // attack target spawn
Debug.Log("ATTACK Mode Start"); Debug.Log("ATTACK Mode Start");
targetTypeInt = (int)Targets.Attack; targetType = Targets.Attack;
RandomSpawnSceneBlock(Targets.Attack); RandomSpawnSceneBlock(Targets.Attack);
// set startDistance // set startDistance
firstRewardFlag = true; firstRewardFlag = true;
@ -177,7 +168,7 @@ public void RollNewScene()
{ {
// defence target spawn // defence target spawn
Debug.Log("DEFENCE Mode Start"); Debug.Log("DEFENCE Mode Start");
targetTypeInt = (int)Targets.Defence; targetType = Targets.Defence;
RandomSpawnSceneBlock(Targets.Defence); RandomSpawnSceneBlock(Targets.Defence);
// set startDistance // set startDistance
firstRewardFlag = true; firstRewardFlag = true;
@ -185,14 +176,14 @@ public void RollNewScene()
else else
{ {
Debug.Log("Free Mode Start"); Debug.Log("Free Mode Start");
targetTypeInt = (int)Targets.Free; targetType = Targets.Free;
enemyCon.DestroyAllEnemys(); enemyCon.DestroyAllEnemys();
enemyCon.RandomInitEnemys(hudCon.enemyNum); enemyCon.RandomInitEnemys(hudCon.enemyNum);
MoveAgentToSpwanArea(); MoveAgentToSpwanArea();
sceneBlockCon.DestroyBlock(); sceneBlockCon.DestroyBlock();
} }
UpdateTargetStates(); UpdateTargetStates();
envUICon.UpdateTargetType(targetTypeInt); envUICon.UpdateTargetType(targetType);
} }
#region Agent Move Method #region Agent Move Method
@ -205,7 +196,7 @@ private void MoveAgentToSpwanArea()
{ {
float randX = UnityEngine.Random.Range(minAgentAreaX, maxAgentAreaX); ; float randX = UnityEngine.Random.Range(minAgentAreaX, maxAgentAreaX); ;
float randZ = 0f; float randZ = 0f;
if (paramCon.spawnAgentInAllMap) if (commonParamCon.spawnAgentInAllMap)
{ {
// spawn agent in all around map // spawn agent in all around map
randZ = UnityEngine.Random.Range(minAgentAreaZ, maxEnemyAreaZ); randZ = UnityEngine.Random.Range(minAgentAreaZ, maxEnemyAreaZ);
@ -243,8 +234,6 @@ public void MoveAgentTo(Vector3 position)
#endregion Agent Move Method #endregion Agent Move Method
#region Random SceneBlock Spawn Method
/// <summary> /// <summary>
/// Randomly spawns a scene block based on the target type. /// Randomly spawns a scene block based on the target type.
/// 根据目标类型随机生成场景块。 /// 根据目标类型随机生成场景块。
@ -257,8 +246,8 @@ public void MoveAgentTo(Vector3 position)
private void RandomSpawnSceneBlock(Targets targetType) private void RandomSpawnSceneBlock(Targets targetType)
{ {
randLevel = RollRandomLevelIndex(targetType); randLevel = RollRandomLevelIndex(targetType);
randBlockType = Random.Range(0, paramCon.scenePrefabSet.GetBlockNumber(randLevel,targetType)); randBlockType = Random.Range(0, commonParamCon.scenePrefabSet.GetBlockNumber(randLevel,targetType));
sceneBlockSize = paramCon.scenePrefabSet.GetBlockSize(randLevel, randBlockType, targetType); sceneBlockSize = commonParamCon.scenePrefabSet.GetBlockSize(randLevel, randBlockType, targetType);
float randX = UnityEngine.Random.Range(minEnemyAreaX + sceneBlockSize / 2 + 1f, maxEnemyAreaX - sceneBlockSize / 2 - 1f); float randX = UnityEngine.Random.Range(minEnemyAreaX + sceneBlockSize / 2 + 1f, maxEnemyAreaX - sceneBlockSize / 2 - 1f);
float randZ = UnityEngine.Random.Range(minEnemyAreaZ + sceneBlockSize / 2 + 1f, maxEnemyAreaZ - sceneBlockSize / 2 - 1f); float randZ = UnityEngine.Random.Range(minEnemyAreaZ + sceneBlockSize / 2 + 1f, maxEnemyAreaZ - sceneBlockSize / 2 - 1f);
@ -266,268 +255,32 @@ private void RandomSpawnSceneBlock(Targets targetType)
// init scene block // init scene block
sceneBlockCon.DestroyBlock(); sceneBlockCon.DestroyBlock();
sceneBlockCon.CreateNewBlock(targetType, randLevel, randBlockType, targetPosition, group1Tag, group2Tag); sceneBlockCon.CreateNewBlock(targetType, randLevel, randBlockType, targetPosition, commonParamCon.group1Tag, commonParamCon.group2Tag);
enemyCon.DestroyAllEnemys(); enemyCon.DestroyAllEnemys();
enemyCon.RandomInitEnemysExcept(hudCon.enemyNum, targetPosition, sceneBlockSize); enemyCon.RandomInitEnemysExcept(hudCon.enemyNum, targetPosition, sceneBlockSize);
sceneBlockCon.nowBlock.InitBlock(environmentObj); sceneBlockCon.nowBlock.InitBlock(environmentObj);
} }
#endregion Random SceneBlock Spawn Method
#region Reward function
/// <summary> /// <summary>
/// Checks the game's end state and retrieves rewards. /// Spawns a scene block at a specified position.
/// </summary> /// </summary>
/// <returns>A tuple containing the game's end type, current reward, and final reward. /// <param name="targetType">The type of the target, determining the type of block to generate.</param>
/// 1 = success,2 = overtime,0 = notover</returns> /// <param name="level">The level of the block, affecting its properties.</param>
public (int, float, float) CheckOverAndRewards() /// <param name="blockNum">The number of the block, used to distinguish different blocks of the same level.</param>
/// <param name="blockPosition">The position of the block in the scene.</param>
/// <remarks>
/// This method first destroys the current block in the scene, then creates a new block based on the provided parameters and initializes it.
/// 'sceneBlockCon' is responsible for managing the creation, destruction, and initialization of scene blocks.
/// 'commonParamCon' provides additional parameters required for block creation.
/// 'environmentObj' is used during the initialization process of the block.
/// </remarks>
private void SpawnSceneBlock(Targets targetType, int level,int blockNum, Vector3 blockPosition)
{ {
int endTypeInt = 0; sceneBlockCon.DestroyBlock();
float nowReward = 0; sceneBlockCon.CreateNewBlock(targetType, level, blockNum, blockPosition, commonParamCon.group1Tag, commonParamCon.group2Tag);
float endReward = 0; sceneBlockCon.InitializeBlock(environmentObj);
float nowDistance = 0f;
switch (targetTypeInt)
{
case (int)Targets.Go:
// goto
(nowDistance, inArea) = sceneBlockCon.GetAgentTargetDistanceAndInside(agentObj.transform.position);
envUICon.UpdateTargetGauge(sceneBlockCon.nowBlock.firebasesBelong, sceneBlockCon.nowBlock.belongMaxPoint);
float areaTargetReward = GetDistanceReward(nowDistance, inArea);
//if(inArea != 0)
if (sceneBlockCon.nowBlock.firebasesBelong >= sceneBlockCon.nowBlock.belongMaxPoint)
{
// win
// let the area belongs to me
nowReward = areaTargetReward;
endReward = paramCon.goWinReward;
//nowReward = (paramCon.inAreaReward * inArea) + getDistanceReward(nowDistance);
endTypeInt = (int)EndType.Win;
}
else if (leftTime <= 0)
{
// time out lose
nowReward = areaTargetReward;
endReward = paramCon.loseReward;
endTypeInt = (int)EndType.Lose;
}
else
{
// keep on keeping on!
nowReward = areaTargetReward;
endReward = 0;
endTypeInt = (int)EndType.Running;
}
break;
case (int)Targets.Attack:
// attack
(nowDistance, inArea) = sceneBlockCon.GetAgentTargetDistanceAndInside(agentObj.transform.position);
envUICon.UpdateTargetGauge(sceneBlockCon.nowBlock.firebasesBelong, sceneBlockCon.nowBlock.belongMaxPoint);
if (sceneBlockCon.nowBlock.GetInAreaNumber(group2Tag) <= 0 && targetEnemySpawnFinish)
{
// win
// let the area belongs to me and kill every enmy in this area.
nowReward = 0;
endReward = paramCon.attackWinReward;
//nowReward = (paramCon.inAreaReward * inArea) + getSceneReward(nowDistance);
endTypeInt = (int)EndType.Win;
targetEnemySpawnFinish = false;
}
else if (leftTime <= 0 && targetEnemySpawnFinish)
{
// time out lose
nowReward = 0;
endReward = paramCon.loseReward;
//nowReward = (paramCon.inAreaReward * inArea) + getSceneReward(nowDistance);
endTypeInt = (int)EndType.Lose;
targetEnemySpawnFinish = false;
}
else
{
// keep on keeping on!
// nowReward = (paramCon.inAreaReward * inArea) + getDistanceReward(nowDistance);
nowReward = 0;
endReward = 0;
targetEnemySpawnFinish = true;
endTypeInt = (int)EndType.Running;
}
break;
case (int)Targets.Defence:
//defence
// !!! DIDN't FINISH!!!
(nowDistance, inArea) = sceneBlockCon.GetAgentTargetDistanceAndInside(agentObj.transform.position);
envUICon.UpdateTargetGauge(sceneBlockCon.nowBlock.firebasesBelong, sceneBlockCon.nowBlock.belongMaxPoint);
if (leftTime <= 0 && sceneBlockCon.nowBlock.firebasesBelong >= 0f)
{
// win
// time over and the area still mine
nowReward = paramCon.defenceWinReward;
//nowReward = (paramCon.inAreaReward * inArea) + getSceneReward(nowDistance);
endTypeInt = (int)EndType.Win;
}
else if (sceneBlockCon.nowBlock.firebasesBelong <= sceneBlockCon.nowBlock.belongMaxPoint)
{
// lost area lose
nowReward = paramCon.loseReward;
//nowReward = (paramCon.inAreaReward * inArea) + getSceneReward(nowDistance);
endTypeInt = (int)EndType.Lose;
}
else
{
// keep on keeping on!
// nowReward = (paramCon.inAreaReward * inArea) + getDistanceReward(nowDistance);
endTypeInt = (int)EndType.Running;
}
break;
case (int)Targets.Stay:
// Stay
// endless
nowReward = 0;
endReward = 0;
endTypeInt = (int)EndType.Running;
break;
default:
//free kill
if (enemyContainerObj.transform.childCount <= 0)
{
// win
// nowReward = paramCon.winReward + (paramCon.timeBonusPerSecReward * leftTime);
nowReward = 0;
endReward = paramCon.freeWinReward;
endTypeInt = (int)EndType.Win;
}
else if (leftTime <= 0)
{
// lose
//nowReward = paramCon.loseReward;
nowReward = 0;
endReward = paramCon.loseReward;
endTypeInt = (int)EndType.Lose;
}
else
{
// keep on keeping on!
nowReward = 0;
endReward = 0;
endTypeInt = (int)EndType.Running;
}
break;
}
envUICon.ShowResult(endTypeInt);
worldUICon.UpdateChart(targetTypeInt, endTypeInt);
return (endTypeInt, nowReward, endReward);
} }
/// <summary>
/// Calculates scene reward based on distance, granting higher rewards for being closer to the target.
/// 根据距离计算场景奖励,靠近目标则获得更高奖励。
/// </summary>
/// <param name="nowDistance">The current distance.</param>
/// <param name="inarea">Whether inside an area.</param>
/// <returns>The reward value calculated based on distance.</returns>
private float GetDistanceReward(float nowDistance, int inarea)
{
if (firstRewardFlag)
{
// first distance record
(lastDistance, _) = sceneBlockCon.GetAgentTargetDistanceAndInside(agentObj.transform.position);
firstRewardFlag = false;
}
float nowSeneReward = 0f;
if (inarea != 0)
{
// in area
nowSeneReward = paramCon.inAreaReward;
}
else
{
// out of area
// nowSeneReward = paramCon.distanceReward * Math.Clamp(lastDistance - nowDistance, 0, 100);
nowSeneReward = paramCon.distanceReward * (lastDistance - nowDistance);
}
lastDistance = nowDistance;
return nowSeneReward;
}
/// <summary>
/// Calculates kill reward based on the position of the killed enemy.
/// 根据击杀的敌人位置计算击杀奖励。
/// </summary>
/// <param name="enemyPosition">The position of the killed enemy.</param>
/// <returns>The reward value calculated based on the kill position.</returns>
public float KillReward(Vector3 enemyPosition)
{
float nowKillReward = 0f;
if (targetTypeInt == (int)Targets.Attack)
{
// attack mode
(_, int isInArea) = sceneBlockCon.nowBlock.GetDistInArea(enemyPosition);
if (isInArea == 1)
{
// kill in area enemy
nowKillReward = paramCon.killTargetEnemyReward;
}
else
{
nowKillReward = paramCon.killNonTargetReward;
}
}
else if (targetTypeInt == (int)Targets.Free)
{
// free mode hit
nowKillReward = paramCon.killTargetEnemyReward;
}
else
{
// goto & defence
nowKillReward = paramCon.killNonTargetReward;
}
return nowKillReward;
}
/// <summary>
/// Calculates hit reward based on the position of the hit enemy and the current mode.
/// 根据击中的敌人位置和当前模式计算击中Reward。
/// </summary>
/// <param name="enemyPosition">The position of the hit enemy.</param>
/// <returns>The reward value calculated based on the hit position and mode.</returns>
public float HitEnemyReward(Vector3 enemyPosition)
{
float nowHitReward = 0f;
if (targetTypeInt == (int)Targets.Attack)
{
// attack mode
(_, int isInArea) = sceneBlockCon.nowBlock.GetDistInArea(enemyPosition);
if (isInArea == 1)
{
// hit in area enemy
nowHitReward = paramCon.hitTargetReward;
}
else
{
// hit not in area enemy
nowHitReward = paramCon.hitNonTargetReward;
}
}
else if (targetTypeInt == (int)Targets.Free)
{
// free mode hit
nowHitReward = paramCon.hitTargetReward;
}
else
{
// goto & defence
nowHitReward = paramCon.hitNonTargetReward;
}
return nowHitReward;
}
#endregion Reward function
#region Play Mode Method #region Play Mode Method
/// <summary> /// <summary>
@ -542,46 +295,40 @@ public float HitEnemyReward(Vector3 enemyPosition)
/// 该方法用于初始化游戏播放模式包括设置目标类型、更新目标状态、更新UI显示、 /// 该方法用于初始化游戏播放模式包括设置目标类型、更新目标状态、更新UI显示、
/// 将代理移动到生成区域、销毁所有敌人和场景块。 /// 将代理移动到生成区域、销毁所有敌人和场景块。
/// </remarks> /// </remarks>
public void PlayInitialize() public void PlayModeInitialize()
{ {
targetTypeInt = (int)Targets.Stay; targetType = Targets.Stay;
UpdateTargetStates(); UpdateTargetStates();
envUICon.UpdateTargetType(targetTypeInt); envUICon.UpdateTargetType(targetType);
MoveAgentToSpwanArea(); MoveAgentToSpwanArea();
enemyCon.DestroyAllEnemys(); enemyCon.DestroyAllEnemys();
sceneBlockCon.DestroyBlock(); sceneBlockCon.DestroyBlock();
} }
// change to attack mode /// <summary>
public void AttackModeChange(Vector3 targetPosition) /// Changes the target type in play mode and updates the game environment accordingly.
/// </summary>
/// <param name="newTargetType">The new target type to be set.</param>
/// <param name="spawnPosition">Spawn position for scene blocks.</param>
/// <param name="level">Level parameter for spawning scene blocks.</param>
/// <param name="blockNum">Number of blocks to spawn.</param>
/// <remarks>
/// This method updates the target type to the specified new target. If a spawn position is provided, it spawns scene blocks at that position
/// with the specified level and block number. The target states are then updated based on the new setup. The UI is also refreshed to reflect the new target type.
/// </remarks>
public void PlayTargetChange(Targets newTargetType, Vector3? spawnPosition = null, int level = 0, int blockNum = 0)
{ {
targetTypeInt = (int)Targets.Attack; targetType = newTargetType;
UpdateTargetStates(targetPosition); if(spawnPosition.HasValue)
envUICon.UpdateTargetType(targetTypeInt); {
} SpawnSceneBlock(targetType, level, blockNum, spawnPosition.Value);
UpdateTargetStates(spawnPosition.Value);
// change to free mode }
public void FreeModeChange() else
{ {
targetTypeInt = (int)Targets.Free; UpdateTargetStates();
UpdateTargetStates(); }
envUICon.UpdateTargetType(targetTypeInt); envUICon.UpdateTargetType(targetType);
}
// change to goto mode
public void GotoModeChange(Vector3 targetPosition)
{
targetTypeInt = (int)Targets.Go;
UpdateTargetStates(targetPosition);
envUICon.UpdateTargetType(targetTypeInt);
}
// change to stay mode
public void StayModeChange()
{
targetTypeInt = (int)Targets.Stay;
UpdateTargetStates();
envUICon.UpdateTargetType(targetTypeInt);
} }
#endregion Play Mode Method #endregion Play Mode Method
@ -594,12 +341,12 @@ public void StayModeChange()
private void UpdateTargetStates(Vector3? targetPosition = null) private void UpdateTargetStates(Vector3? targetPosition = null)
{ {
// targettype, x,y,z, firebasesAreaDiameter // targettype, x,y,z, firebasesAreaDiameter
targetState[0] = targetTypeInt; targetState[0] = (int)targetType;
if (targetPosition != null) if (targetPosition != null)
{ {
this.targetPosition = (Vector3)targetPosition; this.targetPosition = (Vector3)targetPosition;
} }
if (targetTypeInt == (int)Targets.Free || targetTypeInt == (int)Targets.Stay) if (targetType == (int)Targets.Free || targetType == Targets.Stay)
{ {
for (int i = 1; i < targetState.Length; i++) for (int i = 1; i < targetState.Length; i++)
// set target position state to 0 // set target position state to 0
@ -607,11 +354,12 @@ private void UpdateTargetStates(Vector3? targetPosition = null)
} }
else else
{ {
targetState[1] = this.targetPosition.x; Vector3 fireBasePosition = sceneBlockCon.nowBlock.firebasesAreaPosition;
targetState[2] = this.targetPosition.y; Vector3 convertedPosition = fireBasePosition - this.transform.position;
targetState[3] = this.targetPosition.z; targetState[1] = convertedPosition.x;
targetState[2] = convertedPosition.y;
targetState[3] = convertedPosition.z;
targetState[4] = sceneBlockCon.nowBlock.firebasesAreaDiameter; targetState[4] = sceneBlockCon.nowBlock.firebasesAreaDiameter;
targetState[5] = sceneBlockCon.nowBlock.belongRatio;
} }
} }
@ -622,7 +370,7 @@ private void UpdateTargetStates(Vector3? targetPosition = null)
/// <returns>The in-area state.</returns> /// <returns>The in-area state.</returns>
public int GetInAreaState() public int GetInAreaState()
{ {
if (targetTypeInt == (int)Targets.Go) if (targetType == Targets.Go)
{ {
return inArea; return inArea;
} }
@ -640,26 +388,9 @@ public int GetInAreaState()
/// <returns>A random level index.</returns> /// <returns>A random level index.</returns>
public int RollRandomLevelIndex(Targets target) public int RollRandomLevelIndex(Targets target)
{ {
Debug.Log(target);
List<float> targetProbs; List<float> targetProbs;
targetProbs = commonParamCon.levelProbs[target];
switch (target)
{
case Targets.Attack:
targetProbs = paramCon.attackLevelProbs;
break;
case Targets.Go:
targetProbs = paramCon.gotoLevelProbs;
break;
case Targets.Defence:
targetProbs = paramCon.defenceLevelProbs;
break;
default:
messageBoxCon.PushMessage(
new List<string> { "[ERROR]TargetController:RandomLevel", "target type error" },
new List<string> { "#800000ff" });
Debug.LogWarning("[ERROR]TargetController:RandomLevel:target type error");
return -1; // Exit early on default case
}
// sample random level depends on the target probabilities // sample random level depends on the target probabilities
float randomNum = UnityEngine.Random.Range(0f, 1f); float randomNum = UnityEngine.Random.Range(0f, 1f);
@ -675,7 +406,7 @@ public int RollRandomLevelIndex(Targets target)
// If no level was returned, log an error and return -1 // If no level was returned, log an error and return -1
messageBoxCon.PushMessage( messageBoxCon.PushMessage(
new List<string> { "[ERROR]TargetController:RandomLevel", "level index out of range" }, new List<string> { "[ERROR]TargetController:RollRandomLevelIndex", "level index out of range" },
new List<string> { "orange" }); new List<string> { "orange" });
return -1; return -1;
} }

View File

@ -0,0 +1,27 @@
using System.Collections.Generic;
using UnityEngine;
public static class ObjectTags
{
public static List<string> Tags = new List<string>() { "Wall", "Enemy", "Player" };
public static int TagToInt(string tag)
{
return Tags.IndexOf(tag);
}
public static Color TagToCololr(string tag)
{
switch (tag)
{
case "Wall":
return Color.white;
case "Enemy":
return Color.red;
case "Player":
return Color.green;
default:
return Color.cyan;
}
}
}

View File

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

View File

@ -6,21 +6,28 @@ public class MouseInMap : MonoBehaviour
public float targetDistanceThreshold = 6f; public float targetDistanceThreshold = 6f;
public float enemyDistanceThreshold = 1f; public float enemyDistanceThreshold = 1f;
public Camera playCamera; [SerializeField]
public GameObject AgentObj; private Camera playCamera;
public GameObject environmentObj; [SerializeField]
public GameObject mousePreviewObj; private GameObject AgentObj;
public GameObject enemyContainerObj; [SerializeField]
public GameObject sceneBlockContainerObj; private GameObject environmentObj;
public GameObject targetControllerObj; [SerializeField]
public GameObject parameterContainerObj; private GameObject mousePreviewObj;
public GameObject HUDObj; [SerializeField]
private GameObject enemyContainerObj;
[SerializeField]
private GameObject sceneBlockContainerObj;
[SerializeField]
private GameObject targetControllerObj;
[SerializeField]
private GameObject HUDObj;
private Vector3 nowHitPosition = Vector3.zero; private Vector3 nowHitPosition = Vector3.zero;
private Vector3 nowHitPositionRelative = Vector3.zero; private Vector3 nowHitPositionRelative = Vector3.zero;
private LayerMask groundMask; private LayerMask groundMask;
private int blockNum; private int blockNum;
private ParameterContainer paramCon; private CommonParameterContainer commonParamCon;
private GameObject previewModel; private GameObject previewModel;
private TargetController targetCon; private TargetController targetCon;
private MousePreview mousePreviewCon; private MousePreview mousePreviewCon;
@ -47,7 +54,7 @@ public enum MouseMode
private void Start() private void Start()
{ {
paramCon = parameterContainerObj.GetComponent<ParameterContainer>(); commonParamCon = CommonParameterContainer.Instance;
groundMask = LayerMask.GetMask("Ground"); groundMask = LayerMask.GetMask("Ground");
targetCon = targetControllerObj.GetComponent<TargetController>(); targetCon = targetControllerObj.GetComponent<TargetController>();
mousePreviewCon = mousePreviewObj.GetComponent<MousePreview>(); mousePreviewCon = mousePreviewObj.GetComponent<MousePreview>();
@ -80,9 +87,7 @@ private void Update()
else else
{ {
// if agent or enemy is not nearby, create new block // if agent or enemy is not nearby, create new block
sceneBlockCon.CreateNewBlock(Targets.Attack, blockLevel, blockNum, nowHitPositionRelative); targetCon.PlayTargetChange(Targets.Attack, nowHitPositionRelative, blockLevel, blockNum);
sceneBlockCon.InitializeBlock(environmentObj);
targetCon.AttackModeChange(nowHitPositionRelative);
ChangeMouseMode(MouseMode.Default); ChangeMouseMode(MouseMode.Default);
} }
break; break;
@ -97,9 +102,7 @@ private void Update()
else else
{ {
// if agent or enemy is not nearby, create new block // if agent or enemy is not nearby, create new block
sceneBlockCon.CreateNewBlock(Targets.Go, blockLevel, blockNum, nowHitPositionRelative); targetCon.PlayTargetChange(Targets.Go, nowHitPositionRelative, blockLevel, blockNum);
sceneBlockCon.InitializeBlock(environmentObj);
targetCon.GotoModeChange(nowHitPositionRelative);
ChangeMouseMode(MouseMode.Default); ChangeMouseMode(MouseMode.Default);
} }
break; break;
@ -140,7 +143,7 @@ public void ChangeMouseMode(MouseMode mouseMode, int level = -1, int blockNum =
// while blockLevel is not set, send error message // while blockLevel is not set, send error message
messageCon.PushMessage(new List<string> { "[ERROR]MouseInMap:ChangeMouseMode:", "Level not set!", "mouseMode=", mouseMode.ToString() }, messageCon.PushMessage(new List<string> { "[ERROR]MouseInMap:ChangeMouseMode:", "Level not set!", "mouseMode=", mouseMode.ToString() },
new List<string> { messageCon.errorColor }); new List<string> { messageCon.errorColor });
blockLevel = paramCon.scenePrefabSet.GetLevelNumber(nowTargetType); blockLevel = commonParamCon.scenePrefabSet.GetLevelNumber(nowTargetType);
} }
else else
{ {
@ -152,7 +155,7 @@ public void ChangeMouseMode(MouseMode mouseMode, int level = -1, int blockNum =
if (blockNum < 0) if (blockNum < 0)
{ {
// while blockNum is not set, random choose block type // while blockNum is not set, random choose block type
this.blockNum = Random.Range(0, paramCon.scenePrefabSet.GetBlockNumber(blockLevel, nowTargetType)); this.blockNum = Random.Range(0, commonParamCon.scenePrefabSet.GetBlockNumber(blockLevel, nowTargetType));
} }
else else
{ {
@ -160,7 +163,7 @@ public void ChangeMouseMode(MouseMode mouseMode, int level = -1, int blockNum =
this.blockNum = blockNum; this.blockNum = blockNum;
} }
// set previewModel // set previewModel
previewModel = paramCon.scenePrefabSet.GetPrefab(blockLevel, this.blockNum, nowTargetType); previewModel = commonParamCon.scenePrefabSet.GetPrefab(blockLevel, this.blockNum, nowTargetType);
mousePreviewCon.ChangePreviewTo(previewModel); mousePreviewCon.ChangePreviewTo(previewModel);
break; break;

View File

@ -4,22 +4,23 @@
public class PlayerCamera : MonoBehaviour public class PlayerCamera : MonoBehaviour
{ {
public float normalSpeed = 0.0035f; private float normalSpeed = 0.0035f;
public float shiftSpeed = 0.06f; private float shiftSpeed = 0.06f;
public float zoomSpeed = -10.0f; private float zoomSpeed = -10.0f;
public float rotateSpeed = 0.1f; private float rotateSpeed = 0.1f;
public float maxHeight = 40f; private float maxHeight = 40f;
public float minHeight = 6f; private float minHeight = 6f;
public Vector2 startMouseP; private Vector2 startMouseP;
public Vector2 dragMouseP; private Vector2 dragMouseP;
private Vector3 defaultCamPosition;
private float speed; private float speed;
// Start is called before the first frame update // Start is called before the first frame update
void Start() void Start()
{ {
defaultCamPosition = transform.position;
} }
// Update is called once per frame // Update is called once per frame
@ -37,6 +38,12 @@ void Update()
zoomSpeed = 10.0f; zoomSpeed = 10.0f;
} }
// reset camera position
if (Input.GetKeyDown(KeyCode.R))
{
transform.position = defaultCamPosition;
}
float hsp = transform.position.y * speed * Input.GetAxis("Horizontal"); // horizontal movement speed float hsp = transform.position.y * speed * Input.GetAxis("Horizontal"); // horizontal movement speed
float vsp = transform.position.y * speed * Input.GetAxis("Vertical"); // vertical movement speed float vsp = transform.position.y * speed * Input.GetAxis("Vertical"); // vertical movement speed
float scrollSp = Mathf.Log(transform.position.y) * -zoomSpeed * Input.GetAxis("Mouse ScrollWheel"); // scroll speed float scrollSp = Mathf.Log(transform.position.y) * -zoomSpeed * Input.GetAxis("Mouse ScrollWheel"); // scroll speed

View File

@ -0,0 +1,40 @@
using UnityEngine;
public class Singleton<T> : MonoBehaviour where T : MonoBehaviour
{
private static T _instance;
public static T Instance
{
get
{
if (_instance == null)
{
_instance = (T)FindObjectOfType(typeof(T));
if (_instance == null)
{
Debug.LogError("An instance of " + typeof(T) + " is needed in the scene, but there is none.");
}
}
return _instance;
}
}
protected virtual void Awake()
{
if (_instance == null)
{
_instance = this as T;
}
else
{
Destroy(gameObject);
}
}
// keep this instance through scene change
public void KeepThroughSceneChange()
{
DontDestroyOnLoad(this.gameObject);
}
}

View File

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

View File

@ -1,99 +0,0 @@
using DG.Tweening;
using UnityEngine;
public class StartMenuAnimations : MonoBehaviour
{
public GameObject maskObj;
public GameObject mixButton;
public GameObject attackButton;
public GameObject gotoButton;
public GameObject freeButton;
public float animeDuration = 0.2f;
public Vector3 mixDestination = new Vector3(-85, 29, 0);
public Vector3 attackDestination = new Vector3(-100, 0, 0);
public Vector3 gotoDestination = new Vector3(-115, -29, 0);
public Vector3 freeDestination = new Vector3(-130, -58, 0);
public float maskScaleX = 1;
public float maskScaleY = 0.4f;
private Vector3 mixOriginDestination;
private Vector3 attackOriginDestination;
private Vector3 gotoOriginDestination;
private Vector3 freeOriginDestination;
private PolygonCollider2D parallelogramPolygon;
private bool isMouseOverMask = false;
private void Start()
{
// get start position
mixOriginDestination = mixButton.transform.position;
attackOriginDestination = attackButton.transform.position;
gotoOriginDestination = gotoButton.transform.position;
freeOriginDestination = freeButton.transform.position;
// transform local vector3 to world vector3 by parent
mixDestination += mixButton.transform.parent.position;
attackDestination += attackButton.transform.parent.position;
gotoDestination += gotoButton.transform.parent.position;
freeDestination += freeButton.transform.parent.position;
//get polygon from maskOBJ
parallelogramPolygon = maskObj.GetComponent<PolygonCollider2D>();
// minimize mask object
MinimizeMaskObj();
}
private void Update()
{
// check if mouse is in parallelogram
if (!isMouseOverMask && parallelogramPolygon.OverlapPoint(Input.mousePosition))
{
isMouseOverMask = true;
OnMaskPointerEnter();
}
else if (isMouseOverMask && !parallelogramPolygon.OverlapPoint(Input.mousePosition))
{
isMouseOverMask = false;
OnMaskPointerExit();
}
}
private void OnMaskPointerEnter()
{
// dotween move button
mixButton.transform.DOMove(mixDestination, animeDuration, true).SetEase(Ease.OutCirc).Play();
attackButton.transform.DOMove(attackDestination, animeDuration, true).SetEase(Ease.OutCirc).Play();
gotoButton.transform.DOMove(gotoDestination, animeDuration, true).SetEase(Ease.OutCirc).Play();
freeButton.transform.DOMove(freeDestination, animeDuration, true).SetEase(Ease.OutCirc).Play();
MaximizeMaskObj();
}
private void OnMaskPointerExit()
{
// dotween move button batck to original position
mixButton.transform.DOMove(mixOriginDestination, animeDuration, true).SetEase(Ease.OutCirc).Play();
attackButton.transform.DOMove(attackOriginDestination, animeDuration, true).SetEase(Ease.OutCirc).Play();
gotoButton.transform.DOMove(gotoOriginDestination, animeDuration, true).SetEase(Ease.OutCirc).Play();
freeButton.transform.DOMove(freeOriginDestination, animeDuration, true).SetEase(Ease.OutCirc).Play();
MinimizeMaskObj();
}
private void MinimizeMaskObj()
{
// minimize mask object use dotween doscale
maskObj.transform.DOScaleX(maskScaleX, animeDuration).SetEase(Ease.OutCirc).Play();
maskObj.transform.DOScaleY(maskScaleY, animeDuration).SetEase(Ease.OutCirc).Play();
}
private void MaximizeMaskObj()
{
// maximize mask object use dotween doscale
maskObj.transform.DOScaleX(1, animeDuration).SetEase(Ease.OutCirc).Play();
maskObj.transform.DOScaleY(1, animeDuration).SetEase(Ease.OutCirc).Play();
}
}

View File

@ -1,7 +1,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine; using UnityEngine;
public class StartSeneData : MonoBehaviour public class StartSeneDataremove : MonoBehaviour
{ {
[Header("Game mode")] [Header("Game mode")]
public int gameMode = 0;// default trainning mode public int gameMode = 0;// default trainning mode

View File

@ -12,8 +12,8 @@
[CreateAssetMenu(menuName = "All Scene Prefab Set")] [CreateAssetMenu(menuName = "All Scene Prefab Set")]
public class SceneBlocksSet : ScriptableObject public class SceneBlocksSet : ScriptableObject
{ {
public TargetLevelsSet[] targetLevels = new TargetLevelsSet[3]; public TargetLevelsSet[] targetLevels = new TargetLevelsSet[2];
public Targets[] targets = new Targets[3]; public Targets[] targets = new Targets[2];
private GameObject hudObj; private GameObject hudObj;
private MessageBoxController messageBoxController; private MessageBoxController messageBoxController;

View File

@ -7,32 +7,28 @@
public class ButtonActivateColorChanger : MonoBehaviour public class ButtonActivateColorChanger : MonoBehaviour
{ {
public List<Button> clickableButton = new List<Button>(); [SerializeField] private List<Button> clickableButton = new List<Button>();
public List<Button> unclickableButton = new List<Button>(); [SerializeField] private List<Button> unclickableButton = new List<Button>();
public Color32 normalTextColor = new Color32(236, 236, 236, 255); [SerializeField] private float colorChangeSpeed = 0.1f;
public Color32 normalBGColor = new Color32(255, 255, 255, 0);
public Color32 highLightTextColor = new Color32(41, 41, 41, 230);
public Color32 highLightBGColor = new Color32(255, 255, 255, 103);
public Color32 pressedTextColor = new Color32(0, 0, 0, 240);
public Color32 pressedBGColor = new Color32(255, 255, 255, 160);
public Color32 disableTextColor = new Color32(180, 180, b: 180, 80);
public Color32 disableBGColor = new Color32(255, 255, b: 255, 0);
public float colorChangeSpeed = 0.1f;
public bool clickable = true; public bool clickable = true;
[SerializeField] private UIColorContainer uiColor;
// Start is called before the first frame update // Start is called before the first frame update
private void Start() private void Start()
{ {
foreach (Button btn in clickableButton) foreach (Button btn in clickableButton)
{ {
InitializeEventTriggers(btn, true); InitializeEventTriggers(btn, true);
InitializeButtonColor(btn);
} }
foreach (Button btn in unclickableButton) foreach (Button btn in unclickableButton)
{ {
InitializeEventTriggers(btn, false); InitializeEventTriggers(btn, false);
InitializeButtonColor(btn);
} }
} }
@ -58,6 +54,15 @@ private void InitializeEventTriggers(Button btn, bool isClickable)
} }
} }
private void InitializeButtonColor(Button btn)
{
if (btn.interactable)
{
btn.image.DOColor(uiColor.normal.bg, colorChangeSpeed);
btn.GetComponentInChildren<TextMeshProUGUI>().DOColor(uiColor.normal.text, colorChangeSpeed);
}
}
/// <summary> /// <summary>
/// Adds an event trigger entry to an event trigger. /// Adds an event trigger entry to an event trigger.
/// </summary> /// </summary>
@ -76,8 +81,8 @@ private void OnPointerEnter(Button btn)
{ {
if (btn.interactable) if (btn.interactable)
{ {
btn.image.DOColor(highLightBGColor, colorChangeSpeed); btn.image.DOColor(uiColor.highLight.bg, colorChangeSpeed);
btn.GetComponentInChildren<TextMeshProUGUI>().DOColor(highLightTextColor, colorChangeSpeed); btn.GetComponentInChildren<TextMeshProUGUI>().DOColor(uiColor.highLight.text, colorChangeSpeed);
} }
} }
@ -85,8 +90,8 @@ private void OnPointerExit(Button btn)
{ {
if (btn.interactable) if (btn.interactable)
{ {
btn.image.DOColor(normalBGColor, colorChangeSpeed); btn.image.DOColor(uiColor.normal.bg, colorChangeSpeed);
btn.GetComponentInChildren<TextMeshProUGUI>().DOColor(normalTextColor, colorChangeSpeed); btn.GetComponentInChildren<TextMeshProUGUI>().DOColor(uiColor.normal.text, colorChangeSpeed);
} }
} }
@ -94,8 +99,8 @@ private void OnPointerDown(Button btn)
{ {
if (btn.interactable) if (btn.interactable)
{ {
btn.image.DOColor(pressedBGColor, colorChangeSpeed); btn.image.DOColor(uiColor.pressed.bg, colorChangeSpeed);
btn.GetComponentInChildren<TextMeshProUGUI>().DOColor(pressedTextColor, colorChangeSpeed); btn.GetComponentInChildren<TextMeshProUGUI>().DOColor(uiColor.pressed.text, colorChangeSpeed);
} }
} }
@ -103,8 +108,8 @@ private void OnPointerUp(Button btn)
{ {
if (btn.interactable) if (btn.interactable)
{ {
btn.image.DOColor(highLightBGColor, colorChangeSpeed); btn.image.DOColor(uiColor.highLight.bg, colorChangeSpeed);
btn.GetComponentInChildren<TextMeshProUGUI>().DOColor(normalTextColor, colorChangeSpeed); btn.GetComponentInChildren<TextMeshProUGUI>().DOColor(uiColor.highLight.text, colorChangeSpeed);
} }
} }
@ -118,13 +123,13 @@ public void ChangeInteractableColor(Button btn, bool changeTo)
btn.interactable = changeTo; btn.interactable = changeTo;
if (changeTo) if (changeTo)
{ {
btn.image.DOColor(normalBGColor, colorChangeSpeed); btn.image.DOColor(uiColor.normal.bg, colorChangeSpeed);
btn.GetComponentInChildren<TextMeshProUGUI>().DOColor(normalTextColor, colorChangeSpeed); btn.GetComponentInChildren<TextMeshProUGUI>().DOColor(uiColor.normal.text, colorChangeSpeed);
} }
else else
{ {
btn.image.DOColor(disableBGColor, colorChangeSpeed); btn.image.DOColor(uiColor.disabled.bg, colorChangeSpeed);
btn.GetComponentInChildren<TextMeshProUGUI>().DOColor(disableTextColor, colorChangeSpeed); btn.GetComponentInChildren<TextMeshProUGUI>().DOColor(uiColor.disabled.text, colorChangeSpeed);
} }
} }
@ -151,13 +156,13 @@ public void InitializeAllButtonColor()
{ {
foreach (Button btn in clickableButton) foreach (Button btn in clickableButton)
{ {
btn.image.color = normalBGColor; btn.image.color = uiColor.normal.bg;
btn.GetComponentInChildren<TextMeshProUGUI>().color = normalTextColor; btn.GetComponentInChildren<TextMeshProUGUI>().color = uiColor.normal.bg;
} }
foreach (Button btn in unclickableButton) foreach (Button btn in unclickableButton)
{ {
btn.image.color = disableBGColor; btn.image.color = uiColor.disabled.bg;
btn.GetComponentInChildren<TextMeshProUGUI>().color = disableTextColor; btn.GetComponentInChildren<TextMeshProUGUI>().color = uiColor.disabled.text;
} }
} }
} }

View File

@ -7,17 +7,17 @@
public class EnvironmentUIControl : MonoBehaviour public class EnvironmentUIControl : MonoBehaviour
{ {
public GameObject targetControllerObj; [SerializeField] private GameObject targetControllerObj;
public GameObject parameterContainerObj; [SerializeField] private GameObject parameterContainerObj;
public GameObject groundCanvasObj; [SerializeField] private GameObject groundCanvasObj;
public GameObject chartObj; [SerializeField] private GameObject chartObj;
public GameObject HUDObj; [SerializeField] private GameObject HUDObj;
public TextMeshProUGUI remainTimeText; [SerializeField] private TextMeshProUGUI remainTimeText;
public TextMeshProUGUI targetTypeText; [SerializeField] private TextMeshProUGUI targetTypeText;
public TextMeshProUGUI winLoseText; [SerializeField] private TextMeshProUGUI winLoseText;
public TextMeshProUGUI stateText; [SerializeField] private TextMeshProUGUI stateText;
public float resultTimeout = 1f; [SerializeField] private float resultTimeout = 1f;
public GameObject gaugeImgObj; [SerializeField] private GameObject gaugeImgObj;
private StringBuilder stateBuilder = new StringBuilder(); private StringBuilder stateBuilder = new StringBuilder();
private LineChart realTimeRewardChart = null; private LineChart realTimeRewardChart = null;
@ -131,31 +131,31 @@ public void UpdateTargetGauge(float firebasesBelong, float belongMaxPoint)
} }
// update targetType text // update targetType text
public void UpdateTargetType(int targetInt) public void UpdateTargetType(Targets targetInt)
{ {
switch (targetInt) switch (targetInt)
{ {
case (int)Targets.Go: case Targets.Go:
targetTypeText.text = "GOTO"; targetTypeText.text = "GOTO";
targetTypeText.color = Color.blue; targetTypeText.color = Color.blue;
break; break;
case (int)Targets.Attack: case Targets.Attack:
targetTypeText.text = "Attack!"; targetTypeText.text = "Attack!";
targetTypeText.color = Color.red; targetTypeText.color = Color.red;
break; break;
case (int)Targets.Defence: case Targets.Defence:
targetTypeText.text = "Defence"; targetTypeText.text = "Defence";
targetTypeText.color = Color.green; targetTypeText.color = Color.green;
break; break;
case (int)Targets.Free: case Targets.Free:
targetTypeText.text = "Free"; targetTypeText.text = "Free";
targetTypeText.color = Color.yellow; targetTypeText.color = Color.yellow;
break; break;
case (int)Targets.Stay: case Targets.Stay:
targetTypeText.text = "Stay"; targetTypeText.text = "Stay";
targetTypeText.color = Color.white; targetTypeText.color = Color.white;
break; break;
@ -169,10 +169,10 @@ public void UpdateTargetType(int targetInt)
// update state text // update state text
// public TextMeshProUGUI stateText; // public TextMeshProUGUI stateText;
// targetState[0] = targetTypeInt; // targetState[0] = targetType;
// targetState[1] = targetPosition.x / raySensors.viewDistance; // normalization // targetState[1] = targetEndPosition.x / raySensors.viewDistance; // normalization
// targetState[2] = targetPosition.y / raySensors.viewDistance; // targetState[2] = targetEndPosition.y / raySensors.viewDistance;
// targetState[3] = targetPosition.z / raySensors.viewDistance; // targetState[3] = targetEndPosition.z / raySensors.viewDistance;
// targetState[4] = blockCont.thisBlock.firebasesAreaDiameter / raySensors.viewDistance; // targetState[4] = blockCont.thisBlock.firebasesAreaDiameter / raySensors.viewDistance;
// targetState[5] = blockCont.thisBlock.belongRatio; // targetState[5] = blockCont.thisBlock.belongRatio;
// float[] myObserve = { transform.localPosition.x/raySensors.viewDistance, transform.localPosition.y / raySensors.viewDistance, transform.localPosition.z / raySensors.viewDistance, transform.eulerAngles.y/360f } // float[] myObserve = { transform.localPosition.x/raySensors.viewDistance, transform.localPosition.y / raySensors.viewDistance, transform.localPosition.z / raySensors.viewDistance, transform.eulerAngles.y/360f }
@ -190,8 +190,6 @@ public void UpdateStateText(float[] targetStates, float inAreaState, float remai
stateBuilder.Append(targetStates[3]); stateBuilder.Append(targetStates[3]);
stateBuilder.Append("\r\nTargetDiameter:"); stateBuilder.Append("\r\nTargetDiameter:");
stateBuilder.Append(targetStates[4]); stateBuilder.Append(targetStates[4]);
stateBuilder.Append("\r\nTargetBelongRatio:");
stateBuilder.Append(targetStates[5]);
stateBuilder.Append("\r\nInArea:"); stateBuilder.Append("\r\nInArea:");
stateBuilder.Append(inAreaState); stateBuilder.Append(inAreaState);
stateBuilder.Append("\r\nRemainTime:"); stateBuilder.Append("\r\nRemainTime:");
@ -199,9 +197,10 @@ public void UpdateStateText(float[] targetStates, float inAreaState, float remai
stateBuilder.Append("\r\nGunReady:"); stateBuilder.Append("\r\nGunReady:");
stateBuilder.Append(gunReadyToggle); stateBuilder.Append(gunReadyToggle);
stateBuilder.Append("\r\nMyPosition:"); stateBuilder.Append("\r\nMyPosition:");
stateBuilder.Append(myObserve[0]).Append(myObserve[1]).Append(myObserve[2]); stateBuilder.Append(myObserve[0]+"_").Append(myObserve[1]+"_").Append(myObserve[2]);
stateBuilder.Append("\r\nMyRotation:"); stateBuilder.Append("\r\nMyRotation:");
stateBuilder.Append(myObserve[3]); stateBuilder.Append(myObserve[3]+"_").Append(myObserve[4]);
stateText.text = stateBuilder.ToString(); stateText.text = stateBuilder.ToString();
} }

View File

@ -7,11 +7,11 @@
public class HUDController : MonoBehaviour public class HUDController : MonoBehaviour
{ {
public bool chartOn = false; public bool chartOn = false;
public GameObject sideChannelObj; [SerializeField] private GameObject sideChannelObj;
public Toggle chartOnToggleObj; [SerializeField] private Toggle chartOnToggleObj;
public Button saveModelButton; [SerializeField] private Button saveModelButton;
public TMP_InputField chartOnTimeOutInputObj; [SerializeField] private TMP_InputField chartOnTimeOutInputObj;
public TMP_InputField enemyNumInputObj; [SerializeField] private TMP_InputField enemyNumInputObj;
public float chartOnTimeOut = 1; public float chartOnTimeOut = 1;
public int enemyNum = 3; public int enemyNum = 3;
public float chartOnTimeOutDefault = 120f; public float chartOnTimeOutDefault = 120f;
@ -44,18 +44,6 @@ public void OnChartOnToggleChange()
chartOn = chartOnToggleObj.isOn; chartOn = chartOnToggleObj.isOn;
} }
public void OnEnemyNumTextChange()
{
try
{
enemyNum = Math.Abs(int.Parse(enemyNumInputObj.GetComponent<TMP_InputField>().text));
}
catch (NullReferenceException)
{
enemyNum = 3;
}
}
public void OnChartTimeOutTextChange() public void OnChartTimeOutTextChange()
{ {
try try

View File

@ -6,7 +6,7 @@
public class LevelButton : MonoBehaviour public class LevelButton : MonoBehaviour
{ {
public int level; public int level;
public TextMeshProUGUI levelText; [SerializeField] private TextMeshProUGUI levelText;
public void Initialization(int level) public void Initialization(int level)
{ {
this.level = level; this.level = level;

View File

@ -8,9 +8,9 @@ public class LevelPanel : MonoBehaviour
{ {
private int levelNum = 0; private int levelNum = 0;
private float buttonHeight = 30; private float buttonHeight = 30;
public TargetUIController.PrimaryButtonType primaryButtonType; [SerializeField] private TargetUIController.PrimaryButtonType primaryButtonType;
public GameObject levelButtonPrefab; [SerializeField] private GameObject levelButtonPrefab;
public GameObject hudObj; [SerializeField] private GameObject hudObj;
private TargetUIController targetUIController; private TargetUIController targetUIController;
public Vector2 defaultPosition = Vector2.zero; public Vector2 defaultPosition = Vector2.zero;
public Vector2 targetPosition = Vector2.zero; public Vector2 targetPosition = Vector2.zero;

View File

@ -0,0 +1,23 @@
using System.Collections.Generic;
using UnityEngine;
public class LevelProbabilityPanel : MonoBehaviour
{
[SerializeField] private GameObject singleTargetLevelProbabilityPanel;
[SerializeField] private GameObject startSceneData;
private SceneBlocksSet scenePrefabSet;
public List<TargetLevelProbabilityPanel> targetLevelProbabilityPanel = new List<TargetLevelProbabilityPanel>();
private void Start()
{
scenePrefabSet = CommonParameterContainer.Instance.scenePrefabSet;
for (int i = 0; i < scenePrefabSet.targetLevels.Length; i++)
{
Targets nowTarget = scenePrefabSet.targets[i];
targetLevelProbabilityPanel.Add(Instantiate(singleTargetLevelProbabilityPanel, transform).GetComponent<TargetLevelProbabilityPanel>());
targetLevelProbabilityPanel[i].IntializePanels(nowTarget, nowTarget.ToString());
}
}
}

View File

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

View File

@ -9,11 +9,10 @@ public class MessageBoxController : MonoBehaviour
public string warningColor = "#ffa500ff"; public string warningColor = "#ffa500ff";
public string errorColor = "#800000ff"; public string errorColor = "#800000ff";
public string goodColor = "#00ff00ff"; public string goodColor = "#00ff00ff";
public GameObject messagePanelObj; [SerializeField] private GameObject messagePanelObj;
public GameObject messageTextPrefab; [SerializeField] private GameObject messageTextPrefab;
[SerializeField] [SerializeField] private List<Message> messages = new List<Message>();
private List<Message> messages = new List<Message>();
/// <summary> /// <summary>
/// Pushes a simple message to the message list. /// Pushes a simple message to the message list.
@ -45,7 +44,7 @@ public void PushMessage(string text)
/// This method pushes multi-color text messages to the message list and handles message overflow to ensure that the message list does not grow indefinitely. /// This method pushes multi-color text messages to the message list and handles message overflow to ensure that the message list does not grow indefinitely.
/// If the lengths of the message text list and the color list do not match, it either removes excess colors or adds white color to the extra messages. /// If the lengths of the message text list and the color list do not match, it either removes excess colors or adds white color to the extra messages.
/// </remarks> /// </remarks>
public void PushMessage(List<string> messageList,List<string> colorList) public void PushMessage(List<string> messageList, List<string> colorList)
{ {
// check messages and colors list length match // check messages and colors list length match
if (messageList.Count != colorList.Count) if (messageList.Count != colorList.Count)
@ -53,7 +52,7 @@ public void PushMessage(List<string> messageList,List<string> colorList)
// delete extra colors or add white color to extra messages // delete extra colors or add white color to extra messages
if (messageList.Count > colorList.Count) if (messageList.Count > colorList.Count)
{ {
while(messageList.Count > colorList.Count) while (messageList.Count > colorList.Count)
{ {
colorList.Add(defaultColor); colorList.Add(defaultColor);
} }
@ -62,7 +61,6 @@ public void PushMessage(List<string> messageList,List<string> colorList)
{ {
colorList.RemoveRange(messageList.Count, colorList.Count - messageList.Count); colorList.RemoveRange(messageList.Count, colorList.Count - messageList.Count);
} }
} }
MessageOverflowHandler(); MessageOverflowHandler();
Message newMessage = new Message(); Message newMessage = new Message();

View File

@ -5,11 +5,11 @@
public class SingleLevelProbabilityPanel : MonoBehaviour public class SingleLevelProbabilityPanel : MonoBehaviour
{ {
public TextMeshProUGUI levelNameText;
public TMP_InputField inputField; public TMP_InputField inputField;
public Button lockButton; [SerializeField] private TextMeshProUGUI levelNameText;
public Image lockImg; [SerializeField] private Button lockButton;
public Image unlockImg; [SerializeField] private Image lockImg;
[SerializeField] private Image unlockImg;
public Slider probabilitySlider; public Slider probabilitySlider;

View File

@ -0,0 +1,115 @@
using DG.Tweening;
using UnityEngine;
public class StartMenuAnimations : MonoBehaviour
{
[SerializeField] private GameObject maskObj;
[SerializeField] private GameObject mixButton;
[SerializeField] private GameObject attackButton;
[SerializeField] private GameObject gotoButton;
[SerializeField] private GameObject freeButton;
[Header("Animation Parameter")]
[SerializeField] private float animeDuration = 0.2f;
[SerializeField] private float animeMoveXDistance = 20f;
[SerializeField] private float animeMoveYDistance = 20f;
[SerializeField] private float animeScaleX = 1.2f;
[SerializeField] private float animeScaleY = 1.2f;
[SerializeField] private float maskScaleX = 1;
[SerializeField] private float maskScaleY = 0.4f;
private Vector3 mixOriginDestination;
private Vector3 attackOriginDestination;
private Vector3 gotoOriginDestination;
private Vector3 freeOriginDestination;
private Vector3 mixDestination;
private Vector3 attackDestination;
private Vector3 gotoDestination;
private Vector3 freeDestination;
private Vector3 originalCanvas;
private PolygonCollider2D parallelogramPolygon;
private bool isMouseOverMask = false;
private void Start()
{
originalCanvas = transform.parent.position;
// get start position
mixOriginDestination = mixButton.transform.position;
attackOriginDestination = attackButton.transform.position;
gotoOriginDestination = gotoButton.transform.position;
freeOriginDestination = freeButton.transform.position;
// transform local vector3 to world vector3 by parent
mixDestination = mixButton.transform.position + new Vector3(animeScaleX * animeMoveXDistance, animeScaleY * animeMoveYDistance, 0);
attackDestination = attackButton.transform.position + new Vector3(animeMoveXDistance, animeMoveYDistance, 0);
gotoDestination = gotoButton.transform.position - new Vector3(animeMoveXDistance, animeMoveYDistance, 0);
freeDestination = freeButton.transform.position - new Vector3(animeScaleX * animeMoveXDistance, animeScaleY * animeMoveYDistance, 0);
//get polygon from maskOBJ
parallelogramPolygon = maskObj.GetComponent<PolygonCollider2D>();
// minimize mask object
MinimizeMaskObj();
}
private void Update()
{
// check if mouse is in parallelogram
if (!isMouseOverMask && parallelogramPolygon.OverlapPoint(Input.mousePosition))
{
isMouseOverMask = true;
OnMaskPointerEnter();
}
else if (isMouseOverMask && !parallelogramPolygon.OverlapPoint(Input.mousePosition))
{
isMouseOverMask = false;
OnMaskPointerExit();
}
}
private void OnMaskPointerEnter()
{
// dotween move button
mixButton.transform.DOMove(fixCanvas(mixDestination), animeDuration, true).SetEase(Ease.OutCirc).Play();
attackButton.transform.DOMove(fixCanvas(attackDestination), animeDuration, true).SetEase(Ease.OutCirc).Play();
gotoButton.transform.DOMove(fixCanvas(gotoDestination), animeDuration, true).SetEase(Ease.OutCirc).Play();
freeButton.transform.DOMove(fixCanvas(freeDestination), animeDuration, true).SetEase(Ease.OutCirc).Play();
MaximizeMaskObj();
}
private void OnMaskPointerExit()
{
// dotween move button batck to original position
mixButton.transform.DOMove(fixCanvas(mixOriginDestination), animeDuration, true).SetEase(Ease.OutCirc).Play();
attackButton.transform.DOMove(fixCanvas(attackOriginDestination), animeDuration, true).SetEase(Ease.OutCirc).Play();
gotoButton.transform.DOMove(fixCanvas(gotoOriginDestination), animeDuration, true).SetEase(Ease.OutCirc).Play();
freeButton.transform.DOMove(fixCanvas(freeOriginDestination), animeDuration, true).SetEase(Ease.OutCirc).Play();
MinimizeMaskObj();
}
private void MinimizeMaskObj()
{
// minimize mask object use dotween doscale
maskObj.transform.DOScaleX(maskScaleX, animeDuration).SetEase(Ease.OutCirc).Play();
maskObj.transform.DOScaleY(maskScaleY, animeDuration).SetEase(Ease.OutCirc).Play();
}
private void MaximizeMaskObj()
{
// maximize mask object use dotween doscale
maskObj.transform.DOScaleX(1, animeDuration).SetEase(Ease.OutCirc).Play();
maskObj.transform.DOScaleY(1, animeDuration).SetEase(Ease.OutCirc).Play();
}
private Vector3 fixCanvas(Vector3 vector)
{
// fix position of button while canvas is changed
return vector.FixCanvas(originalCanvas, transform.parent.position);
}
}

View File

@ -3,20 +3,20 @@
public class StartMenuProbabilityPanel : MonoBehaviour public class StartMenuProbabilityPanel : MonoBehaviour
{ {
public GameObject singleTargetLevelProbabilityPanel; [SerializeField] private GameObject singleTargetLevelProbabilityPanel;
public GameObject startSceneData; [SerializeField] private GameObject startSceneData;
private SceneBlocksSet scenePrefabSet; private SceneBlocksSet scenePrefabSet;
public List<TargetLevelProbabilityPanel> targetLevelProbabilityPanel = new List<TargetLevelProbabilityPanel>(); public List<TargetLevelProbabilityPanel> targetLevelProbabilityPanel = new List<TargetLevelProbabilityPanel>();
private void Start() private void Start()
{ {
scenePrefabSet = startSceneData.GetComponent<StartSeneData>().scenePrefabSet; scenePrefabSet = CommonParameterContainer.Instance.scenePrefabSet;
for (int i = 0; i < scenePrefabSet.targetLevels.Length; i++) for (int i = 0; i < scenePrefabSet.targetLevels.Length; i++)
{ {
Targets nowTarget = scenePrefabSet.targets[i]; Targets nowTarget = scenePrefabSet.targets[i];
targetLevelProbabilityPanel.Add(Instantiate(singleTargetLevelProbabilityPanel, transform).GetComponent<TargetLevelProbabilityPanel>()); targetLevelProbabilityPanel.Add(Instantiate(singleTargetLevelProbabilityPanel, transform).GetComponent<TargetLevelProbabilityPanel>());
targetLevelProbabilityPanel[i].IntializePanels(scenePrefabSet.GetLevelNumber(nowTarget), nowTarget.ToString()); targetLevelProbabilityPanel[i].IntializePanels(nowTarget, nowTarget.ToString());
} }
} }
} }

View File

@ -5,26 +5,25 @@
public class StartUIManager : MonoBehaviour public class StartUIManager : MonoBehaviour
{ {
public int waitTimeLimit = 45; [SerializeField] private int waitTimeLimit = 45;
public GameObject sceneLoaderObj; [SerializeField] private GameObject sceneLoaderObj;
public GameObject startSceneDataObj; [SerializeField] private GameObject targetLevelProbabilityPanelOBJ;
public GameObject targetLevelProbabilityPanelOBJ; [SerializeField] private TextMeshProUGUI messageTextObj;
public TextMeshProUGUI messageTextObj; [SerializeField] private TextMeshProUGUI waitTimeTextObj;
public TextMeshProUGUI waitTimeTextObj;
private SceneLoader sceneLoader; private SceneLoader sceneLoader;
private StartSeneData startSceneData;
private ButtonActivateColorChanger buttonActivateColorChanger; private ButtonActivateColorChanger buttonActivateColorChanger;
private StartMenuProbabilityPanel startMenuProbabilityPanel; private LevelProbabilityPanel startMenuProbabilityPanel;
private CommonParameterContainer commonParameterContainer;
private float startTime; private float startTime;
private float nowTime; private float nowTime;
// Start is called before the first frame update // Start is called before the first frame update
void Start() void Start()
{ {
sceneLoader = sceneLoaderObj.GetComponent<SceneLoader>(); sceneLoader = sceneLoaderObj.GetComponent<SceneLoader>();
startSceneData = startSceneDataObj.GetComponent<StartSeneData>();
buttonActivateColorChanger = GetComponent<ButtonActivateColorChanger>(); buttonActivateColorChanger = GetComponent<ButtonActivateColorChanger>();
startMenuProbabilityPanel = targetLevelProbabilityPanelOBJ.GetComponent<StartMenuProbabilityPanel>(); startMenuProbabilityPanel = targetLevelProbabilityPanelOBJ.GetComponent<LevelProbabilityPanel>();
commonParameterContainer = CommonParameterContainer.Instance;
messageTextObj.text = ""; messageTextObj.text = "";
buttonActivateColorChanger.InitializeAllButtonColor(); buttonActivateColorChanger.InitializeAllButtonColor();
} }
@ -36,15 +35,19 @@ private void Update()
waitTimeTextObj.text = ((int)Math.Round(leftTime)).ToString(); waitTimeTextObj.text = ((int)Math.Round(leftTime)).ToString();
if (leftTime <= 1) if (leftTime <= 1)
{ {
// if time limit is over, load Train Scene // if time limit is over, end game
sceneLoader.LoadGameScene(SceneLoader.SceneType.Train); # if UNITY_EDITOR
UnityEditor.EditorApplication.isPlaying = false;
#else
StopGame();
#endif
} }
} }
// while StartButton-Play Pressed // while StartButton-Play Pressed
public void OnPlayButtonPressed() public void OnPlayButtonPressed()
{ {
startSceneData.gameMode = 1; commonParameterContainer.gameMode = 1;
sceneLoader.LoadGameScene(SceneLoader.SceneType.Play); sceneLoader.LoadGameScene(SceneLoader.SceneType.Play);
messageTextObj.text = "Loading Play Scene..."; messageTextObj.text = "Loading Play Scene...";
} }
@ -52,30 +55,30 @@ public void OnPlayButtonPressed()
public void OnAttackTrainButtonPressed() public void OnAttackTrainButtonPressed()
{ {
// while Train-Attack-Button Pressed // while Train-Attack-Button Pressed
startSceneData.attackProb = 1f; commonParameterContainer.attackProb = 1f;
ApplicateProbabilityToData(); ApplicateProbabilityToData();
LoadTrainScene(); LoadTrainScene();
} }
public void OnGotoTrainButtonPressed() public void OnGotoTrainButtonPressed()
{ {
// while Train-Goto-Button Pressed // while Train-Goto-Button Pressed
startSceneData.gotoProb = 1f; commonParameterContainer.gotoProb = 1f;
ApplicateProbabilityToData(); ApplicateProbabilityToData();
LoadTrainScene(); LoadTrainScene();
} }
public void OnFreeTrainButtonPressed() public void OnFreeTrainButtonPressed()
{ {
// while Train-Free-Button Pressed // while Train-Free-Button Pressed
startSceneData.attackProb = 0f; commonParameterContainer.attackProb = 0f;
startSceneData.gotoProb = 0f; commonParameterContainer.gotoProb = 0f;
startSceneData.defenceProb = 0f; commonParameterContainer.defenceProb = 0f;
LoadTrainScene(); LoadTrainScene();
} }
public void OnMixTrainButtonPressed() public void OnMixTrainButtonPressed()
{ {
// while Train-Mix-Button Pressed // while Train-Mix-Button Pressed
startSceneData.attackProb = 0.333f; commonParameterContainer.attackProb = 0.333f;
startSceneData.gotoProb = 0.333f; commonParameterContainer.gotoProb = 0.333f;
LoadTrainScene(); LoadTrainScene();
} }
private void LoadTrainScene() private void LoadTrainScene()
@ -87,13 +90,20 @@ private void LoadTrainScene()
private void ApplicateProbabilityToData() private void ApplicateProbabilityToData()
{ {
for (int i = 0; i < startSceneData.scenePrefabSet.targetLevels[0].levelSize; i++) for(int targetIndex = 0;targetIndex < commonParameterContainer.scenePrefabSet.targetLevels.Length; targetIndex++)
{ {
startSceneData.gotoLevelProbs.Add(startMenuProbabilityPanel.targetLevelProbabilityPanel[0].singleLevelPanels[i].ProbabilityValue); Targets nowTarget = commonParameterContainer.scenePrefabSet.targets[targetIndex];
} for(int levelIndex = 0; levelIndex < commonParameterContainer.scenePrefabSet.targetLevels[targetIndex].levelSize; levelIndex++)
for(int i = 0; i < startSceneData.scenePrefabSet.targetLevels[1].levelSize; i++) {
{ commonParameterContainer.levelProbs[nowTarget] = startMenuProbabilityPanel.targetLevelProbabilityPanel[targetIndex].GetTargetProb();
startSceneData.attackLevelProbs.Add(startMenuProbabilityPanel.targetLevelProbabilityPanel[1].singleLevelPanels[i].ProbabilityValue); }
} }
} }
private void StopGame()
{
// stop game,end program
Debug.Log("Game End");
Application.Quit();
}
} }

View File

@ -3,27 +3,36 @@
using System.Linq; using System.Linq;
using TMPro; using TMPro;
using UnityEngine; using UnityEngine;
using UnityEngine.EventSystems;
public class TargetLevelProbabilityPanel : MonoBehaviour public class TargetLevelProbabilityPanel : MonoBehaviour
{ {
public GameObject singleLevelProbabilityPanel; [SerializeField] private GameObject singleLevelProbabilityPanel;
public GameObject targetTitleText; [SerializeField] private GameObject targetTitleText;
private GameObject titleText; private GameObject titleText;
public List<GameObject> singleLevelPanelsObjs = new List<GameObject>(); public List<GameObject> singleLevelPanelsObjs = new List<GameObject>();
public List<SingleLevelProbabilityPanel> singleLevelPanels = new List<SingleLevelProbabilityPanel>(); public List<SingleLevelProbabilityPanel> singleLevelPanels = new List<SingleLevelProbabilityPanel>();
private int panelNum = 0; private int panelNum = 0;
private Targets thisTarget;
public void IntializePanels(int levelNum, string titleName) /// <summary>
/// Initializes panels for a specific target, including the title and level probabilities.
/// </summary>
/// <param name="thisTarget">The specified target, used to obtain associated level numbers and probability data.</param>
/// <param name="titleName">The title name for the panel.</param>
/// <remarks>
/// This method first calculates the panel dimensions, then creates and sets the title text. Subsequently, it creates individual probability panels for each level and adds event listeners for sliders and input fields.
/// It relies on the CommonParameterContainer instance to access scene prefab sets and level probabilities.
/// </remarks>
public void IntializePanels(Targets thisTarget, string titleName)
{ {
this.thisTarget = thisTarget;
int levelNum = CommonParameterContainer.Instance.scenePrefabSet.GetLevelNumber(thisTarget);
// initialize target level probability panel size // initialize target level probability panel size
float defaultWidth = singleLevelProbabilityPanel.GetComponent<RectTransform>().sizeDelta.x; float defaultWidth = singleLevelProbabilityPanel.GetComponent<RectTransform>().sizeDelta.x;
float defaultLevelHeight = singleLevelProbabilityPanel.GetComponent<RectTransform>().sizeDelta.y; float defaultLevelHeight = singleLevelProbabilityPanel.GetComponent<RectTransform>().sizeDelta.y;
float titleHeight = targetTitleText.GetComponent<RectTransform>().sizeDelta.y; float titleHeight = targetTitleText.GetComponent<RectTransform>().sizeDelta.y;
float averageProbability = 1f / levelNum;
float lastLevelProbability = 1f - averageProbability * (levelNum - 1);
// Debug.Log("averageProbability: " + averageProbability); // Debug.Log("averageProbability: " + averageProbability);
transform.GetComponent<RectTransform>().sizeDelta = new Vector2(defaultWidth, (defaultLevelHeight * levelNum) + titleHeight); transform.GetComponent<RectTransform>().sizeDelta = new Vector2(defaultWidth, (defaultLevelHeight * levelNum) + titleHeight);
// create title text // create title text
@ -35,7 +44,8 @@ public void IntializePanels(int levelNum, string titleName)
int tempIndex = i; int tempIndex = i;
singleLevelPanelsObjs.Add(Instantiate(singleLevelProbabilityPanel, transform)); singleLevelPanelsObjs.Add(Instantiate(singleLevelProbabilityPanel, transform));
singleLevelPanels.Add(singleLevelPanelsObjs[i].GetComponent<SingleLevelProbabilityPanel>()); singleLevelPanels.Add(singleLevelPanelsObjs[i].GetComponent<SingleLevelProbabilityPanel>());
singleLevelPanels[i].InitializeLevelProbabilityPanel(i, i == levelNum - 1 ? lastLevelProbability : averageProbability); Debug.Log(CommonParameterContainer.Instance.levelProbs.Count);
singleLevelPanels[i].InitializeLevelProbabilityPanel(i, CommonParameterContainer.Instance.levelProbs[thisTarget][i]);
//add onValueChanged event to slider and input field //add onValueChanged event to slider and input field
singleLevelPanels[i].probabilitySlider.onValueChanged.AddListener((value) => OnProbabilityValueChange(value, tempIndex)); singleLevelPanels[i].probabilitySlider.onValueChanged.AddListener((value) => OnProbabilityValueChange(value, tempIndex));
singleLevelPanels[i].inputField.onEndEdit.AddListener((value) => OnProbabilityValueChange(value, tempIndex)); singleLevelPanels[i].inputField.onEndEdit.AddListener((value) => OnProbabilityValueChange(value, tempIndex));
@ -44,22 +54,21 @@ public void IntializePanels(int levelNum, string titleName)
} }
/// <summary> /// <summary>
/// Adds an event trigger entry to an event trigger. /// Retrieves the probability values for all levels of the current target.
/// </summary> /// </summary>
/// <param name="trigger">The event trigger object.</param> /// <returns>A list of floating-point numbers containing the probability values for each level.</returns>
/// <param name="type">The event trigger type.</param> /// <remarks>
/// <param name="action">The event handler method to execute.</param> /// This method iterates through the panels of all levels, collecting and returning the probability value for each level.
private void AddEventTrigger(GameObject gameObject, EventTriggerType triggerType, System.Action<BaseEventData> action) /// It relies on the singleLevelPanels list, which should have been properly initialized and populated before calling this method.
/// </remarks>
public List<float> GetTargetProb()
{ {
EventTrigger eventTrigger = gameObject.GetComponent<EventTrigger>(); List<float> targetProb = new List<float>();
if (eventTrigger == null) for (int i = 0; i < panelNum; i++)
{ {
eventTrigger = gameObject.AddComponent<EventTrigger>(); targetProb.Add(singleLevelPanels[i].ProbabilityValue);
} }
EventTrigger.Entry entry = new EventTrigger.Entry(); return targetProb;
entry.eventID = triggerType;
entry.callback.AddListener(new UnityEngine.Events.UnityAction<BaseEventData>(action));
eventTrigger.triggers.Add(entry);
} }
/// <summary> /// <summary>
@ -75,17 +84,20 @@ private void OnProbabilityValueChange<T>(T value, int exceptedIndex)
case float floatValue: case float floatValue:
changedValue = floatValue; changedValue = floatValue;
break; break;
case string stringValue: case string stringValue:
changedValue = float.Parse(stringValue); changedValue = float.Parse(stringValue);
// limit the value between 0 and 1 // limit the value between 0 and 1
if(changedValue>1 && changedValue <=100) if (changedValue > 1 && changedValue <= 100)
{ {
changedValue /= 100; changedValue /= 100;
}else if(changedValue>100) }
else if (changedValue > 100)
{ {
changedValue = 1; changedValue = 1;
} }
break; break;
default: default:
Debug.LogError("Invalid value type!"); Debug.LogError("Invalid value type!");
throw new ArgumentException("Unsupported value type"); throw new ArgumentException("Unsupported value type");
@ -164,8 +176,19 @@ private void enableSliderListener()
} }
/// <summary> /// <summary>
/// calculate the correction value to each panel,while the total value is not equal to 1 /// Recalculates correction values.
/// </summary> /// </summary>
/// <param name="correctionValues">The current array of correction values.</param>
/// <param name="exceptedIndex">The index of the panel that is expected not to change.</param>
/// <param name="value">The expected probability value.</param>
/// <param name="extraValue">Additional correction value.</param>
/// <param name="maxLimitValue">The maximum limit for the probability value.</param>
/// <returns>Returns a tuple containing a float array and an integer.
/// The float array is the new correction values, and the integer is the number of panels that need to be corrected in the next iteration.</returns>
/// <remarks>
/// This method calculates new correction values based on the provided parameters.
/// During the iteration, some panels might exceed set limits, and their values will need to be corrected in the next iteration.
/// </remarks>
private (float[], int) reCalculateCorrectionValues(float[] correctionValues, int exceptedIndex, float value, float extraValue, float maxLimitValue) private (float[], int) reCalculateCorrectionValues(float[] correctionValues, int exceptedIndex, float value, float extraValue, float maxLimitValue)
{ {
// the number of panels which need to be corrected in next iteration // the number of panels which need to be corrected in next iteration
@ -249,20 +272,20 @@ private void enableSliderListener()
} }
/// <summary> /// <summary>
/// applicate correction value to each panel /// Applies correction values to adjust the probability values for each level of the current target.
/// </summary> /// </summary>
/// <param name="correctionValues">An array of correction values to be applied to the probability value of each level.</param>
/// <remarks>
/// This method iterates through all the level panels, updating the probability by subtracting the corresponding correction value from the probability value of each level.
/// It also synchronously updates the level probabilities for this target stored in the CommonParameterContainer instance.
/// This method assumes that the length of the correctionValues array matches the number of level panels.
/// </remarks>
private void applyCorrectionValue(float[] correctionValues) private void applyCorrectionValue(float[] correctionValues)
{ {
for (int i = 0; i < panelNum; i++) for (int i = 0; i < panelNum; i++)
{ {
/* if (singleLevelPanels[i].ProbabilityValue - correctionValues[i] < 0)
{
Debug.LogWarning("Probability value is less than 0");
Debug.Log(i);
Debug.Log(singleLevelPanels[i].ProbabilityValue);
Debug.Log(correctionValues[i]);
}*/
singleLevelPanels[i].SetProbability(singleLevelPanels[i].ProbabilityValue - correctionValues[i]); singleLevelPanels[i].SetProbability(singleLevelPanels[i].ProbabilityValue - correctionValues[i]);
CommonParameterContainer.Instance.levelProbs[thisTarget][i] = singleLevelPanels[i].ProbabilityValue;
} }
} }
} }

View File

@ -1,5 +1,4 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel;
using UnityEngine; using UnityEngine;
using UnityEngine.EventSystems; using UnityEngine.EventSystems;
using UnityEngine.UI; using UnityEngine.UI;
@ -8,27 +7,27 @@ public class TargetUIController : MonoBehaviour
{ {
// Controller to control the UI of the target, // Controller to control the UI of the target,
// select target type, select prefeb to set or sth. // select target type, select prefeb to set or sth.
public GameObject targetControllerObj;
public GameObject mouseSelectorObj; [SerializeField] private GameObject targetControllerObj;
public GameObject environmentUIObj; [SerializeField] private GameObject mouseSelectorObj;
[SerializeField] private GameObject environmentUIObj;
public float levelButtonHeight = 30; [SerializeField] private float levelButtonHeight = 30;
[Header("PrimaryButton")] [Header("PrimaryButton")]
public Button clearGameButton; [SerializeField] private Button clearGameButton;
public Button setEnemyButton;
public Button setAttackButton; [SerializeField] private Button setEnemyButton;
public Button setGotoButton; [SerializeField] private Button setAttackButton;
public Button setFreeButton; [SerializeField] private Button setGotoButton;
public Button setStayButton; [SerializeField] private Button setFreeButton;
public int primaryButtonNumber = 6; [SerializeField] private Button setStayButton;
[Header("LevelPanel")] [Header("LevelPanel")]
public GameObject gotoLevelPanel; [SerializeField] private GameObject gotoLevelPanel;
public GameObject attackLevelPanel; [SerializeField] private GameObject attackLevelPanel;
public float levelPanelAnimeTime = 0.2f; [SerializeField] private float levelPanelAnimeTime = 0.2f;
private MouseInMap mouseInMapCon; private MouseInMap mouseInMapCon;
private EnvironmentUIControl envUICon; private EnvironmentUIControl envUICon;
@ -92,7 +91,7 @@ public void LevelButtonPressed(PrimaryButtonType primaryButtonType, int level =
public void ClearGamePressed() public void ClearGamePressed()
{ {
// Clear all enemies and targets. set gamemode to Stay mode // Clear all enemies and targets. set gamemode to Stay mode
targetCon.StayModeChange(); targetCon.PlayTargetChange(Targets.Stay);
mouseInMapCon.ChangeMouseMode(MouseInMap.MouseMode.Default); mouseInMapCon.ChangeMouseMode(MouseInMap.MouseMode.Default);
// disable setStayButton and enable other buttons // disable setStayButton and enable other buttons
buttonColorChanger.ChangeInteractableColor(clearGameButton, true); buttonColorChanger.ChangeInteractableColor(clearGameButton, true);
@ -101,14 +100,14 @@ public void ClearGamePressed()
buttonColorChanger.ChangeInteractableColor(setGotoButton, true); buttonColorChanger.ChangeInteractableColor(setGotoButton, true);
buttonColorChanger.ChangeInteractableColor(setFreeButton, true); buttonColorChanger.ChangeInteractableColor(setFreeButton, true);
buttonColorChanger.ChangeInteractableColor(setStayButton, false); buttonColorChanger.ChangeInteractableColor(setStayButton, false);
targetCon.PlayInitialize(); targetCon.PlayModeInitialize();
} }
// Set Free Button Pressed, change Target mode to free mode // Set Free Button Pressed, change Target mode to free mode
public void SetFreePressed() public void SetFreePressed()
{ {
mouseInMapCon.ChangeMouseMode(MouseInMap.MouseMode.Default); mouseInMapCon.ChangeMouseMode(MouseInMap.MouseMode.Default);
targetCon.FreeModeChange(); targetCon.PlayTargetChange(Targets.Free);
buttonColorChanger.ChangeInteractableColor(setStayButton, true); buttonColorChanger.ChangeInteractableColor(setStayButton, true);
buttonColorChanger.ChangeInteractableColor(setAttackButton, true); buttonColorChanger.ChangeInteractableColor(setAttackButton, true);
buttonColorChanger.ChangeInteractableColor(setGotoButton, true); buttonColorChanger.ChangeInteractableColor(setGotoButton, true);
@ -119,7 +118,7 @@ public void SetFreePressed()
public void SetStayPressed() public void SetStayPressed()
{ {
mouseInMapCon.ChangeMouseMode(MouseInMap.MouseMode.Default); mouseInMapCon.ChangeMouseMode(MouseInMap.MouseMode.Default);
targetCon.StayModeChange(); targetCon.PlayTargetChange(Targets.Stay);
buttonColorChanger.ChangeInteractableColor(setStayButton, false); buttonColorChanger.ChangeInteractableColor(setStayButton, false);
buttonColorChanger.ChangeInteractableColor(setAttackButton, true); buttonColorChanger.ChangeInteractableColor(setAttackButton, true);
buttonColorChanger.ChangeInteractableColor(setGotoButton, true); buttonColorChanger.ChangeInteractableColor(setGotoButton, true);
@ -162,9 +161,9 @@ private void SetAttackPressed(int level)
/// <param name="levelPanel">The level panel object containing the level buttons.</param> /// <param name="levelPanel">The level panel object containing the level buttons.</param>
private void AddLevelButtonToColorChanger(GameObject levelPanel) private void AddLevelButtonToColorChanger(GameObject levelPanel)
{ {
foreach(Button btn in levelPanel.GetComponent<LevelPanel>().LevelButtonList) foreach (Button btn in levelPanel.GetComponent<LevelPanel>().LevelButtonList)
{ {
buttonColorChanger.AddButtonToColorChangerButtonList(btn,true); buttonColorChanger.AddButtonToColorChangerButtonList(btn, true);
} }
} }

View File

@ -1,18 +1,36 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine; using UnityEngine;
public class UIColorContainer : MonoBehaviour [CreateAssetMenu(fileName = "UIColors", menuName = "UI/UIColors")]
public class UIColorContainer : ScriptableObject
{ {
// Start is called before the first frame update [System.Serializable]
void Start() public struct UIButtonStateColors
{ {
public Color32 text;
public Color32 bg;
} }
// Update is called once per frame public UIButtonStateColors normal = new UIButtonStateColors()
void Update()
{ {
text = new Color32(236, 236, 236, 255),
} bg = new Color32(255, 255, 255, 0)
};
public UIButtonStateColors highLight = new UIButtonStateColors()
{
text = new Color32(41, 41, 41, 230),
bg = new Color32(255, 255, 255, 103)
};
public UIButtonStateColors pressed = new UIButtonStateColors()
{
text = new Color32(0, 0, 0, 240),
bg = new Color32(255, 255, 255, 160)
};
public UIButtonStateColors disabled = new UIButtonStateColors()
{
text = new Color32(180, 180, b: 180, 80),
bg = new Color32(255, 255, b: 255, 0)
};
} }

View File

@ -4,7 +4,7 @@
public class WorldUIController : MonoBehaviour public class WorldUIController : MonoBehaviour
{ {
public LineChart winChart; [SerializeField] private LineChart winChart;
public int[] totalGames; public int[] totalGames;
public int[] winGames; public int[] winGames;
@ -26,32 +26,33 @@ private void Start()
} }
} }
public void UpdateChart(int targetType, int endType) public void UpdateChart(Targets targetType, int endType)
{ {
float winRatio = 0f; float winRatio = 0f;
int targetTypeInt = (int)targetType;
switch (endType) switch (endType)
{ {
case (int)TargetController.EndType.Win: case (int)TargetController.EndType.Win:
//Win //Win
totalGames[targetType] += 1; totalGames[targetTypeInt] += 1;
winGames[targetType] += 1; winGames[targetTypeInt] += 1;
winRatio = (float)winGames[targetType] / totalGames[targetType]; winRatio = (float)winGames[targetTypeInt] / totalGames[targetTypeInt];
winChart.AddData(targetType, winRatio); winChart.AddData(targetTypeInt, winRatio);
if (totalGames[targetType] > maxXAxis) if (totalGames[targetTypeInt] > maxXAxis)
{ {
maxXAxis = totalGames[targetType]; maxXAxis = totalGames[targetTypeInt];
winChart.AddXAxisData(Convert.ToString(maxXAxis)); winChart.AddXAxisData(Convert.ToString(maxXAxis));
} }
break; break;
case (int)TargetController.EndType.Lose: case (int)TargetController.EndType.Lose:
//lose //lose
totalGames[targetType] += 1; totalGames[targetTypeInt] += 1;
winRatio = (float)winGames[targetType] / totalGames[targetType]; winRatio = (float)winGames[targetTypeInt] / totalGames[targetTypeInt];
winChart.AddData(targetType, winRatio); winChart.AddData(targetTypeInt, winRatio);
if (totalGames[targetType] > maxXAxis) if (totalGames[targetTypeInt] > maxXAxis)
{ {
maxXAxis = totalGames[targetType]; maxXAxis = totalGames[targetTypeInt];
winChart.AddXAxisData(Convert.ToString(maxXAxis)); winChart.AddXAxisData(Convert.ToString(maxXAxis));
} }
break; break;

View File

@ -0,0 +1,151 @@
using DG.Tweening; // Importing the DOTween library for smooth animations.
using UnityEngine;
using UnityEngine.EventSystems; // Using the EventSystem to handle UI interactions.
public class UIVisibilityController : MonoBehaviour
{
[SerializeField]
private GameObject targetUIObj;
[SerializeField]
private GameObject triggerUIObj;
[SerializeField]
private GameObject canvasObj;
[SerializeField]
private Vector3 slideDirection = Vector3.zero;
[SerializeField]
private Vector3 slideDistance = Vector3.zero;
[SerializeField]
private float slideDuration = 0.2f;
// Cached positions and states for logic and animation.
private Vector3 targetOriginalPosition;
private Vector3 triggerOriginalPosition;
private Vector3 targetEndPosition;
private Vector3 triggerEndPosition;
private Vector3 originalCanvasPosition;
private bool isInActive = true; // Indicates if the UI is currently inactive.
private bool isOutActive = false; // Indicates if the UI is currently active.
private bool isMouseInTarget = false; // Is the mouse currently over the target UI?
private bool isMouseInTrigger = false; // Is the mouse currently over the trigger UI?
private void Start()
{
// Initial setup of component's states and values.
InitializeCanvasPosition();
InitializeSlideValues();
InitializeEventTrigger();
}
private void InitializeCanvasPosition()
{
if (canvasObj == null)
{
// Set canvasObj to the parent if not assigned.
canvasObj = transform.parent.gameObject;
}
originalCanvasPosition = canvasObj.transform.position;
}
private void InitializeSlideValues()
{
if (slideDirection == Vector3.zero)
{
// default slide direction is up (set to right).
slideDirection = Vector3.right;
Debug.LogError("SliderDirection not set, set default right");
}
if (slideDistance == Vector3.zero)
{
// default slide distance is based on targetUIObj dimensions.
RectTransform targetRT = targetUIObj.GetComponent<RectTransform>();
slideDistance = new Vector3(targetRT.rect.width, targetRT.rect.height, 0);
}
// Determine the start and end positions for sliding.
targetOriginalPosition = targetUIObj.transform.position;
triggerOriginalPosition = triggerUIObj.transform.position;
targetEndPosition = targetOriginalPosition + Vector3.Scale(slideDirection, slideDistance);
triggerEndPosition = triggerOriginalPosition + Vector3.Scale(slideDirection, slideDistance);
}
private void InitializeEventTrigger()
{
// Setting up event triggers for mouse interactions.
EventTrigger triggerObjET = triggerUIObj.GetComponent<EventTrigger>();
if (triggerObjET == null)
{
triggerObjET = triggerUIObj.AddComponent<EventTrigger>();
}
EventTrigger targetObjET = targetUIObj.GetComponent<EventTrigger>();
if (targetObjET == null)
{
targetObjET = targetUIObj.AddComponent<EventTrigger>();
}
triggerObjET.AddEventTrigger(EventTriggerType.PointerEnter, (eventData) => OnMouseIn(triggerUIObj));
triggerObjET.AddEventTrigger(EventTriggerType.PointerExit, (eventData) => OnMouseOut(triggerUIObj));
targetObjET.AddEventTrigger(EventTriggerType.PointerEnter, (eventData) => OnMouseIn(targetUIObj));
targetObjET.AddEventTrigger(EventTriggerType.PointerExit, (eventData) => OnMouseOut(targetUIObj));
}
private void Update()
{
// Check mouse interactions to determine whether to slide in or out the UI.
if ((isMouseInTrigger || isMouseInTarget) && isInActive)
{
SlideInScreen();
isInActive = false;
isOutActive = true;
}
else if (!isMouseInTrigger && !isMouseInTarget && isOutActive)
{
SlideOutScreen();
isInActive = true;
isOutActive = false;
}
}
private void OnMouseIn(GameObject type)
{
// Update flags based on which UI object the mouse enters.
if (type == triggerUIObj)
{
isMouseInTrigger = true;
}
else if (type == targetUIObj)
{
isMouseInTarget = true;
}
}
private void OnMouseOut(GameObject type)
{
// Update flags based on which UI object the mouse exits.
if (type == triggerUIObj)
{
isMouseInTrigger = false;
}
else if (type == targetUIObj)
{
isMouseInTarget = false;
}
}
private void SlideInScreen()
{
// Animate the UI objects to slide in.
triggerUIObj.transform.DOMove(triggerEndPosition, slideDuration).SetEase(Ease.OutCirc).Play();
targetUIObj.transform.DOMove(targetEndPosition, slideDuration).SetEase(Ease.OutCirc).Play();
}
private void SlideOutScreen()
{
// Animate the UI objects to slide out.
triggerUIObj.transform.DOMove(triggerOriginalPosition, slideDuration).SetEase(Ease.OutCirc).Play();
targetUIObj.transform.DOMove(targetOriginalPosition, slideDuration).SetEase(Ease.OutCirc).Play();
}
}

View File

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

155
README-JP.md Normal file
View File

@ -0,0 +1,155 @@
# Aimbot-ParallelEnv
これはUnity ML-Agentsに基づいたFPSゲームのマルチエージェントトレーニング環境で、特定の目標と対応する難易度を生成し、エージェントのアクションに基づいて報酬をフィードバックして強化学習エージェントをトレーニングするための環境です。
[![Chinese badge](https://img.shields.io/badge/简体中文-Simplified_Chinese-blue)](./README.md)
[![Japanese badge](https://img.shields.io/badge/日本語-Japanese-blue)](./README-JP.md)
## Description
プロジェクトは[ML-Agents 2.0.1](https://github.com/Unity-Technologies/ml-agents/tree/develop)を基にして、Unity 2021.3.14f1を使用して開発されています。
Python側では、[mlagents-envs 0.30.0](https://pypi.org/project/mlagents-envs/)を使用してゲーム環境と通信を行います。
## Quick start
プロジェクト[Aimbot-PPO](https://koha9.asuscomm.com/yurugit/Koha9/Aimbot-PPO)では、この環境を使用してPPOアルゴリズムのトレーニングが行われています。具体的な使用例は[AimbotEnv.py](https://koha9.asuscomm.com/yurugit/Koha9/Aimbot-PPO/src/branch/OffP-FullMNN-V2/Aimbot-PPO-Python/Pytorch/AimbotEnv.py)で記載されています。
## ゲーム環境の概要
本環境は初代Doomの基本モードを模したFPSゲームで、エージェントには異なる目標が与えられます。エージェントは目標の種類と位置、自身の状態に基づいて、撃つかどうか、撃つ方向、移動方向を決定します。この環境には2つのモードと3種類の目標があります訓練モードとテストモード、そして`FreeTarget`、`GotoTarget`、`AttackTarget`です。`FreeTarget`では、エージェントは武器を使ってエリア内のすべての敵を倒す必要があります。`GotoTarget`と`AttackTarget`では、エリア内に目標ブロックが生成され、エージェントはそれに応じた異なる行動を取る必要があります。さらに、`GotoTarget`と`AttackTarget`では、生成される目標ブロックの構造に応じて5つの異なる難易度に分けられています。
## ゲームの概要
この環境は初代Doomの基本モードを模したFPSゲームで、エージェントには異なる目標が与えられます。エージェントは目標の種類と位置、自身の状態に基づいて、撃つかどうか、撃つ方向、移動方向を決定します。この環境には2つのモードと3種類の目標があります訓練モードとテストモード、そして`FreeTarget`、`GotoTarget`、`AttackTarget`です。`FreeTarget`では、エージェントは武器を使ってエリア内のすべての敵を倒す必要があります。`GotoTarget`と`AttackTarget`では、エリア内に目標ブロックが生成され、エージェントはそれに応じた異なる行動を取る必要があります。さらに、`GotoTarget`と`AttackTarget`では、生成される目標ブロックの構造によって、5つの異なる難易度に分けられています。
## モード
訓練モードとテストモードは、Python側と通信が必要で、この環境から観測されたObservationに基づいてActionを生成し、環境にフィードバックします。環境を起動する際、ゲーム内でユーザーが操作してモードを選択する必要があります。ML-Agentsにはタイムリミットが存在するため、45秒以内にモードを選択する必要があります。45秒を超えると、自動的にゲーム環境から退出します。
### 訓練モード
訓練モードに入る前に、手動でスタート画面から`Train-Free`、`Train-Goto`、`Train-Attack`(単一モードの訓練)または`Train-Mix`(全モードの訓練)の中から選択する必要があります。選択後、訓練モードに入りますが、この選択は後で変更できません。複数の難易度がある目標ブロック`Train-Goto`と`Train-Attack`のモードでは、スタート画面に異なる難易度の目標ブロックを生成する確率を調整するパネルが画面の左上にあります。デフォルトでは、各難易度の生成確率は均等となっています。このパネルでは、各モードの難易度の合計確率が1になるように、一つの難易度の確率を調整すると他の難易度の確率が自動的に調整されます。ユーザーは右側のロックボタンをクリックして、特定の難易度の確率をロックまたは解除することができます。このパネルは訓練モードの実行中にも表示され、ユーザーが訓練中に確率パネルを調整すると、次の目標ブロックの生成時に適用されます。
<br>![TargetLevelProbabilityPanel](./ReadmeImages/LevelProbabilityPanel.jpg)
### テストモード
テストモードでは、ユーザーが手動でエージェントに命令を指定する必要があります。画面右上のメニューをクリックすることで、目標ブロックや敵を生成したり、目標モードを切り替えたりすることができます。このモードでは、訓練モードにはない新しいターゲット`StayTarget`が追加されています。ユーザーが特定の目標を指定しない場合やゲームをクリアした場合、`StayTarget`がエージェントに割り当てられます。右上隅のメニューをクリックすると、マウスモードを切り替えて敵Enemyを生成するモードや、特定の難易度のターゲットブロックを生成するモードに変更できます。マウスがブロック生成モードで、マウスをゲームエリアに移動すると、生成するオブジェクトのプレビューが表示され、マウスの右クリックで指定した位置に対応する敵やブロックを生成できます。ターゲットブロックを生成すると、対応するターゲットが自動的にエージェントに割り当てられます。`FreeTarget`を割り当てる必要がある場合は、`FreeMode`ボタンをクリックします。`ClearGame`をクリックすると、すべての敵とブロックがクリアされ、エージェントのターゲットが`StayTarget`に設定されます。`StayMode`をクリックすると、エージェントのターゲットを強制的に`StayTarget`に設定できます。
## Target
### FreeTarget
エージェントが`FreeTarget`に割り当てられた場合、エージェントはエリア内のすべての敵を武器で倒す必要があります。このモードでは、ラウンド開始時にエリア内にランダムな数の敵が生成されますデフォルトは6体。エージェントはエリアのランダムな位置に生成され、向きは前回のラウンドを引き継ぎます最初のラウンドの場合はデフォルトで角度0。エージェントがすべての敵を倒せば勝利と判断され、30秒以内にすべての敵を倒せない場合は失敗と判断されます。
### GotoTarget
エージェントが`GotoTarget`に割り当てられた場合、指定された目標エリアの特定の位置に移動することが目標です。このモードでは、ラウンドが始まるとエージェントの位置は前のラウンドを引き継ぎます最初のラウンドではマップの左下隅にデフォルトで生成されます。Gotoの目標ブロックは、難易度の確率に応じてエリア内にランダムに生成され、異なる難易度には複数のプリセットブロックが用意されています。これらのプリセットブロックは[`SceneBlocksSet`](https://koha9.asuscomm.com/yurugit/Koha9/Aimbot-ParallelEnv/src/branch/main/Assets/Script/TargetContainer/SceneBlocksSet.cs)によって[Prefabフォルダ](https://koha9.asuscomm.com/yurugit/Koha9/Aimbot-ParallelEnv/src/branch/main/Assets/Prefeb)に保存されています。すべての目標ブロックの合計サイズは10x10で、ブロックが生成される際にはエージェントの位置を避けます。指定された目標エリアは`FireBase`と呼ばれる円形のエリアで、その範囲は目標ブロックを超えることはありませんが、位置とサイズはプリセットブロックによって異なります。エージェントが目標ブロックの中心位置に正常に移動すると勝利と判断され、30秒以内に中心位置に移動できない場合は失敗と判断されます。
### AttackTarget
エージェントが`AttackTarget`に割り当てられた場合、目標エリアに火力を集中し、主な目標はブロック内のすべての敵を倒すことです。このモードでのエージェントと目標ブロックの生成戦略、および`FireBase`の構成は`GotoTarget`と同様です。しかし、`AttackTarget`の`FireBase`エリア内には必ず敵が生成されます。エージェントがブロック内のすべての敵を倒せば勝利と判断され、30秒以内にすべての敵を倒せない場合は失敗と判断されます。
---
# Environment
## Observation Space
本強化学習訓練設定では、状態(State)は環境を理解し、分析する上での鍵となります。観測環境は3つの主要な部分で構成されています`TargetState`(ターゲット状態)、`AgentState`(自機状態)、そして`RaycastState`レイキャスト状態。これらの観測データはML-Agentsの`VectorSensor`クラスを通じて収集され、Python側に送信され、意思決定に必要な情報を提供します。Observationのソースコードは[`MLAgentsCustomController.cs`](https://koha9.asuscomm.com/yurugit/Koha9/Aimbot-ParallelEnv/src/branch/main/Assets/Script/GameScript/MLAgentsCustomController.cs)にあるoverrideされた`CollectObservations`関数内に格納されています。
### TargetStateターゲット状態
`TargetState`は、エージェントが受け取ったTargetとその関連情報を含んで、合計六つあります。ターゲットの種類、x,y,z座標、TargetAreaの直径、そしてエージェントがTargetArea内にいるか、およびそのラウンドの残り時間などの情報を含みます。
| 番号 | 観測項目 | サイズ | 状態空間 | 説明 |
|------|-----------------|-------|------------|---------------------------------------------------------------------------------------------------------------|
| 0 | Targetの種類 | 1 | 0,1,2,3,4 | 割り当てられたTargetの種類を記述0=FreeTarget、1=GotoTarget、2=AttackTarget、3=DefenceTarget未使用、4=StayTarget |
| 1~3 | Targetの座標 | 3 | 0~47 | Target中のFirebaseの連続空間座標を記述、範囲は0から47の連続値 |
| 4 | FireBaseの直径 | 1 | 1~10 | FireBaseの直径を記述、範囲は1から10の連続値 |
| 5 | InFireBase状態 | 1 | 0,1 | エージェントがFireBase内にいるかどうかを記述、0=False、1=True |
| 6 | 残り時間 | 1 | 0~30 | ラウンドの残り時間を記述、範囲は0から30の連続値 |
### AgentState自機の状態
`AgentState`は、エージェントの武器が攻撃可能な状態かどうか、エージェントのx, y, z座標、およびエージェントの向きの角度を含んでいます。エージェントのGameObjectの向きの角度を直接使用すると、0から360度の変化時に値が大幅に変化してしまいます。より良い周期的な表現を実現するために、エージェントのGameObjectの回転角度のコサインとサインの値を使用してエージェントの向きを表しています。
| 番号 | 観測項目 | サイズ | 状態空間 | 説明 |
|------|------------|-------|---------|---------------------------------------------------------------------------------------|
| 7 | GunState | 1 | 0,1 | エージェントの武器が使用可能な状態かどうかを記述。0=False、1=True |
| 8~10 | エージェントの座標 | 3 | 0~47 | エージェントの連続空間座標を記述、範囲は0から47の連続値 |
| 11~12| エージェントの向き | 2 | -1~1 | エージェントのGameObjectの回転角度のcosとsin値を計算してエージェントの正面の向きを記述。 |
### RaycastState視野状態
`RaycastState`はエージェント視界内で発射されたレイキャストが検出したオブジェクトのタグとその距離を記録します。タグはラベルエンコーディングとワンホットエンコーディングの2つの方法で記録することができ、デフォルトではラベルエンコーディングが使用されます。これは`CommonParameterContainer`オブジェクトで調整することが可能です。`RaycastState`は[`RaySensors`](https://koha9.asuscomm.com/yurugit/Koha9/Aimbot-ParallelEnv/src/branch/main/Assets/Script/GameScript/RaySensors.cs)クラスによって管理されており、非均一なレイキャストの分布が実装されています。デフォルトでは、視界の中央15のエリアに射線がより密集して分布し、両側はより希薄です。中央の密集エリアからは5本の射線が、両側の希薄エリアからはそれぞれ7本の射線が発射されます。各レイキャストが検出可能な最大距離は100ユニットで、その距離を超えると0が返されます。視界の中央エリアのカバー範囲、エリア内のレイキャスト数、検出可能な距離は、各`Agent`のGameObjectのInspectorで調整できます。
<br><img src="./ReadmeImages/RayCastLayout.png" alt = "射線の分布方式" width="500" height = "auto">
| 番号 | 観測項目 | サイズ | 状態空間 | 説明 |
|-------------------------------------------------------------------|-------------------|---------------------|--------------|----------------------------------------------------------------------------------------|
| 11~Raynum+11 | TagType(Label) | Raycast数 | 0, 1, 2 | レイキャストが検出した物体のタグ。0=Wall, 1=Enemy, 2=Player, -1=Nothing |
| 11~Raynum * 3+11 | TagType(Onehot) | Raycast数 * 3 | 0, 1 | レイキャストが検出した物体のタグ。ワンホットエンコーディングで記録 |
| Raynum+12~2* Raynum+12ラベル,<br>3* Raynum+12~4* Raynum+12ワンホット | 距離 | Raycast数 | 0~MaxDistance| レイキャストが検出した物体までの距離。範囲は0〜MaxDistance。MaxDistanceのデフォルトは100 |
*注nは各エージェントのRaycast数、MaxDistanceは各エージェントのレイキャストの最大探知距離を指します。*
## Action Space
FPSゲームにおけるプレイヤーのキーボードとマウスの同時操作をシミュレートするため、本環境のActionSpaceは`Discrete Action`(離散動作)と`Continuous Action`連続動作の2つの部分に分かれています。`Discrete Action`はプレイヤーのキーボードによる離散的な操作を模擬し、`Continuous Action`はマウスによる連続的な操作を模擬します。両方のActionSpaceに対応する操作は[`MLAgentsCustomController.cs`](https://koha9.asuscomm.com/yurugit/Koha9/Aimbot-ParallelEnv/src/branch/main/Assets/Script/GameScript/MLAgentsCustomController.cs)内のoverrideされた`Heuristic`関数で参照できます。具体的な実装は[`AgentController.cs`](https://koha9.asuscomm.com/yurugit/Koha9/Aimbot-ParallelEnv/src/branch/main/Assets/Script/GameScript/Character/AgentController.cs)内の`MoveAgent`関数と`CameraControl`関数にあります。
### Discrete Action離散動作
`Discrete Action`では、エージェントは各方向の移動と攻撃を離散的に操作できます。移動操作には垂直移動と水平移動が含まれ、攻撃操作では武器の操作が可能です。
| 番号 | 動作 | ActionSpace | 説明 |
|------|-------------------|----------------|---------------------------------------------------------------------------|
| 0 | 垂直移動 | 0, 1, -1 | エージェントをその正面方向の垂直軸で制御。0=停止、1=前進、-1=後退 |
| 1 | 水平移動 | 0, 1, -1 | エージェントをその正面方向の水平軸で制御。0=停止、1=右移動、-1=左移動 |
| 2 | 攻撃 | 0, 1 | エージェントの攻撃操作を制御。0=攻撃しない、1=攻撃する |
### Continuous Action連続動作
`Continuous Action`では、エージェントの視点を制御できます。本環境は初期のDoomのFPS環境を模擬しているため、エージェントの視点は水平方向のみで回転可能と設定されています。
| 番号 | 動作 | ActionSpace | 説明 |
|------|-------------------|----------------|---------------------------------------------------------------------------------|
| 0 | 水平回転 | -Inf ~ Inf | エージェントの水平方向(左右)の視角回転を制御。正の値で右に、負の値で左に回転する。 |
## Reward
与えられた各ターゲットにおいて、エージェントが異なるタスクを達成することに注力するため、リワードの設計もそれぞれ異なります。訓練モードでは、リワードは共通リワード「Common Reward」と各ターゲット専用のリワードで構成されています。
### Common Reward共通リワード
エージェントが訓練中に目標達成に役立つ行動を取るように導き、無意味な動作を避けるために、`Common Reward`では以下のリワードとペナルティが設計されています。ML-AgentsはPythonに直接ラウンド終了の結果を伝えることができないため、他のリワードの値が小さすぎたり大きすぎたりして勝利または失敗を判断できない場合に備えて、ラウンド終了時のリワードには極大値と極小値が追加されています。
| リワード/ペナルティ | 値/シンボル | 説明 |
|-------------------|----------------|---------------------------------------------------------------|
| 非ターゲット命中 | 3 | エージェントがターゲットではない敵を撃つか倒すと得られるリワード |
| ターゲット命中 | 25 | エージェントがターゲットとなる敵を撃つか倒すと得られるリワード |
| 移動ペナルティ | -0.5 | エージェントがフィールド上を移動するときに与えられるペナルティ |
| 回転ペナルティ | $P_s$ | エージェントが視点を回転するときに与えられるペナルティ |
| 勝利リワード | 999 | ラウンドが終了し、そのラウンドでエージェントが目標を達成したときに与えられるリワード |
| 失敗リワード | 999 | ラウンドが終了し、そのラウンドでエージェントが失敗したときに与えられるリワード |
エージェントが訓練中に無意味な回転を行わないように、また回転速度が速すぎないように、以下の関数を使用して`SpinPenalty`を与えます。40個のマウス操作の回転記録が閾値に達していない場合、小さなペナルティが与えられます。閾値を超えると、エージェントが同じ方向に持続的に回転していることがわかるので、大きなペナルティが与えられます。ここでの<i>P<sub>s<sub>t</sub></sub></i>は時刻`t`の回転ペナルティ、<i>mouseX<sub>t</sub></i>は時刻`t`のエージェントの`Contunuouse Action`内の回転アクションの値を指します。
$$
P_{st} =
\begin{cases}
-|mouseX_t| \cdot 0.06 &, & \left| \sum_{t=0}^{-40} mouseX_t \cdot 0.08 \right| < 10 \\
-\left| \sum_{t=0}^{-40} mouseX_t \cdot 0.08 \right| & , & \left| \sum_{t=0}^{-40} mouseX_t \cdot 0.08 \right| \geq 10
\end{cases}
$$
### FreeTarget
`FreeTarget`では、主な目標は全ての敵を消滅させることです。そのため、敵を追跡する能力が非常に重要です。このモードでは、2種類の報酬メカニズムが設定されています視界の中心で敵を検出した場合、エージェントには2の報酬が与えられます。敵を検出しなかった場合、視界の中心から検出された敵までの距離 \(D\) に基づいて2未満の報酬が与えられます。距離の計算は、Raycastで検出された敵にのみ考慮され、距離が0.5に近づくほど、つまり敵の半径がRewardに近づくほど、報酬は2に近づきます。たとえば、下図では`Enemy1`と`Enemy3`との距離のみが計算され、最短距離 \(D_1\) が報酬の計算に使用されます。検出されなかった`Enemy2`と`Enemy4`は除外されます。このモードでは、すべての敵がターゲットと見なされ、敵が倒されたり、ヒットした場合、エージェントは`Common Reward`の`TargetHit Reward`を獲得します。
<br><img src="./ReadmeImages/FreeTargetFacingreward.png" alt = "FacingReward" width="500" height = "auto">
| 報酬/ペナルティ | 値/記号 | 説明 |
|----------------|----------------|-----------------------------------------|
| FacingReward | \(R_f\) | 視界の中心と検出された最も近い敵との距離に基づく報酬 |
$$
R_{f} =
\begin{cases}
2 &, &min(D) \leq 0.5 \\
\frac{1}{\sqrt{\frac{min(D)}{2}}} &,& min(D) \gt 0.5
\end{cases}
$$
### GotoTarget
`GotoTarget`では、主な目標は指定された`FireBase`への移動です。時刻 \(t\) と \(t-1\) でのプレイヤーとターゲット間の距離 \(D_t\) と \(D_{t-1}\) の差に基づいて、各ステップで獲得できる距離報酬 \(R_d\) が設定されています。エージェントが目標に近づくと正の報酬が与えられ、目標から離れると0未満のペナルティが与えられます。プレイヤーが`FireBase`内にいる場合、より高い固定報酬を得ることができますが、この場合`DistanceReward`は効果を発揮しません。このモードでは、すべての敵は攻撃対象とは見なされませんが、敵をヒットまたは倒した場合、`Common Reward`の`NonTargetHit`を獲得できます。
| 報酬/ペナルティ | 値/記号 | 説明 |
|----------------|---------|----------------------------------------|
| DistanceReward | \(R_d\) | エージェントが目標外にいる際の目標との距離差に基づく報酬 |
| InAreaReward | 5 | エージェントが目標内にいる際の持続報酬 |
$$
R_{d} = (D_{t-1} - D_{t}) \cdot 20
$$
### AttackTarget
`Attack Mode`では、主な目的は目標地点の敵を排除し、エージェントが目標地点に対して行動をとることを奨励することです。したがって、`FreeTarget`と同様に、目標地点への視線の移動も重要です。エージェントが目標地点に面して攻撃する場合、それは抑圧行動と見なされ、より低い`SuppressiveReward`が与えられます。目標地点に面しているが攻撃していない場合、さらに低い`FacingAreaReward`が継続して与えられます。`FireBase`内の敵は目標と見なされ、敵が倒されたりヒットした場合、エージェントは`Common Reward`の`TargetHit Reward`を獲得します。一方、`FireBase`外の敵は目標とは見なされず、敵が倒されたりヒットした場合、エージェントは`Common Reward`の`NonTargetHit Reward`のみを獲得します。
| 報酬/ペナルティ | 値/記号 | 説明 |
|-----------------------|---------|------------------------------------------------|
| SuppressiveReward | 5 | エージェントが`FireBase`に対して抑圧攻撃を行った際の報酬 |
| FacingAreaReward | 2 | エージェントが目標に向かっている間の継続報酬 |
## Side Channel
環境のデバッグやUnityとPython間の非リアルタイム通信を実現するため、この環境ではML-Agentsが提供するSide Channelを使用しています。ここではhuggingfaceの[Custom Side Channels](https://github.com/huggingface/ml-agents-patch/blob/develop/docs/Custom-SideChannels.md)をベースで開発を進みました。Unity側では、Side Channelの実装は[`AimbotSideChannel.cs`](https://koha9.asuscomm.com/yurugit/Koha9/Aimbot-ParallelEnv/src/branch/main/Assets/Script/GameScript/SideChannel/AimbotSideChannel.cs)と[`AimBotSideChannelController.cs`](https://koha9.asuscomm.com/yurugit/Koha9/Aimbot-ParallelEnv/src/branch/main/Assets/Script/GameScript/SideChannel/AimBotSideChannelController.cs)に位置しています。各ログ情報は`|`でフィールドを区切り、最初のフィールドはログのタイプで、次のフィールドはカスタムログ情報です。この環境では、UnityのSide Channelはすべての`LogType.Warning`と`LogType.Error`タイプのログをPython側に送信します。`LogType.Warning`はラウンド終了後の勝敗情報やUnityからPythonへの指示を伝えます。勝敗情報は`Warning|Result|Win`や`Warning|Result|Lose`のようになります。一方、指令は次のトレーニング終了後にモデルを保存するコマンドで、その内容は`Warning|Command`となります。

143
README.md
View File

@ -1 +1,144 @@
# Aimbot-ParallelEnv # Aimbot-ParallelEnv
这是一个基于Unity ML-Agents的基于FPS游戏的多智能体训练环境用于生成指定目标和对应难度并且根据Agent的Action反馈Reward来训练强化学习Agent的环境。
[![Chinese badge](https://img.shields.io/badge/简体中文-Simplified_Chinese-blue)](./README.md)
[![Japanese badge](https://img.shields.io/badge/日本語-Japanese-blue)](./README-JP.md)
## Description
项目基于[ML-Agents 2.0.1](https://github.com/Unity-Technologies/ml-agents/tree/develop)使用Unity 2021.3.14f1开发。
Python侧则使用[mlagents-envs 0.30.0](https://pypi.org/project/mlagents-envs/)与环境进行通信。
## 快速开始
在项目[Aimbot-PPO](https://koha9.asuscomm.com/yurugit/Koha9/Aimbot-PPO)中使用了本环境进行了PPO算法的训练其中在[AimbotEnv.py](https://koha9.asuscomm.com/yurugit/Koha9/Aimbot-PPO/src/branch/OffP-FullMNN-V2/Aimbot-PPO-Python/Pytorch/AimbotEnv.py)中给出了本环境的使用方法。
## 游戏简介
这是一个模仿初代Doom的基本模式的FPS游戏环境Agent将会被给到不同的目标Agent需要根据目标的类型和位置以及自身的状态来决定是否开枪射击射击的方向以及移动方向。环境内包含两种模式和3种目标分别是训练模式和测试模式以及`FreeTarget``GotoTarget`和`AttackTarget`。`FreeTarget`需要Agent使用武器击倒区域内所有的敌人`GotoTarget`和`AttackTarget`会在区域内生成一个目标区块Agent需要对目标区块进行不同的对应来完成任务。同时`GotoTarget`和`AttackTarget`中根据生成目标区块的构造不同分为了5种不同的难度。
## 模式介绍
训练模式和测试模式都需要与Python侧进行通信根据从本环境中观测到的Observation生成Action并传递回本环境。在环境启动时需要使用者在游戏内进行操作来选择模式由于ML-Agents存在Time limit所以需要在45s内进行模式选择超过45s后将自动退出游戏环境。
### 训练模式
在进入训练模式前使用者需要从Start界面中只训练单个模式的`Train-Free``Train-Goto``Train-Attack`和训练所有模式的`Train-Mix`中进行选择。在选择后,将会进入训练模式,并且注意该选择不能在之后进行更改。对于拥有多种难度的目标区块的模式`Train-Goto`和`Train-Attack`在Start界面将会有一个用来调整生成不同难易度目标区块的概率的面板默认的生成概率为平均。面板为了保证该模式各难易度生成概率总和为1在调整某一难度的生成概率时其他难度的生成概率将会被自动调整用户可以通过点击右侧锁定按钮以锁定或解锁某一难度的生成概率。该面板将在训练模式执行中也可见用户在训练模式执行中对概率面板进行调整后将会在应用在下次目标区块生成时。
<br>![TargetLevelProbabilityPanel](./ReadmeImages/LevelProbabilityPanel.jpg)
### 测试模式
测试模式中用户需要手动来对Agent下达命令用户可以通过点击右上角的菜单来执行生成目标区块或敌人切换目标模式等。在该模式中比训练模式多出一个新的Target为StayTarget当用户未指定目标或者清空游戏时将会以将该Target指派给Agent。通过点击右上角的菜单可以将鼠标的模式切换为生成Enemy或者生成对应难度Target区块的模式此时鼠标移动到游戏区域内后将会出现生成物件的预览内点击鼠标右键则可以在对应的位置生成对应的Enemy或者区块。当生成Target区块时会自动指派对应target给agent需要指派`FreeTarget`时则需要点击`FreeMode`按钮。通过点击`ClearGame`可以清空所有enemy和区块并将Agent的目标指派为`StayTarget`,通过点击`StayMode`则可以强制将Agent目标指派为`StayTarget`。
## 目标介绍
### FreeTarget
在Agent被指派到`FreeTarget`时Agent需要使用武器击倒区域内所有的敌人。在该模式中一个回合开始时将会在区域内随机生成一定数量的敌人默认为6Agent将会生成在区域的随机位置Agent朝向继承上一回合如果是第一回合则是默认角度为0。Agent在成功击倒所有敌人后被判断为胜利或者超过30s未能成功击倒所有敌人则被判断为失败。
### GotoTarget
在Agent被指派到`GotoTarget`时Agent的目标是移动到指定目标区块的指定位置。在该模式中一个回合开始时Agent的位置总是继承上一个回合如果是第一回合将会默认生成在地图的左下角。Goto的目标区块将会根据难度概率在区域内随机生成对应难度的预设区块不同难易度拥有多个已保存好的预设区块这些预设区块通过[`SceneBlocksSet`](https://koha9.asuscomm.com/yurugit/Koha9/Aimbot-ParallelEnv/src/branch/main/Assets/Script/TargetContainer/SceneBlocksSet.cs)保存在[Prefab文件夹](https://koha9.asuscomm.com/yurugit/Koha9/Aimbot-ParallelEnv/src/branch/main/Assets/Prefeb)中。所有目标区块的总大小为10*10生成目标区块时区块将会避开Agent的所在位置。指定目标区域是名为`FireBase`的圆形区域该区域所覆盖的范围不会超过目标区块但是它的位置和大小会根据预设区块的不同而不同。Agent在成功移动到目标区块中心位置后被判断为胜利或者超过30s未能成功移动到目标区块中心位置则被判断为失败。
### AttackTarget
在Agent被指派到`AttackTarget`时Agent的目标是对目标区域进行火力压制同时主要目标是击倒区块内所有敌人。在该模式中Agent与目标区块的生成策略还有`FireBase`的构成与`GotoTarget`相同。但是在`AttackTarget`的`FireBase`区域内必定会有Enemy生成。Agent在成功击倒区块内所有敌人后被判断为胜利或者超过30s未能成功击倒区块内所有敌人则被判断为失败。
---
# Environment
## Observation Space
在本强化学习训练设置中,观测数据是理解和交互环境的关键。观测环境由三个主要部分组成:`TargetState`(目标状态)、`AgentState`(自机状态)和`RaycastState`射线探测状态。这些观测数据通过ML-Agents的`VectorSensor`类进行收集并发送给Python侧为决策提供必要的信息。Observation的Source Code位于[`MLAgentsCustomController.cs`](https://koha9.asuscomm.com/yurugit/Koha9/Aimbot-ParallelEnv/src/branch/main/Assets/Script/GameScript/MLAgentsCustomController.cs)中被override的`CollectObservations`函数中。
### TargetState目标状态
`TargetState`包含了Agent接收的目标指令和相关信息,总大小为6。其中包含Target的类型Target的x,y,z坐标TargetArea的直径以及Agent是否处于TargetArea和本回合剩余时间内这些信息。
| Num | Observation | Size | State Space | Description |
|-----|------------------|------|-------------|-------------------------------------------------------------------------------------------------------------|
| 0 | Target类型 | 1 | 0,1,2,3,4 | 描述被指派的Target类型0=FreeTarget1=GotoTarget2=AttackTarget3=DefenceTarget未使用4=StayTarget |
| 1~3 | Target坐标 | 3 | 0~47 | 描述Target中Firebase的连续空间坐标取值范围为0到47之间的连续值 |
| 4 | FireBaseDiameter | 1 | 1~10 | 描述FireBase的直径取值范围为在1到10之间的连续值 |
| 5 | InFireBaseState | 1 | 0,1 | 描述Agent是否处于FireBase中0=False1=True |
| 6 | RemainTime | 1 | 0~30 | 描述本回合剩余时间取值范围为在0到30之间的连续值 |
### AgentState自机状态
`AgentState`包含了Agent的武器可攻击状态Agent的x,y,z坐标和Agent的朝向角度。为了避免直接使用Agent GameObject朝向角度时0到360度变化时值的大幅度跳变同时为了实现更好的周期性表示这里使用了Agent GameObject旋转角度的余弦和正弦值来表示Agent的朝向。
| Num | Observation | Size | State Space | Description |
|------|-------------|------|-------------|---------------------------------------------------------------------|
| 7 | GunState | 1 | 0,1 | 描述Agent武器是否处于可使用状态。0=False1=True |
| 8~10 | Agent坐标 | 3 | 0~47 | 描述Agent的连续空间坐标取值范围为0到47之间的连续值 |
| 11~12 | Agent朝向 | 2 | -1~1 | 通过计算Agent GameObject旋转角度的余弦和正弦以描述Agent的正面朝向。 |
### RaycastState射线探测状态
`RaycastState`记录了视野内发射的射线探测到的Object的Tag及其距离、其中Tag可以通过Label Encoding和OneHot Encoding两种方式来记录默认使用Label Encoding可以在Object`CommonParameterContainer`中进行调整。`RaycastState`由[`RaySensors`](https://koha9.asuscomm.com/yurugit/Koha9/Aimbot-ParallelEnv/src/branch/main/Assets/Script/GameScript/RaySensors.cs)类管理。它实现了射线的非均匀分布默认视野中间15%的区域射线分布更密集两侧则较为稀疏默认中间密集部分共射出5条两侧稀疏部分各7条。 每个射线可探测的对象最远距离为100个单位超过探测距离则返回0。其中视野中间区域的覆盖范围区域内RayCast数量以及可探测距离均可以在每个`Agent`GameObject的Inspector中进行调整。
<br><img src="./ReadmeImages/RayCastLayout.png" alt = "射线分布方式" width="500" height = "auto">
| Num | Observation | Size | State Space | Description |
|------------------------------------------------------------------|-----------------|--------------------|---------------|----------------------------------------------------------------------------------|
| 11~Raynum+11 | TagType(Label) | Number of Raycasts | 0, 1, 2 | 描述Raycast所探测到物体的Tag, 0=Wall, 1=Enemy, 2=Player, -1=Nothing |
| 11~Raynum * 3+11 | TagType(Onehot) | Raynum * 3 | 0, 1 | 描述Raycast所探测到物体的Tag, 使用Onehot编码记录 |
| Raynum+12~2* Raynum+12(Label),<br>3* Raynum+12~4* Raynum+12(OneHot) | Distance | Number of Raycasts | 0~MaxDistance | 描述Raycast所探测到物体的距离取值范围在0~MaxDistance其中MaxDistance默认为100 |
*注n为每个Agent的RayCast数量MaxDistance为每个Agent的RayCast最大探测距离*
## Action Space
为了模拟FPS游戏中玩家对于键盘和鼠标的同时操作本环境中的Action Space分为两个部分分别是`Discrete Action`和`Continuous Action`。其中`Discrete Action`用于模拟玩家对于键盘的离散操作,`Continuous Action`用于模拟玩家对于鼠标的连续操作。两个Action Space的对应操作可以参考于[`MLAgentsCustomController.cs`](https://koha9.asuscomm.com/yurugit/Koha9/Aimbot-ParallelEnv/src/branch/main/Assets/Script/GameScript/MLAgentsCustomController.cs)中被override的`Heuristic`函数。具体实现则于[`AgentController.cs`](https://koha9.asuscomm.com/yurugit/Koha9/Aimbot-ParallelEnv/src/branch/main/Assets/Script/GameScript/Character/AgentController.cs)中的`MoveAgent`和`CameraControl`函数中。
### Discrete Action
在`Discrete Action`中Agent可以对各方向的移动和攻击进行离散操作其中移动操作包括垂直移动操作和水平移动操作攻击操作可以对武器进行操。
| Num | Action | Action Space | Description |
|-----|-----------------|--------------|---------------------------------------------------------------------------|
| 0 | Vertical Move | 0,1,-1 | 用于控制Agent在其正面方向的垂直轴上移动。0=停止1=向前移动,-1=向后移动 |
| 1 | Horizontal Move | 0,1,-1 | 用于控制Agent在其正面方向的水平轴上移动。0=停止1=向右移动,-1=向左移动 |
| 2 | Attack | 0,1 | 用于控制Agent的攻击操作。0=不攻击1=执行攻击 |
### Continuous Action
在`Continuous Action`中可以对Agent的视角进行操作。由于本环境是模拟早期Doom的FPS环境所以Agent的视角被设定为仅能在水平方向上进行旋转。
| Num | Action | Action Space | Description |
|-----|-------------------|--------------|---------------------------------------------------------------------------------|
| 0 | Vertical Rotation | -Inf~Inf | 控制Agent在水平方向左右上的视角旋转。正值使视角向右负值则使视角向左旋转。 |
## Reward
在各给定的目标中为了让Agent注重于完成不同的任务Reward的设计也有所不同。在训练模式中Reward由共同Reward`Common Reward`和各个目标的专用Reward组成。
### Common Reward
为了引导Agent在训练过程中执行对完成目标有帮助的操作和避免无意义的动作在`Common Reward`中环境为Agent设计了以下的Reward和Penalty。其中由于ML-Agents不能向Python直接传递回合结束的结果同时为了避免其他Reward数值过小或者过大导致无法判断胜利或者失败因此在回合结束的Reward中添加了极大数和极小数来表示胜利和失败。
| Reward/Penalty | Value/Symbol | Description |
|----------------|---------------|-----------------------------------------------------|
| NonTargetHit | 3 | 当Agent击中或者击倒不作为Target的敌人时所获得Reward |
| TargetHit | 25 | 当Agent击中或者击倒作为Target的敌人时所获得Reward |
| MovePenalty | -0.5 | 当Agent在场地中移动时给到的Penalty |
| SpinPenalty | $P_s$ | 当Agent进行视角旋转时给到的Penalty |
| WinReward | 999 | 当回合结束并且本回合Agent达成目标时给到的Reward |
| LoseReward | 999 | 当回合结束并且本回合Agent失败时给到的Reward |
为了防止Agent在训练中出现无意义的旋转和旋转过快这里用下列函数来给到Agent一个`SpinPenalty`。当40个Action的旋转记录未达到阈值时会给到一个较小的Penalty而当超过阈值时我们可以知道Agent正在向同一方向持续旋转则给到一个较大的Penalty。其中<i>P<sub>s<sub>t</sub></sub></i>为在`t`时刻时的旋转的Penalty<i>mouseX<sub>t</sub></i>为`t`时刻Agent的`Contunuouse Action`中的旋转Action数值。
$$
P_{st} =
\begin{cases}
-|mouseX_t| \cdot 0.06 &, & \left| \sum_{t=0}^{-40} mouseX_t \cdot 0.08 \right| < 10 \\
-\left| \sum_{t=0}^{-40} mouseX_t \cdot 0.08 \right| & , & \left| \sum_{t=0}^{-40} mouseX_t \cdot 0.08 \right| \geq 10
\end{cases}
$$
### FreeTarget
在`FreeTarget`中主要目标是消灭所有敌人因此追踪敌人的能力非常关键。本模式设置了两种奖励机制当视野中心探测到敌人时给到Agent一个为2的Reward当未探测到敌人时则根据探测到的敌人距离视野中心的距离 $D$ 给到一个小于`2`的Reward。距离的计算仅考虑通过 Raycast 探测到的敌人且当距离越接近0.5即Enemy半径则Reward越接近`2`。例如,在图中,只计算了与`Enemy1`和`Enemy3`的距离,并且取用最短距离 $D_1$ 来计算Reward。未探测到的`Enemy2`和`Enemy4`被排除在外。在这个模式下所有敌人都被视为目标当敌人被击败或击中时Agent 将获得`Common Reward`中的`TargetHit Reward`。
<br><img src="./ReadmeImages/FreeTargetFacingreward.png" alt = "FacingReward" width="500" height = "auto">
| Reward/Penalty | Value/Symbol | Description |
|----------------|----------------------|----------------------------------------|
| FacingReward | $R_f$ | 视野中心与所探测到最近敌人距离的Reward |
$$
R_{f} =
\begin{cases}
2 &, &min(D) \leq 0.5 \\
\frac{1}{\sqrt{\frac{min(D)}{2}}} &,& min(D) \gt 0.5
\end{cases}
$$
### GotoTarget
在`GotoTarget`中,主要目标是向指定的`FireBase`移动。根据在`t`时刻和`t-1`时刻的玩家与目标间的距离 $D_t$ 和 $D_{t-1}$ 的差值,设置了每个 Step 可获得的距离奖励 $R_d$ 。当Agent接近目标时将获得正向Reward远离目标时则获得小于0的Penalty。当玩家处于`FireBase`内时,可以获得更高的固定奖励,然而此时`DistanceReward`将不会生效。在此模式中,所有敌人均不被视为攻击目标,但在击中或击败敌人时,可以获得`Common Reward`中的`NonTargetHit`。
| Reward/Penalty | Value/Symbol | Description |
|----------------|--------------|-----------------------------------------|
| DistanceReward | $R_d$ | Agent不在目标内时和目标的距离差Reward |
| InAreaReward | 5 | Agent处于目标内时的持续奖励 |
$$
R_{d} = (D_{t-1} - D_{t}) \cdot 20
$$
### AttackTarget
在 Attack Mode 中主要目的是消灭目标地点的敌人并鼓励Agent对目标地点进行设计。因此与`FreeTarget`类似将视线移动到目标地点同样重要。当Agent面对目标地点并且进行攻击时将会被视为压制行为并获得较低的`SuppressiveReward`。面对目标地点但未进行攻击时,获得持续获得更低的`FacingAreaReward`。处于`FireBase`中的Enemy将会被视为目标当敌人被击败或击中时Agent 将获得`Common Reward`中的`TargetHit Reward`。而`FireBase`外的敌人则不会被视为目标当敌人被击败或击中时Agent 将只能获得`Common Reward`中的`NonTargetHit Reward`。
| Reward/Penalty | Value/Symbol | Description |
|-------------------|--------------|-----------------------------------------|
| SuppressiveReward | 5 | Agent对`FireBase`进行压制攻击时获得奖励 |
| FacingAreaReward | 2 | Agent面朝目标时获得的持续奖励 |
## Side Channel
为了方便对于环境的调试和实现Unity与Python间非实时通信本环境中使用了ML-Agents提供的Side Channel用于向Python侧传递一些额外的信息。这里我参考了huggingface的[Custom Side Channels](https://github.com/huggingface/ml-agents-patch/blob/develop/docs/Custom-SideChannels.md)。在Unity端Side Channel的实现位于[`AimbotSideChannel.cs`](https://koha9.asuscomm.com/yurugit/Koha9/Aimbot-ParallelEnv/src/branch/main/Assets/Script/GameScript/SideChannel/AimbotSideChannel.cs)和[`AimBotSideChannelController.cs`](https://koha9.asuscomm.com/yurugit/Koha9/Aimbot-ParallelEnv/src/branch/main/Assets/Script/GameScript/SideChannel/AimBotSideChannelController.cs)中。每个Log信息将会以`|`来分隔字段其中第一个字段为Log的类型随后字段为自定义Log信息。在本环境中Unity的SideChannel将会发送所有`LogType.Warning`和`LogType.Error`类型的Log到Python侧。其中`LogType.Warning`会传递一回合结束后的的胜败信息和从Unity发送至Python的指令。胜败信息将类似于`Warning|Result|Win`和`Warning|Result|Lose`。而指令则传递了在下一训练结束后保存模型的命令,它的内容为`Warning|Command`。

BIN
ReadmeImages/FreeTargetFacingreward.png (Stored with Git LFS) Normal file

Binary file not shown.

BIN
ReadmeImages/LevelProbabilityPanel.jpg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
ReadmeImages/RayCastLayout.png (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -1,6 +1,30 @@
%YAML 1.1 %YAML 1.1
%TAG !u! tag:unity3d.com,2011: %TAG !u! tag:unity3d.com,2011:
--- !u!114 &1 --- !u!114 &1
MonoBehaviour:
m_ObjectHideFlags: 52
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: 12004, guid: 0000000000000000e000000000000000, type: 0}
m_Name:
m_EditorClassIdentifier:
m_PixelRect:
serializedVersion: 2
x: -1015
y: -63
width: 963
height: 708
m_ShowMode: 0
m_Title: Game
m_RootView: {fileID: 4}
m_MinSize: {x: 100, y: 121}
m_MaxSize: {x: 4000, y: 4021}
m_Maximized: 0
--- !u!114 &2
MonoBehaviour: MonoBehaviour:
m_ObjectHideFlags: 52 m_ObjectHideFlags: 52
m_CorrespondingSourceObject: {fileID: 0} m_CorrespondingSourceObject: {fileID: 0}
@ -14,17 +38,67 @@ MonoBehaviour:
m_EditorClassIdentifier: m_EditorClassIdentifier:
m_PixelRect: m_PixelRect:
serializedVersion: 2 serializedVersion: 2
x: -21 x: 535
y: 128 y: 182
width: 1855 width: 1175
height: 1037 height: 749
m_ShowMode: 4 m_ShowMode: 4
m_Title: Game m_Title: Hierarchy
m_RootView: {fileID: 2} m_RootView: {fileID: 5}
m_MinSize: {x: 875, y: 300} m_MinSize: {x: 875, y: 300}
m_MaxSize: {x: 10000, y: 10000} m_MaxSize: {x: 10000, y: 10000}
m_Maximized: 0 m_Maximized: 0
--- !u!114 &2 --- !u!114 &3
MonoBehaviour:
m_ObjectHideFlags: 52
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: 12006, guid: 0000000000000000e000000000000000, type: 0}
m_Name: GameView
m_EditorClassIdentifier:
m_Children: []
m_Position:
serializedVersion: 2
x: 0
y: 0
width: 963
height: 708
m_MinSize: {x: 100, y: 121}
m_MaxSize: {x: 4000, y: 4021}
m_ActualView: {fileID: 17}
m_Panes:
- {fileID: 17}
m_Selected: 0
m_LastSelected: 0
--- !u!114 &4
MonoBehaviour:
m_ObjectHideFlags: 52
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: 12010, guid: 0000000000000000e000000000000000, type: 0}
m_Name:
m_EditorClassIdentifier:
m_Children:
- {fileID: 3}
m_Position:
serializedVersion: 2
x: 0
y: 0
width: 963
height: 708
m_MinSize: {x: 100, y: 121}
m_MaxSize: {x: 4000, y: 4021}
vertical: 0
controlID: 105
--- !u!114 &5
MonoBehaviour: MonoBehaviour:
m_ObjectHideFlags: 52 m_ObjectHideFlags: 52
m_CorrespondingSourceObject: {fileID: 0} m_CorrespondingSourceObject: {fileID: 0}
@ -37,22 +111,22 @@ MonoBehaviour:
m_Name: m_Name:
m_EditorClassIdentifier: m_EditorClassIdentifier:
m_Children: m_Children:
- {fileID: 3} - {fileID: 6}
- {fileID: 5} - {fileID: 8}
- {fileID: 4} - {fileID: 7}
m_Position: m_Position:
serializedVersion: 2 serializedVersion: 2
x: 0 x: 0
y: 0 y: 0
width: 1855 width: 1175
height: 1037 height: 749
m_MinSize: {x: 875, y: 300} m_MinSize: {x: 875, y: 300}
m_MaxSize: {x: 10000, y: 10000} m_MaxSize: {x: 10000, y: 10000}
m_UseTopView: 1 m_UseTopView: 1
m_TopViewHeight: 30 m_TopViewHeight: 30
m_UseBottomView: 1 m_UseBottomView: 1
m_BottomViewHeight: 20 m_BottomViewHeight: 20
--- !u!114 &3 --- !u!114 &6
MonoBehaviour: MonoBehaviour:
m_ObjectHideFlags: 52 m_ObjectHideFlags: 52
m_CorrespondingSourceObject: {fileID: 0} m_CorrespondingSourceObject: {fileID: 0}
@ -69,12 +143,12 @@ MonoBehaviour:
serializedVersion: 2 serializedVersion: 2
x: 0 x: 0
y: 0 y: 0
width: 1855 width: 1175
height: 30 height: 30
m_MinSize: {x: 0, y: 0} m_MinSize: {x: 0, y: 0}
m_MaxSize: {x: 0, y: 0} m_MaxSize: {x: 0, y: 0}
m_LastLoadedLayoutName: m_LastLoadedLayoutName:
--- !u!114 &4 --- !u!114 &7
MonoBehaviour: MonoBehaviour:
m_ObjectHideFlags: 52 m_ObjectHideFlags: 52
m_CorrespondingSourceObject: {fileID: 0} m_CorrespondingSourceObject: {fileID: 0}
@ -90,89 +164,11 @@ MonoBehaviour:
m_Position: m_Position:
serializedVersion: 2 serializedVersion: 2
x: 0 x: 0
y: 1017 y: 729
width: 1855 width: 1175
height: 20 height: 20
m_MinSize: {x: 0, y: 0} m_MinSize: {x: 0, y: 0}
m_MaxSize: {x: 0, y: 0} m_MaxSize: {x: 0, y: 0}
--- !u!114 &5
MonoBehaviour:
m_ObjectHideFlags: 52
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 1
m_Script: {fileID: 12010, guid: 0000000000000000e000000000000000, type: 0}
m_Name:
m_EditorClassIdentifier:
m_Children:
- {fileID: 6}
- {fileID: 9}
- {fileID: 12}
m_Position:
serializedVersion: 2
x: 0
y: 30
width: 1855
height: 987
m_MinSize: {x: 300, y: 200}
m_MaxSize: {x: 24288, y: 16192}
vertical: 0
controlID: 28
--- !u!114 &6
MonoBehaviour:
m_ObjectHideFlags: 52
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: 12010, guid: 0000000000000000e000000000000000, type: 0}
m_Name:
m_EditorClassIdentifier:
m_Children:
- {fileID: 7}
- {fileID: 8}
m_Position:
serializedVersion: 2
x: 0
y: 0
width: 1038
height: 987
m_MinSize: {x: 100, y: 200}
m_MaxSize: {x: 8096, y: 16192}
vertical: 1
controlID: 16
--- !u!114 &7
MonoBehaviour:
m_ObjectHideFlags: 52
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 1
m_Script: {fileID: 12006, guid: 0000000000000000e000000000000000, type: 0}
m_Name: GameView
m_EditorClassIdentifier:
m_Children: []
m_Position:
serializedVersion: 2
x: 0
y: 0
width: 1038
height: 594
m_MinSize: {x: 101, y: 121}
m_MaxSize: {x: 4001, y: 4021}
m_ActualView: {fileID: 14}
m_Panes:
- {fileID: 14}
- {fileID: 13}
m_Selected: 0
m_LastSelected: 1
--- !u!114 &8 --- !u!114 &8
MonoBehaviour: MonoBehaviour:
m_ObjectHideFlags: 52 m_ObjectHideFlags: 52
@ -181,25 +177,24 @@ MonoBehaviour:
m_PrefabAsset: {fileID: 0} m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0} m_GameObject: {fileID: 0}
m_Enabled: 1 m_Enabled: 1
m_EditorHideFlags: 0 m_EditorHideFlags: 1
m_Script: {fileID: 12006, guid: 0000000000000000e000000000000000, type: 0} m_Script: {fileID: 12010, guid: 0000000000000000e000000000000000, type: 0}
m_Name: ProjectBrowser m_Name:
m_EditorClassIdentifier: m_EditorClassIdentifier:
m_Children: [] m_Children:
- {fileID: 9}
- {fileID: 12}
- {fileID: 15}
m_Position: m_Position:
serializedVersion: 2 serializedVersion: 2
x: 0 x: 0
y: 594 y: 30
width: 1038 width: 1175
height: 393 height: 699
m_MinSize: {x: 231, y: 271} m_MinSize: {x: 300, y: 200}
m_MaxSize: {x: 10001, y: 10021} m_MaxSize: {x: 24288, y: 16192}
m_ActualView: {fileID: 15} vertical: 0
m_Panes: controlID: 52
- {fileID: 15}
- {fileID: 16}
m_Selected: 0
m_LastSelected: 1
--- !u!114 &9 --- !u!114 &9
MonoBehaviour: MonoBehaviour:
m_ObjectHideFlags: 52 m_ObjectHideFlags: 52
@ -217,15 +212,93 @@ MonoBehaviour:
- {fileID: 11} - {fileID: 11}
m_Position: m_Position:
serializedVersion: 2 serializedVersion: 2
x: 1038 x: 0
y: 0 y: 0
width: 405 width: 609
height: 987 height: 699
m_MinSize: {x: 100, y: 200} m_MinSize: {x: 100, y: 200}
m_MaxSize: {x: 8096, y: 16192} m_MaxSize: {x: 8096, y: 16192}
vertical: 1 vertical: 1
controlID: 29 controlID: 53
--- !u!114 &10 --- !u!114 &10
MonoBehaviour:
m_ObjectHideFlags: 52
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 1
m_Script: {fileID: 12006, guid: 0000000000000000e000000000000000, type: 0}
m_Name: SceneView
m_EditorClassIdentifier:
m_Children: []
m_Position:
serializedVersion: 2
x: 0
y: 0
width: 609
height: 501
m_MinSize: {x: 201, y: 221}
m_MaxSize: {x: 4001, y: 4021}
m_ActualView: {fileID: 16}
m_Panes:
- {fileID: 16}
m_Selected: 0
m_LastSelected: 0
--- !u!114 &11
MonoBehaviour:
m_ObjectHideFlags: 52
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: 12006, guid: 0000000000000000e000000000000000, type: 0}
m_Name: ProjectBrowser
m_EditorClassIdentifier:
m_Children: []
m_Position:
serializedVersion: 2
x: 0
y: 501
width: 609
height: 198
m_MinSize: {x: 231, y: 271}
m_MaxSize: {x: 10001, y: 10021}
m_ActualView: {fileID: 18}
m_Panes:
- {fileID: 18}
- {fileID: 19}
m_Selected: 0
m_LastSelected: 1
--- !u!114 &12
MonoBehaviour:
m_ObjectHideFlags: 52
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: 12010, guid: 0000000000000000e000000000000000, type: 0}
m_Name:
m_EditorClassIdentifier:
m_Children:
- {fileID: 13}
- {fileID: 14}
m_Position:
serializedVersion: 2
x: 609
y: 0
width: 336
height: 699
m_MinSize: {x: 100, y: 200}
m_MaxSize: {x: 8096, y: 16192}
vertical: 1
controlID: 78
--- !u!114 &13
MonoBehaviour: MonoBehaviour:
m_ObjectHideFlags: 52 m_ObjectHideFlags: 52
m_CorrespondingSourceObject: {fileID: 0} m_CorrespondingSourceObject: {fileID: 0}
@ -242,16 +315,16 @@ MonoBehaviour:
serializedVersion: 2 serializedVersion: 2
x: 0 x: 0
y: 0 y: 0
width: 405 width: 336
height: 611 height: 392
m_MinSize: {x: 202, y: 221} m_MinSize: {x: 202, y: 221}
m_MaxSize: {x: 4002, y: 4021} m_MaxSize: {x: 4002, y: 4021}
m_ActualView: {fileID: 17} m_ActualView: {fileID: 20}
m_Panes: m_Panes:
- {fileID: 17} - {fileID: 20}
m_Selected: 0 m_Selected: 0
m_LastSelected: 0 m_LastSelected: 0
--- !u!114 &11 --- !u!114 &14
MonoBehaviour: MonoBehaviour:
m_ObjectHideFlags: 52 m_ObjectHideFlags: 52
m_CorrespondingSourceObject: {fileID: 0} m_CorrespondingSourceObject: {fileID: 0}
@ -267,18 +340,18 @@ MonoBehaviour:
m_Position: m_Position:
serializedVersion: 2 serializedVersion: 2
x: 0 x: 0
y: 611 y: 392
width: 405 width: 336
height: 376 height: 307
m_MinSize: {x: 100, y: 100} m_MinSize: {x: 102, y: 121}
m_MaxSize: {x: 4000, y: 4000} m_MaxSize: {x: 4002, y: 4021}
m_ActualView: {fileID: 18} m_ActualView: {fileID: 21}
m_Panes: m_Panes:
- {fileID: 18} - {fileID: 21}
- {fileID: 19} - {fileID: 22}
m_Selected: 0 m_Selected: 0
m_LastSelected: 1 m_LastSelected: 1
--- !u!114 &12 --- !u!114 &15
MonoBehaviour: MonoBehaviour:
m_ObjectHideFlags: 52 m_ObjectHideFlags: 52
m_CorrespondingSourceObject: {fileID: 0} m_CorrespondingSourceObject: {fileID: 0}
@ -293,18 +366,18 @@ MonoBehaviour:
m_Children: [] m_Children: []
m_Position: m_Position:
serializedVersion: 2 serializedVersion: 2
x: 1443 x: 945
y: 0 y: 0
width: 412 width: 230
height: 987 height: 699
m_MinSize: {x: 276, y: 71} m_MinSize: {x: 276, y: 71}
m_MaxSize: {x: 4001, y: 4021} m_MaxSize: {x: 4001, y: 4021}
m_ActualView: {fileID: 20} m_ActualView: {fileID: 23}
m_Panes: m_Panes:
- {fileID: 20} - {fileID: 23}
m_Selected: 0 m_Selected: 0
m_LastSelected: 0 m_LastSelected: 0
--- !u!114 &13 --- !u!114 &16
MonoBehaviour: MonoBehaviour:
m_ObjectHideFlags: 52 m_ObjectHideFlags: 52
m_CorrespondingSourceObject: {fileID: 0} m_CorrespondingSourceObject: {fileID: 0}
@ -324,10 +397,10 @@ MonoBehaviour:
m_Tooltip: m_Tooltip:
m_Pos: m_Pos:
serializedVersion: 2 serializedVersion: 2
x: 65 x: 535
y: 73 y: 212
width: 1037 width: 608
height: 573 height: 480
m_ViewDataDictionary: {fileID: 0} m_ViewDataDictionary: {fileID: 0}
m_OverlayCanvas: m_OverlayCanvas:
m_LastAppliedPresetName: Default m_LastAppliedPresetName: Default
@ -348,9 +421,9 @@ MonoBehaviour:
floating: 0 floating: 0
collapsed: 0 collapsed: 0
displayed: 1 displayed: 1
snapOffset: {x: -141, y: 149} snapOffset: {x: 0, y: 149}
snapOffsetDelta: {x: 0, y: 0} snapOffsetDelta: {x: 0, y: 0}
snapCorner: 1 snapCorner: 0
id: unity-grid-and-snap-toolbar id: unity-grid-and-snap-toolbar
index: 1 index: 1
layout: 1 layout: 1
@ -424,7 +497,7 @@ MonoBehaviour:
containerId: overlay-container--right containerId: overlay-container--right
floating: 0 floating: 0
collapsed: 0 collapsed: 0
displayed: 1 displayed: 0
snapOffset: {x: 0, y: 0} snapOffset: {x: 0, y: 0}
snapOffsetDelta: {x: 0, y: 0} snapOffsetDelta: {x: 0, y: 0}
snapCorner: 0 snapCorner: 0
@ -562,9 +635,9 @@ MonoBehaviour:
m_PlayAudio: 0 m_PlayAudio: 0
m_AudioPlay: 0 m_AudioPlay: 0
m_Position: m_Position:
m_Target: {x: -93.190475, y: 4.007041, z: -23.907015} m_Target: {x: 462, y: 315.5, z: 0}
speed: 2 speed: 2
m_Value: {x: -93.190475, y: 4.007041, z: -23.907015} m_Value: {x: 461.9999, y: 315.5, z: -0.00004226652}
m_RenderMode: 0 m_RenderMode: 0
m_CameraMode: m_CameraMode:
drawMode: 0 drawMode: 0
@ -611,13 +684,13 @@ MonoBehaviour:
m_GridAxis: 1 m_GridAxis: 1
m_gridOpacity: 0.529 m_gridOpacity: 0.529
m_Rotation: m_Rotation:
m_Target: {x: -0.04341376, y: 0.5871053, z: 0.031550582, w: 0.80778545} m_Target: {x: -0.31611243, y: -0.22831854, z: 0.078667216, w: -0.9174724}
speed: 2 speed: 2
m_Value: {x: -0.043411803, y: 0.5870788, z: 0.03154916, w: 0.80774903} m_Value: {x: -0.31611243, y: -0.22831854, z: 0.07866721, w: -0.9174724}
m_Size: m_Size:
m_Target: 12.124355 m_Target: 10
speed: 2 speed: 2
m_Value: 12.124355 m_Value: 10
m_Ortho: m_Ortho:
m_Target: 0 m_Target: 0
speed: 2 speed: 2
@ -635,14 +708,14 @@ MonoBehaviour:
m_FarClip: 10000 m_FarClip: 10000
m_DynamicClip: 1 m_DynamicClip: 1
m_OcclusionCulling: 0 m_OcclusionCulling: 0
m_LastSceneViewRotation: {x: -0.23316237, y: -0.24425557, z: 0.060633, w: -0.93931496} m_LastSceneViewRotation: {x: -0.08717229, y: 0.89959055, z: -0.21045254, w: -0.3726226}
m_LastSceneViewOrtho: 0 m_LastSceneViewOrtho: 0
m_ReplacementShader: {fileID: 0} m_ReplacementShader: {fileID: 0}
m_ReplacementString: m_ReplacementString:
m_SceneVisActive: 1 m_SceneVisActive: 1
m_LastLockedObject: {fileID: 0} m_LastLockedObject: {fileID: 0}
m_ViewIsLockedToObject: 0 m_ViewIsLockedToObject: 0
--- !u!114 &14 --- !u!114 &17
MonoBehaviour: MonoBehaviour:
m_ObjectHideFlags: 52 m_ObjectHideFlags: 52
m_CorrespondingSourceObject: {fileID: 0} m_CorrespondingSourceObject: {fileID: 0}
@ -662,10 +735,10 @@ MonoBehaviour:
m_Tooltip: m_Tooltip:
m_Pos: m_Pos:
serializedVersion: 2 serializedVersion: 2
x: -21 x: -1015
y: 158 y: -63
width: 1037 width: 963
height: 573 height: 687
m_ViewDataDictionary: {fileID: 0} m_ViewDataDictionary: {fileID: 0}
m_OverlayCanvas: m_OverlayCanvas:
m_LastAppliedPresetName: Default m_LastAppliedPresetName: Default
@ -673,17 +746,17 @@ MonoBehaviour:
m_SerializedViewNames: [] m_SerializedViewNames: []
m_SerializedViewValues: [] m_SerializedViewValues: []
m_PlayModeViewName: GameView m_PlayModeViewName: GameView
m_ShowGizmos: 1 m_ShowGizmos: 0
m_TargetDisplay: 0 m_TargetDisplay: 0
m_ClearColor: {r: 0, g: 0, b: 0, a: 0} m_ClearColor: {r: 0, g: 0, b: 0, a: 0}
m_TargetSize: {x: 1037, y: 552} m_TargetSize: {x: 963, y: 666}
m_TextureFilterMode: 0 m_TextureFilterMode: 0
m_TextureHideFlags: 61 m_TextureHideFlags: 61
m_RenderIMGUI: 1 m_RenderIMGUI: 1
m_EnterPlayModeBehavior: 0 m_EnterPlayModeBehavior: 0
m_UseMipMap: 0 m_UseMipMap: 0
m_VSyncEnabled: 0 m_VSyncEnabled: 0
m_Gizmos: 1 m_Gizmos: 0
m_Stats: 0 m_Stats: 0
m_SelectedSizes: 00000000000000000000000000000000000000000000000000000000000000000000000000000000 m_SelectedSizes: 00000000000000000000000000000000000000000000000000000000000000000000000000000000
m_ZoomArea: m_ZoomArea:
@ -691,10 +764,10 @@ MonoBehaviour:
m_VRangeLocked: 0 m_VRangeLocked: 0
hZoomLockedByDefault: 0 hZoomLockedByDefault: 0
vZoomLockedByDefault: 0 vZoomLockedByDefault: 0
m_HBaseRangeMin: -518.5 m_HBaseRangeMin: -481.5
m_HBaseRangeMax: 518.5 m_HBaseRangeMax: 481.5
m_VBaseRangeMin: -276 m_VBaseRangeMin: -333
m_VBaseRangeMax: 276 m_VBaseRangeMax: 333
m_HAllowExceedBaseRangeMin: 1 m_HAllowExceedBaseRangeMin: 1
m_HAllowExceedBaseRangeMax: 1 m_HAllowExceedBaseRangeMax: 1
m_VAllowExceedBaseRangeMin: 1 m_VAllowExceedBaseRangeMin: 1
@ -712,29 +785,29 @@ MonoBehaviour:
serializedVersion: 2 serializedVersion: 2
x: 0 x: 0
y: 21 y: 21
width: 1037 width: 963
height: 552 height: 666
m_Scale: {x: 1, y: 1} m_Scale: {x: 1, y: 1}
m_Translation: {x: 518.5, y: 276} m_Translation: {x: 481.5, y: 333}
m_MarginLeft: 0 m_MarginLeft: 0
m_MarginRight: 0 m_MarginRight: 0
m_MarginTop: 0 m_MarginTop: 0
m_MarginBottom: 0 m_MarginBottom: 0
m_LastShownAreaInsideMargins: m_LastShownAreaInsideMargins:
serializedVersion: 2 serializedVersion: 2
x: -518.5 x: -481.5
y: -276 y: -333
width: 1037 width: 963
height: 552 height: 666
m_MinimalGUI: 1 m_MinimalGUI: 1
m_defaultScale: 1 m_defaultScale: 1
m_LastWindowPixelSize: {x: 1037, y: 573} m_LastWindowPixelSize: {x: 963, y: 687}
m_ClearInEditMode: 1 m_ClearInEditMode: 1
m_NoCameraWarning: 1 m_NoCameraWarning: 1
m_LowResolutionForAspectRatios: 01000000000000000000 m_LowResolutionForAspectRatios: 01000000000000000000
m_XRRenderMode: 0 m_XRRenderMode: 0
m_RenderTexture: {fileID: 0} m_RenderTexture: {fileID: 0}
--- !u!114 &15 --- !u!114 &18
MonoBehaviour: MonoBehaviour:
m_ObjectHideFlags: 52 m_ObjectHideFlags: 52
m_CorrespondingSourceObject: {fileID: 0} m_CorrespondingSourceObject: {fileID: 0}
@ -754,10 +827,10 @@ MonoBehaviour:
m_Tooltip: m_Tooltip:
m_Pos: m_Pos:
serializedVersion: 2 serializedVersion: 2
x: 0 x: 535
y: 613 y: 713
width: 1037 width: 608
height: 372 height: 177
m_ViewDataDictionary: {fileID: 0} m_ViewDataDictionary: {fileID: 0}
m_OverlayCanvas: m_OverlayCanvas:
m_LastAppliedPresetName: Default m_LastAppliedPresetName: Default
@ -775,22 +848,22 @@ MonoBehaviour:
m_SkipHidden: 0 m_SkipHidden: 0
m_SearchArea: 1 m_SearchArea: 1
m_Folders: m_Folders:
- Assets/Script/GameScript - Assets/Scenes
m_Globs: [] m_Globs: []
m_OriginalText: m_OriginalText:
m_ViewMode: 1 m_ViewMode: 1
m_StartGridSize: 16 m_StartGridSize: 16
m_LastFolders: m_LastFolders:
- Assets/Script/GameScript - Assets/Script/PlayMode
m_LastFoldersGridSize: 16 m_LastFoldersGridSize: 16
m_LastProjectPath: C:\Users\UCUNI\OneDrive\Unity\ML-Agents\Aimbot-ParallelEnv m_LastProjectPath: C:\Users\UCUNI\OneDrive\Unity\ML-Agents\Aimbot-ParallelEnv
m_LockTracker: m_LockTracker:
m_IsLocked: 0 m_IsLocked: 0
m_FolderTreeState: m_FolderTreeState:
scrollPos: {x: 0, y: 352} scrollPos: {x: 0, y: 0}
m_SelectedIDs: 7c970000 m_SelectedIDs: 05ca9a3b
m_LastClickedID: 38780 m_LastClickedID: 1000000005
m_ExpandedIDs: 000000005e97000060970000629700006497000066970000689700006a9700006c9700006e97000070970000729700007497000076970000789700007a9700007c9700007e970000d297000000ca9a3bffffff7f m_ExpandedIDs: 000000004294000000ca9a3b
m_RenameOverlay: m_RenameOverlay:
m_UserAcceptedRename: 0 m_UserAcceptedRename: 0
m_Name: m_Name:
@ -806,7 +879,7 @@ MonoBehaviour:
m_IsRenaming: 0 m_IsRenaming: 0
m_OriginalEventType: 11 m_OriginalEventType: 11
m_IsRenamingFilename: 1 m_IsRenamingFilename: 1
m_ClientGUIView: {fileID: 8} m_ClientGUIView: {fileID: 11}
m_SearchString: m_SearchString:
m_CreateAssetUtility: m_CreateAssetUtility:
m_EndAction: {fileID: 0} m_EndAction: {fileID: 0}
@ -818,7 +891,7 @@ MonoBehaviour:
scrollPos: {x: 0, y: 0} scrollPos: {x: 0, y: 0}
m_SelectedIDs: m_SelectedIDs:
m_LastClickedID: 0 m_LastClickedID: 0
m_ExpandedIDs: 000000005e97000060970000629700006497000066970000689700006a9700006c9700006e97000070970000729700007497000076970000789700007a9700007c9700007e970000 m_ExpandedIDs: 0000000042940000
m_RenameOverlay: m_RenameOverlay:
m_UserAcceptedRename: 0 m_UserAcceptedRename: 0
m_Name: m_Name:
@ -849,20 +922,20 @@ MonoBehaviour:
m_ExpandedInstanceIDs: c62300008a5c000000000000 m_ExpandedInstanceIDs: c62300008a5c000000000000
m_RenameOverlay: m_RenameOverlay:
m_UserAcceptedRename: 0 m_UserAcceptedRename: 0
m_Name: m_Name: Train
m_OriginalName: m_OriginalName: Train
m_EditFieldRect: m_EditFieldRect:
serializedVersion: 2 serializedVersion: 2
x: 0 x: 0
y: 0 y: 0
width: 0 width: 0
height: 0 height: 0
m_UserData: 0 m_UserData: 38084
m_IsWaitingForDelay: 0 m_IsWaitingForDelay: 0
m_IsRenaming: 0 m_IsRenaming: 0
m_OriginalEventType: 11 m_OriginalEventType: 0
m_IsRenamingFilename: 1 m_IsRenamingFilename: 1
m_ClientGUIView: {fileID: 8} m_ClientGUIView: {fileID: 11}
m_CreateAssetUtility: m_CreateAssetUtility:
m_EndAction: {fileID: 0} m_EndAction: {fileID: 0}
m_InstanceID: 0 m_InstanceID: 0
@ -874,7 +947,7 @@ MonoBehaviour:
m_GridSize: 16 m_GridSize: 16
m_SkipHiddenPackages: 0 m_SkipHiddenPackages: 0
m_DirectoriesAreaWidth: 355 m_DirectoriesAreaWidth: 355
--- !u!114 &16 --- !u!114 &19
MonoBehaviour: MonoBehaviour:
m_ObjectHideFlags: 52 m_ObjectHideFlags: 52
m_CorrespondingSourceObject: {fileID: 0} m_CorrespondingSourceObject: {fileID: 0}
@ -894,15 +967,15 @@ MonoBehaviour:
m_Tooltip: m_Tooltip:
m_Pos: m_Pos:
serializedVersion: 2 serializedVersion: 2
x: 65 x: 64
y: 667 y: 780
width: 1041 width: 961
height: 372 height: 259
m_ViewDataDictionary: {fileID: 0} m_ViewDataDictionary: {fileID: 0}
m_OverlayCanvas: m_OverlayCanvas:
m_LastAppliedPresetName: Default m_LastAppliedPresetName: Default
m_SaveData: [] m_SaveData: []
--- !u!114 &17 --- !u!114 &20
MonoBehaviour: MonoBehaviour:
m_ObjectHideFlags: 52 m_ObjectHideFlags: 52
m_CorrespondingSourceObject: {fileID: 0} m_CorrespondingSourceObject: {fileID: 0}
@ -922,10 +995,10 @@ MonoBehaviour:
m_Tooltip: m_Tooltip:
m_Pos: m_Pos:
serializedVersion: 2 serializedVersion: 2
x: 1017 x: 1144
y: 158 y: 212
width: 403 width: 334
height: 590 height: 371
m_ViewDataDictionary: {fileID: 0} m_ViewDataDictionary: {fileID: 0}
m_OverlayCanvas: m_OverlayCanvas:
m_LastAppliedPresetName: Default m_LastAppliedPresetName: Default
@ -933,9 +1006,9 @@ MonoBehaviour:
m_SceneHierarchy: m_SceneHierarchy:
m_TreeViewState: m_TreeViewState:
scrollPos: {x: 0, y: 0} scrollPos: {x: 0, y: 0}
m_SelectedIDs: 30740000 m_SelectedIDs: 5ef40000
m_LastClickedID: 29744 m_LastClickedID: 62558
m_ExpandedIDs: 32fbffffea73000064740000187900003e7b0000047c0000 m_ExpandedIDs: 9aebffff80ecffff2aeeffff2aefffff60f2ffff22f3ffff72f5ffffbaf5ffffdaf5ffff32fbffff86f50000
m_RenameOverlay: m_RenameOverlay:
m_UserAcceptedRename: 0 m_UserAcceptedRename: 0
m_Name: m_Name:
@ -951,7 +1024,7 @@ MonoBehaviour:
m_IsRenaming: 0 m_IsRenaming: 0
m_OriginalEventType: 11 m_OriginalEventType: 11
m_IsRenamingFilename: 0 m_IsRenamingFilename: 0
m_ClientGUIView: {fileID: 10} m_ClientGUIView: {fileID: 13}
m_SearchString: m_SearchString:
m_ExpandedScenes: [] m_ExpandedScenes: []
m_CurrenRootInstanceID: 0 m_CurrenRootInstanceID: 0
@ -959,7 +1032,7 @@ MonoBehaviour:
m_IsLocked: 0 m_IsLocked: 0
m_CurrentSortingName: TransformSorting m_CurrentSortingName: TransformSorting
m_WindowGUID: 4c969a2b90040154d917609493e03593 m_WindowGUID: 4c969a2b90040154d917609493e03593
--- !u!114 &18 --- !u!114 &21
MonoBehaviour: MonoBehaviour:
m_ObjectHideFlags: 52 m_ObjectHideFlags: 52
m_CorrespondingSourceObject: {fileID: 0} m_CorrespondingSourceObject: {fileID: 0}
@ -979,15 +1052,15 @@ MonoBehaviour:
m_Tooltip: m_Tooltip:
m_Pos: m_Pos:
serializedVersion: 2 serializedVersion: 2
x: 1017 x: 1144
y: 769 y: 604
width: 403 width: 334
height: 355 height: 286
m_ViewDataDictionary: {fileID: 0} m_ViewDataDictionary: {fileID: 0}
m_OverlayCanvas: m_OverlayCanvas:
m_LastAppliedPresetName: Default m_LastAppliedPresetName: Default
m_SaveData: [] m_SaveData: []
--- !u!114 &19 --- !u!114 &22
MonoBehaviour: MonoBehaviour:
m_ObjectHideFlags: 52 m_ObjectHideFlags: 52
m_CorrespondingSourceObject: {fileID: 0} m_CorrespondingSourceObject: {fileID: 0}
@ -999,7 +1072,7 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: 6c262c1329a02fa49b5cb4c297106f3f, type: 3} m_Script: {fileID: 11500000, guid: 6c262c1329a02fa49b5cb4c297106f3f, type: 3}
m_Name: m_Name:
m_EditorClassIdentifier: m_EditorClassIdentifier:
m_MinSize: {x: 136, y: 30} m_MinSize: {x: 129, y: 28}
m_MaxSize: {x: 4000, y: 4000} m_MaxSize: {x: 4000, y: 4000}
m_TitleContent: m_TitleContent:
m_Text: ProBuilder m_Text: ProBuilder
@ -1015,7 +1088,7 @@ MonoBehaviour:
m_OverlayCanvas: m_OverlayCanvas:
m_LastAppliedPresetName: Default m_LastAppliedPresetName: Default
m_SaveData: [] m_SaveData: []
--- !u!114 &20 --- !u!114 &23
MonoBehaviour: MonoBehaviour:
m_ObjectHideFlags: 52 m_ObjectHideFlags: 52
m_CorrespondingSourceObject: {fileID: 0} m_CorrespondingSourceObject: {fileID: 0}
@ -1035,10 +1108,10 @@ MonoBehaviour:
m_Tooltip: m_Tooltip:
m_Pos: m_Pos:
serializedVersion: 2 serializedVersion: 2
x: 1422 x: 1480
y: 158 y: 212
width: 411 width: 229
height: 966 height: 678
m_ViewDataDictionary: {fileID: 0} m_ViewDataDictionary: {fileID: 0}
m_OverlayCanvas: m_OverlayCanvas:
m_LastAppliedPresetName: Default m_LastAppliedPresetName: Default
@ -1050,7 +1123,7 @@ MonoBehaviour:
m_ControlHash: -371814159 m_ControlHash: -371814159
m_PrefName: Preview_InspectorPreview m_PrefName: Preview_InspectorPreview
m_LastInspectedObjectInstanceID: -1 m_LastInspectedObjectInstanceID: -1
m_LastVerticalScrollValue: 280 m_LastVerticalScrollValue: 0
m_GlobalObjectId: m_GlobalObjectId:
m_InspectorMode: 0 m_InspectorMode: 0
m_LockTracker: m_LockTracker: