Compare commits
51 Commits
more-targe
...
master
Author | SHA1 | Date |
---|---|---|
Daniel Lovell | 54c7e5fbc7 | |
Daniel Lovell | 256f845c18 | |
Daniel Lovell | ae5798081a | |
Daniel Lovell | eeb82a9539 | |
Daniel Lovell | 1cec2fab7d | |
Daniel Lovell | ecfdb490ae | |
Daniel Lovell | 45cdf740b1 | |
Daniel Lovell | 090c3168ec | |
Daniel Lovell | 4768cffe8a | |
Daniel Lovell | 9c5dfe9b07 | |
Daniel Lovell | f13103a9e5 | |
Daniel Lovell | 4b72ed9c27 | |
Daniel Lovell | 6c88a881f2 | |
Daniel Lovell | 3e59ede2ed | |
Daniel Lovell | aba01e9a4e | |
Daniel Lovell | 05ef40aa94 | |
Daniel Lovell | 4a79b77b41 | |
Daniel Lovell | 494cb8591f | |
Daniel Lovell | dc811e0185 | |
Daniel Lovell | 78b349610f | |
Daniel Lovell | 6ada38fb73 | |
Daniel Lovell | 269fc479cc | |
Daniel Lovell | 99d617f142 | |
Daniel Lovell | 05400f318a | |
Daniel Lovell | 17987c2c5f | |
Daniel Lovell | 0c7d69d632 | |
Daniel Lovell | 2d97112e51 | |
Daniel Lovell | 64b542a866 | |
Daniel Lovell | 9bd3e513ca | |
Daniel Lovell | fab0c769d1 | |
Daniel Lovell | f4faafcc24 | |
Daniel Lovell | 46fe48afdb | |
Daniel Lovell | 91587afce5 | |
Daniel Lovell | 3293d65ccb | |
Daniel Lovell | f6d1935694 | |
Daniel Lovell | 07838e79b4 | |
Daniel Lovell | 4cf8567d91 | |
Daniel Lovell | 90cc1d29f8 | |
Daniel Lovell | 2174379fb1 | |
Daniel Lovell | 611dcb8365 | |
Daniel Lovell | 4fb40a2bc6 | |
Daniel Lovell | 4882caea45 | |
Daniel Lovell | e9d3f2b388 | |
Daniel Lovell | 765f3983f3 | |
Daniel Lovell | 474c322b35 | |
Daniel Lovell | 9a569e6415 | |
Daniel Lovell | 1dcaf2d245 | |
Daniel Lovell | 156960bae5 | |
Daniel Lovell | f701e34863 | |
Daniel Lovell | 32f3b0aa7a | |
Daniel Lovell | e15b70fafc |
|
@ -9,6 +9,8 @@ on:
|
|||
pull_request:
|
||||
branches:
|
||||
- release
|
||||
schedule:
|
||||
- cron: '0 2 * * *' # Run at 2 AM UTC every day
|
||||
|
||||
jobs:
|
||||
buildForAllSupportedPlatforms:
|
||||
|
@ -41,6 +43,9 @@ jobs:
|
|||
buildName: micromissiles-${{ github.ref_name }}-${{ matrix.targetPlatform }}
|
||||
versioning: Semantic
|
||||
targetPlatform: ${{ matrix.targetPlatform }}
|
||||
- name: Copy Tools Directory
|
||||
run: |
|
||||
sudo cp -r Tools/ build/${{ matrix.targetPlatform }}/
|
||||
- if: matrix.targetPlatform == 'StandaloneWindows64'
|
||||
run: cd build/${{ matrix.targetPlatform }} && sudo zip -r ../build-${{ matrix.targetPlatform }}.zip * && cd -
|
||||
- if: matrix.targetPlatform == 'StandaloneWindows64'
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
# .github/workflows/docs.yaml
|
||||
name: Deploy Documentation
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
workflow_dispatch: # Allows manual triggering
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
pages: write
|
||||
id-token: write
|
||||
|
||||
jobs:
|
||||
build-deploy:
|
||||
permissions:
|
||||
contents: write
|
||||
pages: write
|
||||
id-token: write
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: '18' # Use Node.js 18
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: Build documentation
|
||||
run: npm run docs:build
|
||||
|
||||
- name: Deploy Documentation
|
||||
uses: peaceiris/actions-gh-pages@v4
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
publish_dir: ./docs/.vitepress/dist
|
||||
allow_empty_commit: true
|
||||
keep_files: true
|
||||
force_orphan: false
|
|
@ -1,27 +0,0 @@
|
|||
# micromissiles-unity
|
||||
|
||||
## Build ${{ github.ref }}
|
||||
|
||||
## Instructions
|
||||
|
||||
Download and extract the archive corresponding to your platform (Windows or Mac) from the binaries listed below.
|
||||
|
||||
## Windows
|
||||
|
||||
1. Download the zip file for Windows: `micromissiles-${{ github.ref }}-windows_x86_64.zip`.
|
||||
2. Unzip the zip file. The zip file should contain a single directory called `micromissiles-${{ github.ref }}-windows_x86_64`.
|
||||
3. Run `micromissiles-<version>-StandaloneWindows64.exe`.
|
||||
|
||||
## Mac
|
||||
|
||||
1. Download the zip file for Darwin: `micromissiles-${{ github.ref }}-darwin.zip`.
|
||||
2. Unzip the zip file. The zip file should contain a single app file.
|
||||
3. Change the permission of the app file recursively by running:
|
||||
```bash
|
||||
chmod -R +x micromissiles-<version>-StandaloneOSX.app
|
||||
```
|
||||
4. Open the app file.
|
||||
5. If you get a warning that Apple cannot check the application for malicious software:
|
||||
* Open `System Preferences`.
|
||||
* Navigate to `Privacy & Security`.
|
||||
* Click on `Open Anyway` to bypass Apple's developer check.
|
|
@ -18,14 +18,19 @@ jobs:
|
|||
ref: ${{ github.event.workflow_run.head_branch }}
|
||||
fetch-depth: 0
|
||||
lfs: false
|
||||
- name: Get latest tag
|
||||
id: get_latest_tag
|
||||
run: |
|
||||
latest_tag=$(git describe --tags --abbrev=0)
|
||||
echo "LATEST_TAG=${latest_tag}" >> $GITHUB_OUTPUT
|
||||
- name: Create release
|
||||
id: create_release
|
||||
uses: actions/create-release@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
tag_name: ${{ github.event.workflow_run.head_branch }}
|
||||
release_name: ${{ github.event.workflow_run.head_branch }}
|
||||
tag_name: ${{ steps.get_latest_tag.outputs.LATEST_TAG }}
|
||||
release_name: ${{ steps.get_latest_tag.outputs.LATEST_TAG }}
|
||||
body_path: RELEASE.md
|
||||
draft: false
|
||||
prerelease: false
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
# .github/workflows/test.yaml
|
||||
name: Test
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 2 * * *' # Runs at 2 AM UTC every day
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
testAllModes:
|
||||
name: Test in ${{ matrix.testMode }}
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
testMode:
|
||||
- playmode
|
||||
- editmode
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
lfs: true
|
||||
|
||||
- uses: actions/cache@v4
|
||||
with:
|
||||
path: ${{ matrix.projectPath }}/Library
|
||||
key: Library-${{ matrix.projectPath }}
|
||||
restore-keys: |
|
||||
Library-
|
||||
|
||||
- uses: game-ci/unity-test-runner@v4
|
||||
id: tests
|
||||
env:
|
||||
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
|
||||
UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
|
||||
UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
|
||||
with:
|
||||
projectPath: ${{ matrix.projectPath }}
|
||||
testMode: ${{ matrix.testMode }}
|
||||
artifactsPath: ${{ matrix.testMode }}-artifacts
|
||||
githubToken: ${{ secrets.GITHUB_TOKEN }}
|
||||
checkName: ${{ matrix.testMode }} Test Results
|
||||
coverageOptions: 'generateAdditionalMetrics;generateHtmlReport;generateBadgeReport;assemblyFilters:+bamlab.*'
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
if: always()
|
||||
with:
|
||||
name: Test results for ${{ matrix.testMode }}
|
||||
path: ${{ steps.tests.outputs.artifactsPath }}
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
if: always()
|
||||
with:
|
||||
name: Coverage results for ${{ matrix.testMode }}
|
||||
path: ${{ steps.tests.outputs.coveragePath }}
|
||||
|
||||
- name: Deploy Coverage Report
|
||||
if: always()
|
||||
uses: peaceiris/actions-gh-pages@v4
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
publish_dir: ${{ steps.tests.outputs.coveragePath }}
|
||||
destination_dir: coverage/${{ matrix.testMode }}
|
||||
allow_empty_commit: true
|
||||
keep_files: true
|
||||
force_orphan: false
|
|
@ -80,4 +80,6 @@ crashlytics-build.properties
|
|||
.vsconfig
|
||||
|
||||
# Telemetry Logs
|
||||
Telemetry/Logs/
|
||||
Telemetry/Logs/
|
||||
|
||||
node_modules/
|
|
@ -98,6 +98,7 @@ Material:
|
|||
m_Offset: {x: 0, y: 0}
|
||||
m_Ints: []
|
||||
m_Floats:
|
||||
- _AddPrecomputedVelocity: 0
|
||||
- _AlphaClip: 0
|
||||
- _AlphaToMask: 0
|
||||
- _Blend: 0
|
||||
|
@ -135,8 +136,8 @@ Material:
|
|||
- _WorkflowMode: 1
|
||||
- _ZWrite: 1
|
||||
m_Colors:
|
||||
- _BaseColor: {r: 1, g: 0, b: 0, a: 1}
|
||||
- _Color: {r: 1, g: 0, b: 0, a: 1}
|
||||
- _BaseColor: {r: 0.6679245, g: 0, b: 0, a: 1}
|
||||
- _Color: {r: 0.66792446, g: 0, b: 0, a: 1}
|
||||
- _EmissionColor: {r: 0.9622642, g: 0, b: 0, a: 1}
|
||||
- _SpecColor: {r: 0.5, g: 0.5, b: 0.5, a: 0.5}
|
||||
m_BuildTextureStacks: []
|
||||
|
|
|
@ -109,7 +109,7 @@ MonoBehaviour:
|
|||
m_PrefilterDebugKeywords: 1
|
||||
m_PrefilterWriteRenderingLayers: 1
|
||||
m_PrefilterHDROutput: 1
|
||||
m_PrefilterAlphaOutput: 0
|
||||
m_PrefilterAlphaOutput: 1
|
||||
m_PrefilterSSAODepthNormals: 1
|
||||
m_PrefilterSSAOSourceDepthLow: 1
|
||||
m_PrefilterSSAOSourceDepthMedium: 1
|
||||
|
|
|
@ -1,361 +0,0 @@
|
|||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!1 &295999596028346972
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 9192475791974545516}
|
||||
- component: {fileID: 3681380462727606042}
|
||||
- component: {fileID: 5038767565634652910}
|
||||
m_Layer: 0
|
||||
m_Name: Cone
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &9192475791974545516
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 295999596028346972}
|
||||
serializedVersion: 2
|
||||
m_LocalRotation: {x: 0.7071068, y: 0, z: 0, w: 0.7071068}
|
||||
m_LocalPosition: {x: 0, y: 0, z: -3.89}
|
||||
m_LocalScale: {x: 20, y: 20, z: 20}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 8462434346230391091}
|
||||
m_LocalEulerAnglesHint: {x: 90, y: 0, z: 0}
|
||||
--- !u!33 &3681380462727606042
|
||||
MeshFilter:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 295999596028346972}
|
||||
m_Mesh: {fileID: 4300000, guid: 36b72d5a34c22d94c88a068dfcbdf27a, type: 2}
|
||||
--- !u!23 &5038767565634652910
|
||||
MeshRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 295999596028346972}
|
||||
m_Enabled: 1
|
||||
m_CastShadows: 1
|
||||
m_ReceiveShadows: 1
|
||||
m_DynamicOccludee: 1
|
||||
m_StaticShadowCaster: 0
|
||||
m_MotionVectors: 1
|
||||
m_LightProbeUsage: 1
|
||||
m_ReflectionProbeUsage: 1
|
||||
m_RayTracingMode: 2
|
||||
m_RayTraceProcedural: 0
|
||||
m_RayTracingAccelStructBuildFlagsOverride: 0
|
||||
m_RayTracingAccelStructBuildFlags: 1
|
||||
m_SmallMeshCulling: 1
|
||||
m_RenderingLayerMask: 1
|
||||
m_RendererPriority: 0
|
||||
m_Materials:
|
||||
- {fileID: 2100000, guid: 061083197c659dc44983633a84d39cea, type: 2}
|
||||
m_StaticBatchInfo:
|
||||
firstSubMesh: 0
|
||||
subMeshCount: 0
|
||||
m_StaticBatchRoot: {fileID: 0}
|
||||
m_ProbeAnchor: {fileID: 0}
|
||||
m_LightProbeVolumeOverride: {fileID: 0}
|
||||
m_ScaleInLightmap: 1
|
||||
m_ReceiveGI: 1
|
||||
m_PreserveUVs: 0
|
||||
m_IgnoreNormalsForChartDetection: 0
|
||||
m_ImportantGI: 0
|
||||
m_StitchLightmapSeams: 1
|
||||
m_SelectedEditorRenderState: 3
|
||||
m_MinimumChartSize: 4
|
||||
m_AutoUVMaxDistance: 0.5
|
||||
m_AutoUVMaxAngle: 89
|
||||
m_LightmapParameters: {fileID: 0}
|
||||
m_SortingLayerID: 0
|
||||
m_SortingLayer: 0
|
||||
m_SortingOrder: 0
|
||||
m_AdditionalVertexStreams: {fileID: 0}
|
||||
--- !u!1 &4390675743535140416
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 585396986125101381}
|
||||
- component: {fileID: 4620404264009677289}
|
||||
m_Layer: 0
|
||||
m_Name: TrailRenderer
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &585396986125101381
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 4390675743535140416}
|
||||
serializedVersion: 2
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 10, y: 10, z: 10}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 8462434346230391091}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!96 &4620404264009677289
|
||||
TrailRenderer:
|
||||
serializedVersion: 3
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 4390675743535140416}
|
||||
m_Enabled: 1
|
||||
m_CastShadows: 0
|
||||
m_ReceiveShadows: 0
|
||||
m_DynamicOccludee: 1
|
||||
m_StaticShadowCaster: 0
|
||||
m_MotionVectors: 0
|
||||
m_LightProbeUsage: 0
|
||||
m_ReflectionProbeUsage: 0
|
||||
m_RayTracingMode: 0
|
||||
m_RayTraceProcedural: 0
|
||||
m_RayTracingAccelStructBuildFlagsOverride: 0
|
||||
m_RayTracingAccelStructBuildFlags: 1
|
||||
m_SmallMeshCulling: 1
|
||||
m_RenderingLayerMask: 1
|
||||
m_RendererPriority: 0
|
||||
m_Materials:
|
||||
- {fileID: 2100000, guid: 0e42500808910f24cb6626a81760c995, type: 2}
|
||||
m_StaticBatchInfo:
|
||||
firstSubMesh: 0
|
||||
subMeshCount: 0
|
||||
m_StaticBatchRoot: {fileID: 0}
|
||||
m_ProbeAnchor: {fileID: 0}
|
||||
m_LightProbeVolumeOverride: {fileID: 0}
|
||||
m_ScaleInLightmap: 1
|
||||
m_ReceiveGI: 1
|
||||
m_PreserveUVs: 0
|
||||
m_IgnoreNormalsForChartDetection: 0
|
||||
m_ImportantGI: 0
|
||||
m_StitchLightmapSeams: 1
|
||||
m_SelectedEditorRenderState: 3
|
||||
m_MinimumChartSize: 4
|
||||
m_AutoUVMaxDistance: 0.5
|
||||
m_AutoUVMaxAngle: 89
|
||||
m_LightmapParameters: {fileID: 0}
|
||||
m_SortingLayerID: 0
|
||||
m_SortingLayer: 0
|
||||
m_SortingOrder: 0
|
||||
m_Time: 5
|
||||
m_PreviewTimeScale: 1
|
||||
m_Parameters:
|
||||
serializedVersion: 3
|
||||
widthMultiplier: 5
|
||||
widthCurve:
|
||||
serializedVersion: 2
|
||||
m_Curve:
|
||||
- serializedVersion: 3
|
||||
time: 0
|
||||
value: 1
|
||||
inSlope: 0
|
||||
outSlope: 0
|
||||
tangentMode: 0
|
||||
weightedMode: 0
|
||||
inWeight: 0.33333334
|
||||
outWeight: 0.33333334
|
||||
m_PreInfinity: 2
|
||||
m_PostInfinity: 2
|
||||
m_RotationOrder: 4
|
||||
colorGradient:
|
||||
serializedVersion: 2
|
||||
key0: {r: 1, g: 0, b: 0, a: 1}
|
||||
key1: {r: 1, g: 1, b: 1, a: 1}
|
||||
key2: {r: 0, g: 0, b: 0, a: 0}
|
||||
key3: {r: 0, g: 0, b: 0, a: 0}
|
||||
key4: {r: 0, g: 0, b: 0, a: 0}
|
||||
key5: {r: 0, g: 0, b: 0, a: 0}
|
||||
key6: {r: 0, g: 0, b: 0, a: 0}
|
||||
key7: {r: 0, g: 0, b: 0, a: 0}
|
||||
ctime0: 0
|
||||
ctime1: 65535
|
||||
ctime2: 0
|
||||
ctime3: 0
|
||||
ctime4: 0
|
||||
ctime5: 0
|
||||
ctime6: 0
|
||||
ctime7: 0
|
||||
atime0: 0
|
||||
atime1: 65535
|
||||
atime2: 0
|
||||
atime3: 0
|
||||
atime4: 0
|
||||
atime5: 0
|
||||
atime6: 0
|
||||
atime7: 0
|
||||
m_Mode: 0
|
||||
m_ColorSpace: 0
|
||||
m_NumColorKeys: 2
|
||||
m_NumAlphaKeys: 2
|
||||
numCornerVertices: 0
|
||||
numCapVertices: 0
|
||||
alignment: 0
|
||||
textureMode: 0
|
||||
textureScale: {x: 1, y: 1}
|
||||
shadowBias: 0.5
|
||||
generateLightingData: 0
|
||||
m_MinVertexDistance: 0.1
|
||||
m_MaskInteraction: 0
|
||||
m_Autodestruct: 0
|
||||
m_Emitting: 1
|
||||
m_ApplyActiveColorSpace: 0
|
||||
--- !u!1 &4590233640347492898
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 8315564871113561163}
|
||||
- component: {fileID: 6203868598056538240}
|
||||
m_Layer: 0
|
||||
m_Name: Collider
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &8315564871113561163
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 4590233640347492898}
|
||||
serializedVersion: 2
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 8462434346230391091}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!135 &6203868598056538240
|
||||
SphereCollider:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 4590233640347492898}
|
||||
m_Material: {fileID: 0}
|
||||
m_IncludeLayers:
|
||||
serializedVersion: 2
|
||||
m_Bits: 0
|
||||
m_ExcludeLayers:
|
||||
serializedVersion: 2
|
||||
m_Bits: 0
|
||||
m_LayerOverridePriority: 0
|
||||
m_IsTrigger: 1
|
||||
m_ProvidesContacts: 0
|
||||
m_Enabled: 1
|
||||
serializedVersion: 3
|
||||
m_Radius: 10
|
||||
m_Center: {x: 0, y: 0, z: 0}
|
||||
--- !u!1 &6438458936967544359
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 8462434346230391091}
|
||||
- component: {fileID: 4451965530778273955}
|
||||
- component: {fileID: 4194966225731047199}
|
||||
m_Layer: 0
|
||||
m_Name: FixedWingMissileThreat
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &8462434346230391091
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 6438458936967544359}
|
||||
serializedVersion: 2
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children:
|
||||
- {fileID: 585396986125101381}
|
||||
- {fileID: 8315564871113561163}
|
||||
- {fileID: 9192475791974545516}
|
||||
m_Father: {fileID: 0}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!54 &4451965530778273955
|
||||
Rigidbody:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 6438458936967544359}
|
||||
serializedVersion: 4
|
||||
m_Mass: 1
|
||||
m_Drag: 0
|
||||
m_AngularDrag: 0
|
||||
m_CenterOfMass: {x: 0, y: 0, z: 0}
|
||||
m_InertiaTensor: {x: 1, y: 1, z: 1}
|
||||
m_InertiaRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_IncludeLayers:
|
||||
serializedVersion: 2
|
||||
m_Bits: 0
|
||||
m_ExcludeLayers:
|
||||
serializedVersion: 2
|
||||
m_Bits: 0
|
||||
m_ImplicitCom: 1
|
||||
m_ImplicitTensor: 1
|
||||
m_UseGravity: 0
|
||||
m_IsKinematic: 0
|
||||
m_Interpolate: 0
|
||||
m_Constraints: 0
|
||||
m_CollisionDetection: 0
|
||||
--- !u!114 &4194966225731047199
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 6438458936967544359}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 4e6c2fbd1e492be448760f5045b13b2e, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
_flightPhase: 3
|
||||
_velocity: {x: 0, y: 0, z: 0}
|
||||
_acceleration: {x: 0, y: 0, z: 0}
|
||||
_dragAcceleration: {x: 0, y: 0, z: 0}
|
||||
_target: {fileID: 0}
|
||||
staticConfigFile: generic_static_config.json
|
|
@ -1,361 +0,0 @@
|
|||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!1 &295999596028346972
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 9192475791974545516}
|
||||
- component: {fileID: 3681380462727606042}
|
||||
- component: {fileID: 5038767565634652910}
|
||||
m_Layer: 0
|
||||
m_Name: Cone
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &9192475791974545516
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 295999596028346972}
|
||||
serializedVersion: 2
|
||||
m_LocalRotation: {x: 0.7071068, y: 0, z: 0, w: 0.7071068}
|
||||
m_LocalPosition: {x: 0, y: 0, z: -3.89}
|
||||
m_LocalScale: {x: 20, y: 20, z: 20}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 8462434346230391091}
|
||||
m_LocalEulerAnglesHint: {x: 90, y: 0, z: 0}
|
||||
--- !u!33 &3681380462727606042
|
||||
MeshFilter:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 295999596028346972}
|
||||
m_Mesh: {fileID: 4300000, guid: 36b72d5a34c22d94c88a068dfcbdf27a, type: 2}
|
||||
--- !u!23 &5038767565634652910
|
||||
MeshRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 295999596028346972}
|
||||
m_Enabled: 1
|
||||
m_CastShadows: 1
|
||||
m_ReceiveShadows: 1
|
||||
m_DynamicOccludee: 1
|
||||
m_StaticShadowCaster: 0
|
||||
m_MotionVectors: 1
|
||||
m_LightProbeUsage: 1
|
||||
m_ReflectionProbeUsage: 1
|
||||
m_RayTracingMode: 2
|
||||
m_RayTraceProcedural: 0
|
||||
m_RayTracingAccelStructBuildFlagsOverride: 0
|
||||
m_RayTracingAccelStructBuildFlags: 1
|
||||
m_SmallMeshCulling: 1
|
||||
m_RenderingLayerMask: 1
|
||||
m_RendererPriority: 0
|
||||
m_Materials:
|
||||
- {fileID: 2100000, guid: 061083197c659dc44983633a84d39cea, type: 2}
|
||||
m_StaticBatchInfo:
|
||||
firstSubMesh: 0
|
||||
subMeshCount: 0
|
||||
m_StaticBatchRoot: {fileID: 0}
|
||||
m_ProbeAnchor: {fileID: 0}
|
||||
m_LightProbeVolumeOverride: {fileID: 0}
|
||||
m_ScaleInLightmap: 1
|
||||
m_ReceiveGI: 1
|
||||
m_PreserveUVs: 0
|
||||
m_IgnoreNormalsForChartDetection: 0
|
||||
m_ImportantGI: 0
|
||||
m_StitchLightmapSeams: 1
|
||||
m_SelectedEditorRenderState: 3
|
||||
m_MinimumChartSize: 4
|
||||
m_AutoUVMaxDistance: 0.5
|
||||
m_AutoUVMaxAngle: 89
|
||||
m_LightmapParameters: {fileID: 0}
|
||||
m_SortingLayerID: 0
|
||||
m_SortingLayer: 0
|
||||
m_SortingOrder: 0
|
||||
m_AdditionalVertexStreams: {fileID: 0}
|
||||
--- !u!1 &4390675743535140416
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 585396986125101381}
|
||||
- component: {fileID: 4620404264009677289}
|
||||
m_Layer: 0
|
||||
m_Name: TrailRenderer
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &585396986125101381
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 4390675743535140416}
|
||||
serializedVersion: 2
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 10, y: 10, z: 10}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 8462434346230391091}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!96 &4620404264009677289
|
||||
TrailRenderer:
|
||||
serializedVersion: 3
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 4390675743535140416}
|
||||
m_Enabled: 1
|
||||
m_CastShadows: 0
|
||||
m_ReceiveShadows: 0
|
||||
m_DynamicOccludee: 1
|
||||
m_StaticShadowCaster: 0
|
||||
m_MotionVectors: 0
|
||||
m_LightProbeUsage: 0
|
||||
m_ReflectionProbeUsage: 0
|
||||
m_RayTracingMode: 0
|
||||
m_RayTraceProcedural: 0
|
||||
m_RayTracingAccelStructBuildFlagsOverride: 0
|
||||
m_RayTracingAccelStructBuildFlags: 1
|
||||
m_SmallMeshCulling: 1
|
||||
m_RenderingLayerMask: 1
|
||||
m_RendererPriority: 0
|
||||
m_Materials:
|
||||
- {fileID: 2100000, guid: 0e42500808910f24cb6626a81760c995, type: 2}
|
||||
m_StaticBatchInfo:
|
||||
firstSubMesh: 0
|
||||
subMeshCount: 0
|
||||
m_StaticBatchRoot: {fileID: 0}
|
||||
m_ProbeAnchor: {fileID: 0}
|
||||
m_LightProbeVolumeOverride: {fileID: 0}
|
||||
m_ScaleInLightmap: 1
|
||||
m_ReceiveGI: 1
|
||||
m_PreserveUVs: 0
|
||||
m_IgnoreNormalsForChartDetection: 0
|
||||
m_ImportantGI: 0
|
||||
m_StitchLightmapSeams: 1
|
||||
m_SelectedEditorRenderState: 3
|
||||
m_MinimumChartSize: 4
|
||||
m_AutoUVMaxDistance: 0.5
|
||||
m_AutoUVMaxAngle: 89
|
||||
m_LightmapParameters: {fileID: 0}
|
||||
m_SortingLayerID: 0
|
||||
m_SortingLayer: 0
|
||||
m_SortingOrder: 0
|
||||
m_Time: 5
|
||||
m_PreviewTimeScale: 1
|
||||
m_Parameters:
|
||||
serializedVersion: 3
|
||||
widthMultiplier: 5
|
||||
widthCurve:
|
||||
serializedVersion: 2
|
||||
m_Curve:
|
||||
- serializedVersion: 3
|
||||
time: 0
|
||||
value: 1
|
||||
inSlope: 0
|
||||
outSlope: 0
|
||||
tangentMode: 0
|
||||
weightedMode: 0
|
||||
inWeight: 0.33333334
|
||||
outWeight: 0.33333334
|
||||
m_PreInfinity: 2
|
||||
m_PostInfinity: 2
|
||||
m_RotationOrder: 4
|
||||
colorGradient:
|
||||
serializedVersion: 2
|
||||
key0: {r: 1, g: 0, b: 0, a: 1}
|
||||
key1: {r: 1, g: 1, b: 1, a: 1}
|
||||
key2: {r: 0, g: 0, b: 0, a: 0}
|
||||
key3: {r: 0, g: 0, b: 0, a: 0}
|
||||
key4: {r: 0, g: 0, b: 0, a: 0}
|
||||
key5: {r: 0, g: 0, b: 0, a: 0}
|
||||
key6: {r: 0, g: 0, b: 0, a: 0}
|
||||
key7: {r: 0, g: 0, b: 0, a: 0}
|
||||
ctime0: 0
|
||||
ctime1: 65535
|
||||
ctime2: 0
|
||||
ctime3: 0
|
||||
ctime4: 0
|
||||
ctime5: 0
|
||||
ctime6: 0
|
||||
ctime7: 0
|
||||
atime0: 0
|
||||
atime1: 65535
|
||||
atime2: 0
|
||||
atime3: 0
|
||||
atime4: 0
|
||||
atime5: 0
|
||||
atime6: 0
|
||||
atime7: 0
|
||||
m_Mode: 0
|
||||
m_ColorSpace: 0
|
||||
m_NumColorKeys: 2
|
||||
m_NumAlphaKeys: 2
|
||||
numCornerVertices: 0
|
||||
numCapVertices: 0
|
||||
alignment: 0
|
||||
textureMode: 0
|
||||
textureScale: {x: 1, y: 1}
|
||||
shadowBias: 0.5
|
||||
generateLightingData: 0
|
||||
m_MinVertexDistance: 0.1
|
||||
m_MaskInteraction: 0
|
||||
m_Autodestruct: 0
|
||||
m_Emitting: 1
|
||||
m_ApplyActiveColorSpace: 0
|
||||
--- !u!1 &4590233640347492898
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 8315564871113561163}
|
||||
- component: {fileID: 6203868598056538240}
|
||||
m_Layer: 0
|
||||
m_Name: Collider
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &8315564871113561163
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 4590233640347492898}
|
||||
serializedVersion: 2
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 8462434346230391091}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!135 &6203868598056538240
|
||||
SphereCollider:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 4590233640347492898}
|
||||
m_Material: {fileID: 0}
|
||||
m_IncludeLayers:
|
||||
serializedVersion: 2
|
||||
m_Bits: 0
|
||||
m_ExcludeLayers:
|
||||
serializedVersion: 2
|
||||
m_Bits: 0
|
||||
m_LayerOverridePriority: 0
|
||||
m_IsTrigger: 1
|
||||
m_ProvidesContacts: 0
|
||||
m_Enabled: 1
|
||||
serializedVersion: 3
|
||||
m_Radius: 10
|
||||
m_Center: {x: 0, y: 0, z: 0}
|
||||
--- !u!1 &6438458936967544359
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 8462434346230391091}
|
||||
- component: {fileID: -2759790757235477429}
|
||||
- component: {fileID: 4451965530778273955}
|
||||
m_Layer: 0
|
||||
m_Name: RollStabilizedMissileThreat
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &8462434346230391091
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 6438458936967544359}
|
||||
serializedVersion: 2
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children:
|
||||
- {fileID: 585396986125101381}
|
||||
- {fileID: 8315564871113561163}
|
||||
- {fileID: 9192475791974545516}
|
||||
m_Father: {fileID: 0}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!114 &-2759790757235477429
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 6438458936967544359}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 16e40584b2154ef4a95c84e85a321999, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
_flightPhase: 3
|
||||
_velocity: {x: 0, y: 0, z: 0}
|
||||
_acceleration: {x: 0, y: 0, z: 0}
|
||||
_dragAcceleration: {x: 0, y: 0, z: 0}
|
||||
_target: {fileID: 0}
|
||||
staticConfigFile: base_roll_stabilized_missile.json
|
||||
--- !u!54 &4451965530778273955
|
||||
Rigidbody:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 6438458936967544359}
|
||||
serializedVersion: 4
|
||||
m_Mass: 1
|
||||
m_Drag: 0
|
||||
m_AngularDrag: 0
|
||||
m_CenterOfMass: {x: 0, y: 0, z: 0}
|
||||
m_InertiaTensor: {x: 1, y: 1, z: 1}
|
||||
m_InertiaRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_IncludeLayers:
|
||||
serializedVersion: 2
|
||||
m_Bits: 0
|
||||
m_ExcludeLayers:
|
||||
serializedVersion: 2
|
||||
m_Bits: 0
|
||||
m_ImplicitCom: 1
|
||||
m_ImplicitTensor: 1
|
||||
m_UseGravity: 0
|
||||
m_IsKinematic: 0
|
||||
m_Interpolate: 0
|
||||
m_Constraints: 0
|
||||
m_CollisionDetection: 0
|
|
@ -1,5 +1,5 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 0d798867791c1444b985d8807b144572
|
||||
guid: b00bb4a2208bd164392fce8408d145e7
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
|
@ -1,5 +1,5 @@
|
|||
fileFormatVersion: 2
|
||||
guid: f034d27b4aab67a47865af3d624c4375
|
||||
guid: bd2143c1edb61ab4ab876add0f4ab9f2
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
|
@ -1,5 +1,6 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 72573475cbd372d4dbb25291cc6545b0
|
||||
guid: 0f46139bb9c99e9499af0597ad648f3e
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
|
@ -1,5 +1,6 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 22c1e00f13b5ec6468892b8c6df37933
|
||||
guid: 8accc326a00806044a0099b7d98eb9cc
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
|
@ -13,7 +13,7 @@ OcclusionCullingSettings:
|
|||
--- !u!104 &2
|
||||
RenderSettings:
|
||||
m_ObjectHideFlags: 0
|
||||
serializedVersion: 9
|
||||
serializedVersion: 10
|
||||
m_Fog: 0
|
||||
m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1}
|
||||
m_FogMode: 3
|
||||
|
@ -43,7 +43,6 @@ RenderSettings:
|
|||
LightmapSettings:
|
||||
m_ObjectHideFlags: 0
|
||||
serializedVersion: 12
|
||||
m_GIWorkflowMode: 1
|
||||
m_GISettings:
|
||||
serializedVersion: 2
|
||||
m_BounceScale: 1
|
||||
|
@ -66,9 +65,6 @@ LightmapSettings:
|
|||
m_LightmapParameters: {fileID: 0}
|
||||
m_LightmapsBakeMode: 1
|
||||
m_TextureCompression: 1
|
||||
m_FinalGather: 0
|
||||
m_FinalGatherFiltering: 1
|
||||
m_FinalGatherRayCount: 256
|
||||
m_ReflectionCompression: 2
|
||||
m_MixedBakeMode: 2
|
||||
m_BakeBackend: 1
|
||||
|
@ -207,9 +203,8 @@ Light:
|
|||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 50643631}
|
||||
m_Enabled: 1
|
||||
serializedVersion: 10
|
||||
serializedVersion: 11
|
||||
m_Type: 1
|
||||
m_Shape: 0
|
||||
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_Intensity: 0.75
|
||||
m_Range: 10
|
||||
|
@ -259,8 +254,12 @@ Light:
|
|||
m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_UseBoundingSphereOverride: 0
|
||||
m_UseViewFrustumForShadowCasterCull: 1
|
||||
m_ForceVisible: 0
|
||||
m_ShadowRadius: 0
|
||||
m_ShadowAngle: 0
|
||||
m_LightUnit: 1
|
||||
m_LuxAtDistance: 1
|
||||
m_EnableSpotReflector: 1
|
||||
--- !u!4 &50643634
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
|
@ -349,6 +348,9 @@ MeshRenderer:
|
|||
m_ReflectionProbeUsage: 1
|
||||
m_RayTracingMode: 2
|
||||
m_RayTraceProcedural: 0
|
||||
m_RayTracingAccelStructBuildFlagsOverride: 0
|
||||
m_RayTracingAccelStructBuildFlags: 1
|
||||
m_SmallMeshCulling: 1
|
||||
m_RenderingLayerMask: 1
|
||||
m_RendererPriority: 0
|
||||
m_Materials:
|
||||
|
@ -455,6 +457,9 @@ MeshRenderer:
|
|||
m_ReflectionProbeUsage: 1
|
||||
m_RayTracingMode: 2
|
||||
m_RayTraceProcedural: 0
|
||||
m_RayTracingAccelStructBuildFlagsOverride: 0
|
||||
m_RayTracingAccelStructBuildFlags: 1
|
||||
m_SmallMeshCulling: 1
|
||||
m_RenderingLayerMask: 1
|
||||
m_RendererPriority: 0
|
||||
m_Materials:
|
||||
|
@ -561,6 +566,9 @@ MeshRenderer:
|
|||
m_ReflectionProbeUsage: 1
|
||||
m_RayTracingMode: 2
|
||||
m_RayTraceProcedural: 0
|
||||
m_RayTracingAccelStructBuildFlagsOverride: 0
|
||||
m_RayTracingAccelStructBuildFlags: 1
|
||||
m_SmallMeshCulling: 1
|
||||
m_RenderingLayerMask: 1
|
||||
m_RendererPriority: 0
|
||||
m_Materials:
|
||||
|
@ -667,6 +675,9 @@ MeshRenderer:
|
|||
m_ReflectionProbeUsage: 1
|
||||
m_RayTracingMode: 2
|
||||
m_RayTraceProcedural: 0
|
||||
m_RayTracingAccelStructBuildFlagsOverride: 0
|
||||
m_RayTracingAccelStructBuildFlags: 1
|
||||
m_SmallMeshCulling: 1
|
||||
m_RenderingLayerMask: 1
|
||||
m_RendererPriority: 0
|
||||
m_Materials:
|
||||
|
@ -863,6 +874,9 @@ MeshRenderer:
|
|||
m_ReflectionProbeUsage: 1
|
||||
m_RayTracingMode: 2
|
||||
m_RayTraceProcedural: 0
|
||||
m_RayTracingAccelStructBuildFlagsOverride: 0
|
||||
m_RayTracingAccelStructBuildFlags: 1
|
||||
m_SmallMeshCulling: 1
|
||||
m_RenderingLayerMask: 1
|
||||
m_RendererPriority: 0
|
||||
m_Materials:
|
||||
|
@ -996,15 +1010,17 @@ MonoBehaviour:
|
|||
m_lineSpacingMax: 0
|
||||
m_paragraphSpacing: 0
|
||||
m_charWidthMaxAdj: 0
|
||||
m_enableWordWrapping: 1
|
||||
m_TextWrappingMode: 1
|
||||
m_wordWrappingRatios: 0.4
|
||||
m_overflowMode: 0
|
||||
m_linkedTextComponent: {fileID: 0}
|
||||
parentLinkedComponent: {fileID: 0}
|
||||
m_enableKerning: 1
|
||||
m_ActiveFontFeatures: 6e72656b
|
||||
m_enableExtraPadding: 0
|
||||
checkPaddingRequired: 0
|
||||
m_isRichText: 1
|
||||
m_EmojiFallbackSupport: 1
|
||||
m_parseCtrlCharacters: 1
|
||||
m_isOrthographic: 1
|
||||
m_isCullingEnabled: 0
|
||||
|
@ -1103,6 +1119,9 @@ MeshRenderer:
|
|||
m_ReflectionProbeUsage: 1
|
||||
m_RayTracingMode: 2
|
||||
m_RayTraceProcedural: 0
|
||||
m_RayTracingAccelStructBuildFlagsOverride: 0
|
||||
m_RayTracingAccelStructBuildFlags: 1
|
||||
m_SmallMeshCulling: 1
|
||||
m_RenderingLayerMask: 1
|
||||
m_RendererPriority: 0
|
||||
m_Materials:
|
||||
|
@ -1419,14 +1438,18 @@ MonoBehaviour:
|
|||
m_ItemText: {fileID: 1985109736}
|
||||
m_ItemImage: {fileID: 0}
|
||||
m_Value: 0
|
||||
m_MultiSelect: 0
|
||||
m_Options:
|
||||
m_Options:
|
||||
- m_Text: Option A
|
||||
m_Image: {fileID: 0}
|
||||
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
||||
- m_Text: Option B
|
||||
m_Image: {fileID: 0}
|
||||
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
||||
- m_Text: Option C
|
||||
m_Image: {fileID: 0}
|
||||
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_OnValueChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
|
@ -1569,15 +1592,17 @@ MonoBehaviour:
|
|||
m_lineSpacingMax: 0
|
||||
m_paragraphSpacing: 0
|
||||
m_charWidthMaxAdj: 0
|
||||
m_enableWordWrapping: 1
|
||||
m_TextWrappingMode: 1
|
||||
m_wordWrappingRatios: 0.4
|
||||
m_overflowMode: 0
|
||||
m_linkedTextComponent: {fileID: 0}
|
||||
parentLinkedComponent: {fileID: 0}
|
||||
m_enableKerning: 1
|
||||
m_ActiveFontFeatures: 6e72656b
|
||||
m_enableExtraPadding: 0
|
||||
checkPaddingRequired: 0
|
||||
m_isRichText: 1
|
||||
m_EmojiFallbackSupport: 1
|
||||
m_parseCtrlCharacters: 1
|
||||
m_isOrthographic: 1
|
||||
m_isCullingEnabled: 0
|
||||
|
@ -1703,15 +1728,17 @@ MonoBehaviour:
|
|||
m_lineSpacingMax: 0
|
||||
m_paragraphSpacing: 0
|
||||
m_charWidthMaxAdj: 0
|
||||
m_enableWordWrapping: 1
|
||||
m_TextWrappingMode: 1
|
||||
m_wordWrappingRatios: 0.4
|
||||
m_overflowMode: 0
|
||||
m_linkedTextComponent: {fileID: 0}
|
||||
parentLinkedComponent: {fileID: 0}
|
||||
m_enableKerning: 1
|
||||
m_ActiveFontFeatures: 6e72656b
|
||||
m_enableExtraPadding: 0
|
||||
checkPaddingRequired: 0
|
||||
m_isRichText: 1
|
||||
m_EmojiFallbackSupport: 1
|
||||
m_parseCtrlCharacters: 1
|
||||
m_isOrthographic: 0
|
||||
m_isCullingEnabled: 0
|
||||
|
@ -1749,6 +1776,9 @@ MeshRenderer:
|
|||
m_ReflectionProbeUsage: 1
|
||||
m_RayTracingMode: 2
|
||||
m_RayTraceProcedural: 0
|
||||
m_RayTracingAccelStructBuildFlagsOverride: 0
|
||||
m_RayTracingAccelStructBuildFlags: 1
|
||||
m_SmallMeshCulling: 1
|
||||
m_RenderingLayerMask: 1
|
||||
m_RendererPriority: 0
|
||||
m_Materials:
|
||||
|
@ -1851,6 +1881,9 @@ MeshRenderer:
|
|||
m_ReflectionProbeUsage: 1
|
||||
m_RayTracingMode: 2
|
||||
m_RayTraceProcedural: 0
|
||||
m_RayTracingAccelStructBuildFlagsOverride: 0
|
||||
m_RayTracingAccelStructBuildFlags: 1
|
||||
m_SmallMeshCulling: 1
|
||||
m_RenderingLayerMask: 1
|
||||
m_RendererPriority: 0
|
||||
m_Materials:
|
||||
|
@ -1933,9 +1966,8 @@ Light:
|
|||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 396716023}
|
||||
m_Enabled: 1
|
||||
serializedVersion: 10
|
||||
serializedVersion: 11
|
||||
m_Type: 1
|
||||
m_Shape: 0
|
||||
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_Intensity: 0.75
|
||||
m_Range: 10
|
||||
|
@ -1985,8 +2017,12 @@ Light:
|
|||
m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_UseBoundingSphereOverride: 0
|
||||
m_UseViewFrustumForShadowCasterCull: 1
|
||||
m_ForceVisible: 0
|
||||
m_ShadowRadius: 0
|
||||
m_ShadowAngle: 0
|
||||
m_LightUnit: 1
|
||||
m_LuxAtDistance: 1
|
||||
m_EnableSpotReflector: 1
|
||||
--- !u!4 &396716026
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
|
@ -2075,6 +2111,9 @@ MeshRenderer:
|
|||
m_ReflectionProbeUsage: 1
|
||||
m_RayTracingMode: 2
|
||||
m_RayTraceProcedural: 0
|
||||
m_RayTracingAccelStructBuildFlagsOverride: 0
|
||||
m_RayTracingAccelStructBuildFlags: 1
|
||||
m_SmallMeshCulling: 1
|
||||
m_RenderingLayerMask: 1
|
||||
m_RendererPriority: 0
|
||||
m_Materials:
|
||||
|
@ -2185,6 +2224,9 @@ MeshRenderer:
|
|||
m_ReflectionProbeUsage: 1
|
||||
m_RayTracingMode: 2
|
||||
m_RayTraceProcedural: 0
|
||||
m_RayTracingAccelStructBuildFlagsOverride: 0
|
||||
m_RayTracingAccelStructBuildFlags: 1
|
||||
m_SmallMeshCulling: 1
|
||||
m_RenderingLayerMask: 1
|
||||
m_RendererPriority: 0
|
||||
m_Materials:
|
||||
|
@ -2298,9 +2340,8 @@ Light:
|
|||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 566761696}
|
||||
m_Enabled: 1
|
||||
serializedVersion: 10
|
||||
serializedVersion: 11
|
||||
m_Type: 1
|
||||
m_Shape: 0
|
||||
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_Intensity: 0.75
|
||||
m_Range: 10
|
||||
|
@ -2350,8 +2391,12 @@ Light:
|
|||
m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_UseBoundingSphereOverride: 0
|
||||
m_UseViewFrustumForShadowCasterCull: 1
|
||||
m_ForceVisible: 0
|
||||
m_ShadowRadius: 0
|
||||
m_ShadowAngle: 0
|
||||
m_LightUnit: 1
|
||||
m_LuxAtDistance: 1
|
||||
m_EnableSpotReflector: 1
|
||||
--- !u!4 &566761699
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
|
@ -2474,15 +2519,17 @@ MonoBehaviour:
|
|||
m_lineSpacingMax: 0
|
||||
m_paragraphSpacing: 0
|
||||
m_charWidthMaxAdj: 0
|
||||
m_enableWordWrapping: 1
|
||||
m_TextWrappingMode: 1
|
||||
m_wordWrappingRatios: 0.4
|
||||
m_overflowMode: 0
|
||||
m_linkedTextComponent: {fileID: 0}
|
||||
parentLinkedComponent: {fileID: 0}
|
||||
m_enableKerning: 1
|
||||
m_ActiveFontFeatures: 6e72656b
|
||||
m_enableExtraPadding: 0
|
||||
checkPaddingRequired: 0
|
||||
m_isRichText: 1
|
||||
m_EmojiFallbackSupport: 1
|
||||
m_parseCtrlCharacters: 1
|
||||
m_isOrthographic: 1
|
||||
m_isCullingEnabled: 0
|
||||
|
@ -3022,15 +3069,17 @@ MonoBehaviour:
|
|||
m_lineSpacingMax: 0
|
||||
m_paragraphSpacing: 0
|
||||
m_charWidthMaxAdj: 0
|
||||
m_enableWordWrapping: 1
|
||||
m_TextWrappingMode: 1
|
||||
m_wordWrappingRatios: 0.4
|
||||
m_overflowMode: 0
|
||||
m_linkedTextComponent: {fileID: 0}
|
||||
parentLinkedComponent: {fileID: 0}
|
||||
m_enableKerning: 1
|
||||
m_ActiveFontFeatures: 6e72656b
|
||||
m_enableExtraPadding: 0
|
||||
checkPaddingRequired: 0
|
||||
m_isRichText: 1
|
||||
m_EmojiFallbackSupport: 1
|
||||
m_parseCtrlCharacters: 1
|
||||
m_isOrthographic: 0
|
||||
m_isCullingEnabled: 0
|
||||
|
@ -3068,6 +3117,9 @@ MeshRenderer:
|
|||
m_ReflectionProbeUsage: 1
|
||||
m_RayTracingMode: 2
|
||||
m_RayTraceProcedural: 0
|
||||
m_RayTracingAccelStructBuildFlagsOverride: 0
|
||||
m_RayTracingAccelStructBuildFlags: 1
|
||||
m_SmallMeshCulling: 1
|
||||
m_RenderingLayerMask: 1
|
||||
m_RendererPriority: 0
|
||||
m_Materials:
|
||||
|
@ -3268,15 +3320,17 @@ MonoBehaviour:
|
|||
m_lineSpacingMax: 0
|
||||
m_paragraphSpacing: 0
|
||||
m_charWidthMaxAdj: 0
|
||||
m_enableWordWrapping: 1
|
||||
m_TextWrappingMode: 1
|
||||
m_wordWrappingRatios: 0.4
|
||||
m_overflowMode: 0
|
||||
m_linkedTextComponent: {fileID: 0}
|
||||
parentLinkedComponent: {fileID: 0}
|
||||
m_enableKerning: 1
|
||||
m_ActiveFontFeatures: 6e72656b
|
||||
m_enableExtraPadding: 0
|
||||
checkPaddingRequired: 0
|
||||
m_isRichText: 1
|
||||
m_EmojiFallbackSupport: 1
|
||||
m_parseCtrlCharacters: 1
|
||||
m_isOrthographic: 1
|
||||
m_isCullingEnabled: 0
|
||||
|
@ -3410,6 +3464,51 @@ CanvasRenderer:
|
|||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1071150555}
|
||||
m_CullTransparentMesh: 1
|
||||
--- !u!1 &1134242713
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 1134242715}
|
||||
- component: {fileID: 1134242714}
|
||||
m_Layer: 0
|
||||
m_Name: IADS
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!114 &1134242714
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1134242713}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: a5899f1049cf3d64e8c06c1db772c879, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
_threatTable: []
|
||||
--- !u!4 &1134242715
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1134242713}
|
||||
serializedVersion: 2
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 0}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!1 &1254435375
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
|
@ -3478,6 +3577,9 @@ MeshRenderer:
|
|||
m_ReflectionProbeUsage: 1
|
||||
m_RayTracingMode: 2
|
||||
m_RayTraceProcedural: 0
|
||||
m_RayTracingAccelStructBuildFlagsOverride: 0
|
||||
m_RayTracingAccelStructBuildFlags: 1
|
||||
m_SmallMeshCulling: 1
|
||||
m_RenderingLayerMask: 1
|
||||
m_RendererPriority: 0
|
||||
m_Materials:
|
||||
|
@ -3599,6 +3701,9 @@ MeshRenderer:
|
|||
m_ReflectionProbeUsage: 1
|
||||
m_RayTracingMode: 2
|
||||
m_RayTraceProcedural: 0
|
||||
m_RayTracingAccelStructBuildFlagsOverride: 0
|
||||
m_RayTracingAccelStructBuildFlags: 1
|
||||
m_SmallMeshCulling: 1
|
||||
m_RenderingLayerMask: 1
|
||||
m_RendererPriority: 0
|
||||
m_Materials:
|
||||
|
@ -3732,15 +3837,17 @@ MonoBehaviour:
|
|||
m_lineSpacingMax: 0
|
||||
m_paragraphSpacing: 0
|
||||
m_charWidthMaxAdj: 0
|
||||
m_enableWordWrapping: 1
|
||||
m_TextWrappingMode: 1
|
||||
m_wordWrappingRatios: 0.4
|
||||
m_overflowMode: 0
|
||||
m_linkedTextComponent: {fileID: 0}
|
||||
parentLinkedComponent: {fileID: 0}
|
||||
m_enableKerning: 1
|
||||
m_ActiveFontFeatures: 6e72656b
|
||||
m_enableExtraPadding: 0
|
||||
checkPaddingRequired: 0
|
||||
m_isRichText: 1
|
||||
m_EmojiFallbackSupport: 1
|
||||
m_parseCtrlCharacters: 1
|
||||
m_isOrthographic: 0
|
||||
m_isCullingEnabled: 0
|
||||
|
@ -3778,6 +3885,9 @@ MeshRenderer:
|
|||
m_ReflectionProbeUsage: 1
|
||||
m_RayTracingMode: 2
|
||||
m_RayTraceProcedural: 0
|
||||
m_RayTracingAccelStructBuildFlagsOverride: 0
|
||||
m_RayTracingAccelStructBuildFlags: 1
|
||||
m_SmallMeshCulling: 1
|
||||
m_RenderingLayerMask: 1
|
||||
m_RendererPriority: 0
|
||||
m_Materials:
|
||||
|
@ -4207,15 +4317,17 @@ MonoBehaviour:
|
|||
m_lineSpacingMax: 0
|
||||
m_paragraphSpacing: 0
|
||||
m_charWidthMaxAdj: 0
|
||||
m_enableWordWrapping: 1
|
||||
m_TextWrappingMode: 1
|
||||
m_wordWrappingRatios: 0.4
|
||||
m_overflowMode: 0
|
||||
m_linkedTextComponent: {fileID: 0}
|
||||
parentLinkedComponent: {fileID: 0}
|
||||
m_enableKerning: 1
|
||||
m_ActiveFontFeatures: 6e72656b
|
||||
m_enableExtraPadding: 0
|
||||
checkPaddingRequired: 0
|
||||
m_isRichText: 1
|
||||
m_EmojiFallbackSupport: 1
|
||||
m_parseCtrlCharacters: 1
|
||||
m_isOrthographic: 1
|
||||
m_isCullingEnabled: 0
|
||||
|
@ -4389,6 +4501,9 @@ MeshRenderer:
|
|||
m_ReflectionProbeUsage: 1
|
||||
m_RayTracingMode: 2
|
||||
m_RayTraceProcedural: 0
|
||||
m_RayTracingAccelStructBuildFlagsOverride: 0
|
||||
m_RayTracingAccelStructBuildFlags: 1
|
||||
m_SmallMeshCulling: 1
|
||||
m_RenderingLayerMask: 1
|
||||
m_RendererPriority: 0
|
||||
m_Materials:
|
||||
|
@ -4611,15 +4726,17 @@ MonoBehaviour:
|
|||
m_lineSpacingMax: 0
|
||||
m_paragraphSpacing: 0
|
||||
m_charWidthMaxAdj: 0
|
||||
m_enableWordWrapping: 1
|
||||
m_TextWrappingMode: 1
|
||||
m_wordWrappingRatios: 0.4
|
||||
m_overflowMode: 0
|
||||
m_linkedTextComponent: {fileID: 0}
|
||||
parentLinkedComponent: {fileID: 0}
|
||||
m_enableKerning: 1
|
||||
m_ActiveFontFeatures: 6e72656b
|
||||
m_enableExtraPadding: 0
|
||||
checkPaddingRequired: 0
|
||||
m_isRichText: 1
|
||||
m_EmojiFallbackSupport: 1
|
||||
m_parseCtrlCharacters: 1
|
||||
m_isOrthographic: 0
|
||||
m_isCullingEnabled: 0
|
||||
|
@ -4657,6 +4774,9 @@ MeshRenderer:
|
|||
m_ReflectionProbeUsage: 1
|
||||
m_RayTracingMode: 2
|
||||
m_RayTraceProcedural: 0
|
||||
m_RayTracingAccelStructBuildFlagsOverride: 0
|
||||
m_RayTracingAccelStructBuildFlags: 1
|
||||
m_SmallMeshCulling: 1
|
||||
m_RenderingLayerMask: 1
|
||||
m_RendererPriority: 0
|
||||
m_Materials:
|
||||
|
@ -4858,15 +4978,17 @@ MonoBehaviour:
|
|||
m_lineSpacingMax: 0
|
||||
m_paragraphSpacing: 0
|
||||
m_charWidthMaxAdj: 0
|
||||
m_enableWordWrapping: 1
|
||||
m_TextWrappingMode: 1
|
||||
m_wordWrappingRatios: 0.4
|
||||
m_overflowMode: 0
|
||||
m_linkedTextComponent: {fileID: 0}
|
||||
parentLinkedComponent: {fileID: 0}
|
||||
m_enableKerning: 1
|
||||
m_ActiveFontFeatures: 00000000
|
||||
m_enableExtraPadding: 0
|
||||
checkPaddingRequired: 0
|
||||
m_isRichText: 1
|
||||
m_EmojiFallbackSupport: 1
|
||||
m_parseCtrlCharacters: 1
|
||||
m_isOrthographic: 1
|
||||
m_isCullingEnabled: 0
|
||||
|
@ -5461,3 +5583,4 @@ SceneRoots:
|
|||
- {fileID: 566761699}
|
||||
- {fileID: 50643634}
|
||||
- {fileID: 396716026}
|
||||
- {fileID: 1134242715}
|
||||
|
|
|
@ -33,16 +33,16 @@ public abstract class Agent : MonoBehaviour {
|
|||
protected StaticConfig _staticConfig;
|
||||
|
||||
// Define delegates
|
||||
public delegate void AgentHitEventHandler(Agent agent);
|
||||
public delegate void AgentMissEventHandler(Agent agent);
|
||||
public delegate void InterceptHitEventHandler(Interceptor interceptor, Threat target);
|
||||
public delegate void InterceptMissEventHandler(Interceptor interceptor, Threat target);
|
||||
|
||||
// Define events
|
||||
public event AgentHitEventHandler OnAgentHit;
|
||||
public event AgentMissEventHandler OnAgentMiss;
|
||||
public event InterceptHitEventHandler OnInterceptHit;
|
||||
public event InterceptMissEventHandler OnInterceptMiss;
|
||||
|
||||
public void SetFlightPhase(FlightPhase flightPhase) {
|
||||
Debug.Log(
|
||||
$"Setting {name} flight phase to {flightPhase} at time {SimManager.Instance.GetElapsedSimulationTime()}");
|
||||
$"Setting flight phase to {flightPhase} at time {SimManager.Instance.GetElapsedSimulationTime()}");
|
||||
_timeInPhase = 0;
|
||||
_flightPhase = flightPhase;
|
||||
}
|
||||
|
@ -94,10 +94,6 @@ public abstract class Agent : MonoBehaviour {
|
|||
return _isHit;
|
||||
}
|
||||
|
||||
public bool IsMiss() {
|
||||
return _isMiss;
|
||||
}
|
||||
|
||||
public void TerminateAgent() {
|
||||
_flightPhase = FlightPhase.TERMINATED;
|
||||
transform.position = new Vector3(0, 0, 0);
|
||||
|
@ -105,16 +101,23 @@ public abstract class Agent : MonoBehaviour {
|
|||
}
|
||||
|
||||
// Mark the agent as having hit the target or been hit.
|
||||
public void MarkAsHit() {
|
||||
public void HandleInterceptHit(Agent otherAgent) {
|
||||
_isHit = true;
|
||||
OnAgentHit?.Invoke(this);
|
||||
if (this is Interceptor interceptor && otherAgent is Threat threat) {
|
||||
OnInterceptHit?.Invoke(interceptor, threat);
|
||||
} else if (this is Threat threatAgent && otherAgent is Interceptor interceptorTarget) {
|
||||
OnInterceptHit?.Invoke(interceptorTarget, threatAgent);
|
||||
}
|
||||
TerminateAgent();
|
||||
}
|
||||
|
||||
public void MarkAsMiss() {
|
||||
_isMiss = true;
|
||||
public void HandleInterceptMiss() {
|
||||
if (_target != null) {
|
||||
OnAgentMiss?.Invoke(this);
|
||||
if (this is Interceptor interceptor && _target is Threat threat) {
|
||||
OnInterceptMiss?.Invoke(interceptor, threat);
|
||||
} else if (this is Threat threatAgent && _target is Interceptor interceptorTarget) {
|
||||
OnInterceptMiss?.Invoke(interceptorTarget, threatAgent);
|
||||
}
|
||||
_target = null;
|
||||
}
|
||||
TerminateAgent();
|
||||
|
@ -128,10 +131,6 @@ public abstract class Agent : MonoBehaviour {
|
|||
return GetComponent<Rigidbody>().linearVelocity;
|
||||
}
|
||||
|
||||
public Vector3 GetAcceleration() {
|
||||
return _acceleration;
|
||||
}
|
||||
|
||||
public double GetDynamicPressure() {
|
||||
var airDensity = Constants.CalculateAirDensityAtAltitude(transform.position.y);
|
||||
var flowSpeed = GetSpeed();
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections;
|
||||
using UnityEngine;
|
||||
using System.Linq;
|
||||
using System.Diagnostics.Contracts;
|
||||
|
||||
// The assignment class is an interface for assigning a threat to each interceptor.
|
||||
public interface IAssignment {
|
||||
|
@ -8,39 +11,30 @@ public interface IAssignment {
|
|||
// The first element corresponds to the interceptor index, and the second element
|
||||
// corresponds to the threat index.
|
||||
public struct AssignmentItem {
|
||||
public int InterceptorIndex;
|
||||
public int ThreatIndex;
|
||||
public Interceptor Interceptor;
|
||||
public Threat Threat;
|
||||
|
||||
public AssignmentItem(int missileIndex, int threatIndex) {
|
||||
InterceptorIndex = missileIndex;
|
||||
ThreatIndex = threatIndex;
|
||||
public AssignmentItem(Interceptor interceptor, Threat threat) {
|
||||
Interceptor = interceptor;
|
||||
Threat = threat;
|
||||
}
|
||||
}
|
||||
|
||||
// A list containing the interceptor-target assignments.
|
||||
|
||||
// Assign a target to each interceptor that has not been assigned a target yet.
|
||||
public abstract IEnumerable<AssignmentItem> Assign(List<Agent> missiles, List<Agent> targets);
|
||||
[Pure]
|
||||
public abstract IEnumerable<AssignmentItem> Assign(in IReadOnlyList<Interceptor> interceptors, in IReadOnlyList<ThreatData> threatTable);
|
||||
|
||||
// Get the list of assignable interceptor indices.
|
||||
protected static List<int> GetAssignableInterceptorIndices(List<Agent> missiles) {
|
||||
List<int> assignableInterceptorIndices = new List<int>();
|
||||
for (int missileIndex = 0; missileIndex < missiles.Count; missileIndex++) {
|
||||
if (missiles[missileIndex].IsAssignable()) {
|
||||
assignableInterceptorIndices.Add(missileIndex);
|
||||
}
|
||||
}
|
||||
return assignableInterceptorIndices;
|
||||
[Pure]
|
||||
protected static List<Interceptor> GetAssignableInterceptors(in IReadOnlyList<Interceptor> interceptors) {
|
||||
return interceptors.Where(interceptor => interceptor.IsAssignable()).ToList();
|
||||
}
|
||||
|
||||
// Get the list of active target indices.
|
||||
protected static List<int> GetActiveThreatIndices(List<Agent> threats) {
|
||||
List<int> activeThreatIndices = new List<int>();
|
||||
for (int threatIndex = 0; threatIndex < threats.Count; threatIndex++) {
|
||||
if (!threats[threatIndex].IsHit()) {
|
||||
activeThreatIndices.Add(threatIndex);
|
||||
}
|
||||
}
|
||||
return activeThreatIndices;
|
||||
// Get the list of active threats.
|
||||
[Pure]
|
||||
protected static List<ThreatData> GetActiveThreats(in IReadOnlyList<ThreatData> threats) {
|
||||
return threats.Where(t => t.Status != ThreatStatus.DESTROYED).ToList();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,39 +1,43 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
// The round-robin assignment class assigns missiles to the targets in a
|
||||
// round-robin order.
|
||||
using System.Diagnostics.Contracts;
|
||||
// The round-robin assignment class assigns interceptors to the targets in a
|
||||
// round-robin order using the new paradigm.
|
||||
public class RoundRobinAssignment : IAssignment {
|
||||
// Previous target index that was assigned.
|
||||
private int prevTargetIndex = -1;
|
||||
// Previous target index that was assigned.
|
||||
private int prevTargetIndex = -1;
|
||||
|
||||
// Assign a target to each interceptor that has not been assigned a target yet.
|
||||
public IEnumerable<IAssignment.AssignmentItem> Assign(List<Agent> missiles, List<Agent> targets) {
|
||||
List<IAssignment.AssignmentItem> assignments = new List<IAssignment.AssignmentItem>();
|
||||
List<int> assignableInterceptorIndices = IAssignment.GetAssignableInterceptorIndices(missiles);
|
||||
if (assignableInterceptorIndices.Count == 0) {
|
||||
return assignments;
|
||||
// Assign a target to each interceptor that has not been assigned a target yet.
|
||||
[Pure]
|
||||
public IEnumerable<IAssignment.AssignmentItem> Assign(in IReadOnlyList<Interceptor> interceptors, in IReadOnlyList<ThreatData> targets) {
|
||||
List<IAssignment.AssignmentItem> assignments = new List<IAssignment.AssignmentItem>();
|
||||
|
||||
// Get the list of interceptors that are available for assignment.
|
||||
List<Interceptor> assignableInterceptors = IAssignment.GetAssignableInterceptors(interceptors);
|
||||
if (assignableInterceptors.Count == 0) {
|
||||
return assignments;
|
||||
}
|
||||
|
||||
// Get the list of active threats that need to be addressed.
|
||||
List<ThreatData> activeThreats = IAssignment.GetActiveThreats(targets);
|
||||
if (activeThreats.Count == 0) {
|
||||
return assignments;
|
||||
}
|
||||
|
||||
// Perform round-robin assignment.
|
||||
foreach (Interceptor interceptor in assignableInterceptors) {
|
||||
// Determine the next target index in a round-robin fashion.
|
||||
int nextTargetIndex = (prevTargetIndex + 1) % activeThreats.Count;
|
||||
ThreatData selectedThreat = activeThreats[nextTargetIndex];
|
||||
|
||||
// Assign the interceptor to the selected threat.
|
||||
assignments.Add(new IAssignment.AssignmentItem(interceptor, selectedThreat.Threat));
|
||||
|
||||
// Update the previous target index.
|
||||
prevTargetIndex = nextTargetIndex;
|
||||
}
|
||||
|
||||
return assignments;
|
||||
}
|
||||
|
||||
List<int> activeThreatIndices = IAssignment.GetActiveThreatIndices(targets);
|
||||
if (activeThreatIndices.Count == 0) {
|
||||
return assignments;
|
||||
}
|
||||
|
||||
foreach (int missileIndex in assignableInterceptorIndices) {
|
||||
int nextActiveTargetIndex = activeThreatIndices.FindIndex(index => index > prevTargetIndex);
|
||||
|
||||
if (nextActiveTargetIndex == -1) {
|
||||
nextActiveTargetIndex = 0;
|
||||
}
|
||||
|
||||
int nextTargetIndex = activeThreatIndices[nextActiveTargetIndex];
|
||||
assignments.Add(new IAssignment.AssignmentItem(missileIndex, nextTargetIndex));
|
||||
prevTargetIndex = nextTargetIndex;
|
||||
}
|
||||
|
||||
return assignments;
|
||||
}
|
||||
}
|
|
@ -3,70 +3,64 @@ using System.Collections.Generic;
|
|||
using System.Linq;
|
||||
using Unity.VisualScripting;
|
||||
using UnityEngine;
|
||||
|
||||
// The threat assignment class assigns missiles to the targets based
|
||||
using System.Diagnostics.Contracts;
|
||||
// The threat assignment class assigns interceptors to the targets based
|
||||
// on the threat level of the targets.
|
||||
public class ThreatAssignment : IAssignment {
|
||||
// Assign a target to each interceptor that has not been assigned a target yet.
|
||||
public IEnumerable<IAssignment.AssignmentItem> Assign(List<Agent> missiles, List<Agent> targets) {
|
||||
[Pure]
|
||||
public IEnumerable<IAssignment.AssignmentItem> Assign(in IReadOnlyList<Interceptor> interceptors, in IReadOnlyList<ThreatData> targets) {
|
||||
List<IAssignment.AssignmentItem> assignments = new List<IAssignment.AssignmentItem>();
|
||||
|
||||
List<int> assignableInterceptorIndices = IAssignment.GetAssignableInterceptorIndices(missiles);
|
||||
if (assignableInterceptorIndices.Count == 0) {
|
||||
List<Interceptor> assignableInterceptors = IAssignment.GetAssignableInterceptors(interceptors);
|
||||
if (assignableInterceptors.Count == 0) {
|
||||
Debug.LogWarning("No assignable interceptors found");
|
||||
return assignments;
|
||||
}
|
||||
|
||||
List<int> activeThreatIndices = IAssignment.GetActiveThreatIndices(targets);
|
||||
if (activeThreatIndices.Count == 0) {
|
||||
List<ThreatData> activeThreats = IAssignment.GetActiveThreats(targets);
|
||||
if (activeThreats.Count == 0) {
|
||||
Debug.LogWarning("No active threats found");
|
||||
return assignments;
|
||||
}
|
||||
|
||||
Vector3 positionToDefend = Vector3.zero;
|
||||
List<ThreatInfo> threatInfos =
|
||||
CalculateThreatLevels(targets, activeThreatIndices, positionToDefend);
|
||||
CalculateThreatLevels(activeThreats, positionToDefend);
|
||||
|
||||
foreach (int missileIndex in assignableInterceptorIndices) {
|
||||
if (missiles[missileIndex].HasAssignedTarget())
|
||||
continue;
|
||||
if (threatInfos.Count == 0)
|
||||
break;
|
||||
|
||||
// Find the optimal target for this interceptor based on distance and threat
|
||||
ThreatInfo optimalTarget = null;
|
||||
float optimalScore = float.MinValue;
|
||||
|
||||
foreach (ThreatInfo threat in threatInfos) {
|
||||
float distance = Vector3.Distance(missiles[missileIndex].transform.position,
|
||||
targets[threat.TargetIndex].transform.position);
|
||||
float score = threat.ThreatLevel / distance; // Balance threat level with proximity
|
||||
|
||||
if (score > optimalScore) {
|
||||
optimalScore = score;
|
||||
optimalTarget = threat;
|
||||
// Sort ThreatInfo first by ThreatData.Status (UNASSIGNED first, then ASSIGNED)
|
||||
// Within each group, order by ThreatLevel descending
|
||||
threatInfos = threatInfos.OrderByDescending(t => t.ThreatData.Status == ThreatStatus.UNASSIGNED)
|
||||
.ThenByDescending(t => t.ThreatLevel)
|
||||
.ToList();
|
||||
|
||||
var assignableInterceptorsEnumerator = assignableInterceptors.GetEnumerator();
|
||||
if (assignableInterceptorsEnumerator.MoveNext()) // Move to the first element
|
||||
{
|
||||
foreach (ThreatInfo threatInfo in threatInfos) {
|
||||
assignments.Add(new IAssignment.AssignmentItem(assignableInterceptorsEnumerator.Current, threatInfo.ThreatData.Threat));
|
||||
if (!assignableInterceptorsEnumerator.MoveNext()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (optimalTarget != null) {
|
||||
assignments.Add(new IAssignment.AssignmentItem(missileIndex, optimalTarget.TargetIndex));
|
||||
threatInfos.Remove(optimalTarget);
|
||||
}
|
||||
}
|
||||
return assignments;
|
||||
}
|
||||
|
||||
private List<ThreatInfo> CalculateThreatLevels(List<Agent> targets, List<int> activeThreatIndices,
|
||||
Vector3 missilesMeanPosition) {
|
||||
|
||||
private List<ThreatInfo> CalculateThreatLevels(List<ThreatData> threatTable,
|
||||
Vector3 defensePosition) {
|
||||
List<ThreatInfo> threatInfos = new List<ThreatInfo>();
|
||||
|
||||
foreach (int targetIndex in activeThreatIndices) {
|
||||
Agent target = targets[targetIndex];
|
||||
float distanceToMean = Vector3.Distance(target.transform.position, missilesMeanPosition);
|
||||
float velocityMagnitude = target.GetVelocity().magnitude;
|
||||
foreach (ThreatData threatData in threatTable) {
|
||||
Threat threat = threatData.Threat;
|
||||
float distanceToMean = Vector3.Distance(threat.transform.position, defensePosition);
|
||||
float velocityMagnitude = threat.GetVelocity().magnitude;
|
||||
|
||||
// Calculate threat level based on proximity and velocity
|
||||
float threatLevel = (1 / distanceToMean) * velocityMagnitude;
|
||||
|
||||
threatInfos.Add(new ThreatInfo(targetIndex, threatLevel));
|
||||
threatInfos.Add(new ThreatInfo(threatData, threatLevel));
|
||||
}
|
||||
|
||||
// Sort threats in descending order
|
||||
|
@ -74,11 +68,11 @@ public class ThreatAssignment : IAssignment {
|
|||
}
|
||||
|
||||
private class ThreatInfo {
|
||||
public int TargetIndex { get; }
|
||||
public ThreatData ThreatData { get; }
|
||||
public float ThreatLevel { get; }
|
||||
|
||||
public ThreatInfo(int targetIndex, float threatLevel) {
|
||||
TargetIndex = targetIndex;
|
||||
public ThreatInfo(ThreatData threatData, float threatLevel) {
|
||||
ThreatData = threatData;
|
||||
ThreatLevel = threatLevel;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,121 +4,115 @@ using UnityEngine;
|
|||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Converters;
|
||||
|
||||
|
||||
[Serializable]
|
||||
public class SimulationConfig {
|
||||
[Header("Simulation Settings")]
|
||||
public float timeScale = 0.05f;
|
||||
[Header("Simulation Settings")]
|
||||
public float timeScale = 0.05f;
|
||||
|
||||
// [Header("Defense Points")]
|
||||
// public SwarmConfig defense_points_config;
|
||||
[Header("Interceptor Swarm Configurations")]
|
||||
public List<SwarmConfig> interceptor_swarm_configs = new List<SwarmConfig>();
|
||||
|
||||
[Header("Interceptor Swarm Configurations")]
|
||||
public List<SwarmConfig> interceptor_swarm_configs = new List<SwarmConfig>();
|
||||
|
||||
[Header("Threat Swarm Configurations")]
|
||||
public List<SwarmConfig> threat_swarm_configs = new List<SwarmConfig>();
|
||||
[Header("Threat Swarm Configurations")]
|
||||
public List<SwarmConfig> threat_swarm_configs = new List<SwarmConfig>();
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class DynamicConfig {
|
||||
public LaunchConfig launch_config;
|
||||
public SensorConfig sensor_config;
|
||||
public LaunchConfig launch_config;
|
||||
public SensorConfig sensor_config;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
[Serializable]
|
||||
public class SwarmConfig {
|
||||
public int num_agents;
|
||||
public AgentConfig agent_config;
|
||||
public int num_agents;
|
||||
public AgentConfig agent_config;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class AgentConfig {
|
||||
public InterceptorType interceptor_type;
|
||||
public ThreatType threat_type;
|
||||
public InitialState initial_state;
|
||||
public StandardDeviation standard_deviation;
|
||||
public DynamicConfig dynamic_config;
|
||||
public PlottingConfig plotting_config;
|
||||
public SubmunitionsConfig submunitions_config;
|
||||
public InterceptorType interceptor_type;
|
||||
public ThreatType threat_type;
|
||||
public InitialState initial_state;
|
||||
public StandardDeviation standard_deviation;
|
||||
public DynamicConfig dynamic_config;
|
||||
public PlottingConfig plotting_config;
|
||||
public SubmunitionsConfig submunitions_config;
|
||||
|
||||
public static AgentConfig FromSubmunitionAgentConfig(SubmunitionAgentConfig submunitionConfig) {
|
||||
return new AgentConfig {
|
||||
interceptor_type = submunitionConfig.interceptor_type,
|
||||
initial_state = submunitionConfig.initial_state,
|
||||
standard_deviation = submunitionConfig.standard_deviation,
|
||||
dynamic_config = submunitionConfig.dynamic_config,
|
||||
plotting_config = submunitionConfig.plotting_config,
|
||||
// Set other fields as needed, using default values if not present in SubmunitionAgentConfig
|
||||
threat_type = ThreatType.DRONE, // Or another default value
|
||||
submunitions_config = null // Or a default value if needed
|
||||
};
|
||||
}
|
||||
public static AgentConfig FromSubmunitionAgentConfig(SubmunitionAgentConfig submunitionConfig) {
|
||||
return new AgentConfig {
|
||||
interceptor_type = submunitionConfig.interceptor_type,
|
||||
initial_state = submunitionConfig.initial_state,
|
||||
standard_deviation = submunitionConfig.standard_deviation,
|
||||
dynamic_config = submunitionConfig.dynamic_config,
|
||||
plotting_config = submunitionConfig.plotting_config,
|
||||
// Set other fields as needed, using default values if not present in SubmunitionAgentConfig
|
||||
threat_type = ThreatType.DRONE, // Or another default value
|
||||
submunitions_config = null // Or a default value if needed
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class InitialState {
|
||||
public Vector3 position;
|
||||
public Vector3 rotation;
|
||||
public Vector3 velocity;
|
||||
public Vector3 position;
|
||||
public Vector3 rotation;
|
||||
public Vector3 velocity;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class StandardDeviation {
|
||||
public Vector3 position;
|
||||
public Vector3 velocity;
|
||||
public Vector3 position;
|
||||
public Vector3 velocity;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
[Serializable]
|
||||
public class LaunchConfig {
|
||||
public float launch_time;
|
||||
public float launch_time;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class PlottingConfig {
|
||||
public ConfigColor color;
|
||||
public LineStyle linestyle;
|
||||
public Marker marker;
|
||||
public ConfigColor color;
|
||||
public LineStyle linestyle;
|
||||
public Marker marker;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class SubmunitionsConfig {
|
||||
public int num_submunitions;
|
||||
public LaunchConfig launch_config;
|
||||
public SubmunitionAgentConfig agent_config;
|
||||
public int num_submunitions;
|
||||
public LaunchConfig launch_config;
|
||||
public SubmunitionAgentConfig agent_config;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class SubmunitionAgentConfig {
|
||||
public InterceptorType interceptor_type;
|
||||
public InitialState initial_state;
|
||||
public StandardDeviation standard_deviation;
|
||||
public DynamicConfig dynamic_config;
|
||||
public PlottingConfig plotting_config;
|
||||
public InterceptorType interceptor_type;
|
||||
public InitialState initial_state;
|
||||
public StandardDeviation standard_deviation;
|
||||
public DynamicConfig dynamic_config;
|
||||
public PlottingConfig plotting_config;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class SensorConfig {
|
||||
public SensorType type;
|
||||
public float frequency;
|
||||
public SensorType type;
|
||||
public float frequency;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class TargetConfig {
|
||||
public ThreatType threat_type;
|
||||
public InitialState initial_state;
|
||||
public PlottingConfig plotting_config;
|
||||
public string prefabName;
|
||||
public ThreatType threat_type;
|
||||
public InitialState initial_state;
|
||||
public PlottingConfig plotting_config;
|
||||
public string prefabName;
|
||||
}
|
||||
|
||||
// Enums
|
||||
[JsonConverter(typeof(StringEnumConverter))]
|
||||
public enum InterceptorType { HYDRA_70, MICROMISSILE }
|
||||
[JsonConverter(typeof(StringEnumConverter))]
|
||||
public enum ThreatType {
|
||||
DRONE,
|
||||
FIXED_WING_MISSILE,
|
||||
ROLL_STABILIZED_MISSILE
|
||||
} // Add ballistic later -michael
|
||||
public enum ThreatType { DRONE, ANTISHIP_MISSILE }
|
||||
[JsonConverter(typeof(StringEnumConverter))]
|
||||
public enum ConfigColor { BLUE, GREEN, RED }
|
||||
[JsonConverter(typeof(StringEnumConverter))]
|
||||
|
|
|
@ -1,28 +0,0 @@
|
|||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// Static targetable point to defend
|
||||
/// </summary>
|
||||
public class DefendPoint : Agent {
|
||||
// Currently just initializes to the origin
|
||||
public DefendPoint() {
|
||||
// Set the initial state
|
||||
this.transform.position = Vector3.zero;
|
||||
}
|
||||
|
||||
protected override void FixedUpdate() {
|
||||
return;
|
||||
}
|
||||
|
||||
protected override void UpdateBoost(double deltaTime) {
|
||||
return;
|
||||
}
|
||||
|
||||
protected override void UpdateMidCourse(double deltaTime) {
|
||||
return;
|
||||
}
|
||||
|
||||
protected override void UpdateReady(double deltaTime) {
|
||||
return;
|
||||
}
|
||||
}
|
|
@ -1,2 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 7eed014a152a65043be19cd044faa5d2
|
|
@ -3,6 +3,7 @@ using UnityEditor;
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
public class GenerateCone : EditorWindow {
|
||||
private int sides = 16;
|
||||
private float baseRadius = 1f;
|
||||
|
@ -139,4 +140,5 @@ public class GenerateCone : EditorWindow {
|
|||
}
|
||||
return sum / vertices.Count;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -1,30 +1,146 @@
|
|||
using UnityEngine;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
// Integrated Air Defense System
|
||||
public class IADS : MonoBehaviour {
|
||||
public enum TargetStatus { UNASSIGNED, ASSIGNED, HIT, DEGRADED, DESTROYED }
|
||||
|
||||
// Look up threat status by unique threat ID
|
||||
public Dictionary<string, TargetStatus> _targetStatusDictionary;
|
||||
public enum ThreatAssignmentStyle {
|
||||
ONE_TIME,
|
||||
CONTINUOUS
|
||||
}
|
||||
|
||||
private List<Threat> _threats;
|
||||
public static IADS Instance { get; private set; }
|
||||
private IAssignment _assignmentScheme;
|
||||
|
||||
[SerializeField]
|
||||
private List<ThreatData> _threatTable = new List<ThreatData>();
|
||||
private Dictionary<Threat, ThreatData> _threatDataMap = new Dictionary<Threat, ThreatData>();
|
||||
|
||||
private List<Interceptor> _interceptors;
|
||||
private List<Interceptor> _assignmentQueue = new List<Interceptor>();
|
||||
|
||||
private List<Vessel> _vessels;
|
||||
private void Awake() {
|
||||
if (Instance == null) {
|
||||
Instance = this;
|
||||
} else {
|
||||
Destroy(gameObject);
|
||||
}
|
||||
|
||||
public delegate void RegisterNewThreatDelegate(Threat threat);
|
||||
public event RegisterNewThreatDelegate OnRegisterNewThreat;
|
||||
}
|
||||
|
||||
void Start() {
|
||||
_threats = new List<Threat>();
|
||||
private void Start() {
|
||||
SimManager.Instance.OnSimulationEnded += RegisterSimulationEnded;
|
||||
SimManager.Instance.OnNewThreat += RegisterNewThreat;
|
||||
SimManager.Instance.OnNewInterceptor += RegisterNewInterceptor;
|
||||
_assignmentScheme = new ThreatAssignment();
|
||||
|
||||
}
|
||||
|
||||
public void LateUpdate() {
|
||||
if (_assignmentQueue.Count > 0) {
|
||||
AssignInterceptorsToThreats(_assignmentQueue);
|
||||
_assignmentQueue.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
public void RequestThreatAssignment(List<Interceptor> interceptors) {
|
||||
_assignmentQueue.AddRange(interceptors);
|
||||
}
|
||||
|
||||
public void RequestThreatAssignment(Interceptor interceptor) {
|
||||
_assignmentQueue.Add(interceptor);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Assigns the specified list of missiles to available targets based on the assignment scheme.
|
||||
/// </summary>
|
||||
/// <param name="missilesToAssign">The list of missiles to assign.</param>
|
||||
public void AssignInterceptorsToThreats(List<Interceptor> missilesToAssign) {
|
||||
// Perform the assignment
|
||||
IEnumerable<IAssignment.AssignmentItem> assignments =
|
||||
_assignmentScheme.Assign(missilesToAssign, _threatTable);
|
||||
|
||||
// Apply the assignments to the missiles
|
||||
foreach (var assignment in assignments) {
|
||||
assignment.Interceptor.AssignTarget(assignment.Threat);
|
||||
_threatDataMap[assignment.Threat].AssignInterceptor(assignment.Interceptor);
|
||||
Debug.Log($"Interceptor {assignment.Interceptor.name} assigned to threat {assignment.Threat.name}");
|
||||
}
|
||||
|
||||
// Check if any interceptors were not assigned
|
||||
List<Interceptor> unassignedInterceptors = missilesToAssign.Where(m => !m.HasAssignedTarget()).ToList();
|
||||
|
||||
if (unassignedInterceptors.Count > 0)
|
||||
{
|
||||
string unassignedIds = string.Join(", ", unassignedInterceptors.Select(m => m.name));
|
||||
int totalInterceptors = missilesToAssign.Count;
|
||||
int assignedInterceptors = totalInterceptors - unassignedInterceptors.Count;
|
||||
|
||||
Debug.LogWarning($"Warning: {unassignedInterceptors.Count} out of {totalInterceptors} interceptors were not assigned to any threat. " +
|
||||
$"Unassigned interceptor IDs: {unassignedIds}. " +
|
||||
$"Total interceptors: {totalInterceptors}, Assigned: {assignedInterceptors}, Unassigned: {unassignedInterceptors.Count}");
|
||||
|
||||
// Log information about the assignment scheme
|
||||
Debug.Log($"Current Assignment Scheme: {_assignmentScheme.GetType().Name}");
|
||||
}
|
||||
}
|
||||
|
||||
public void RegisterNewThreat(Threat threat) {
|
||||
_threats.Add(threat);
|
||||
OnRegisterNewThreat?.Invoke(threat);
|
||||
ThreatData threatData = new ThreatData(threat, threat.gameObject.name);
|
||||
_threatTable.Add(threatData);
|
||||
_threatDataMap.Add(threat, threatData);
|
||||
|
||||
// Subscribe to the threat's events
|
||||
// TODO: If we do not want omniscient IADS, we
|
||||
// need to model the IADS's sensors here.
|
||||
threat.OnInterceptHit += RegisterThreatHit;
|
||||
threat.OnInterceptMiss += RegisterThreatMiss;
|
||||
}
|
||||
|
||||
public void RegisterNewInterceptor(Interceptor interceptor) {
|
||||
// Placeholder
|
||||
interceptor.OnInterceptMiss += RegisterInterceptorMiss;
|
||||
interceptor.OnInterceptHit += RegisterInterceptorHit;
|
||||
}
|
||||
|
||||
private void RegisterInterceptorHit(Interceptor interceptor, Threat threat) {
|
||||
ThreatData threatData = _threatDataMap[threat];
|
||||
if (threatData != null) {
|
||||
threatData.RemoveInterceptor(interceptor);
|
||||
MarkThreatDestroyed(threatData);
|
||||
}
|
||||
}
|
||||
|
||||
private void RegisterInterceptorMiss(Interceptor interceptor, Threat threat) {
|
||||
// Remove the interceptor from the threat's assigned interceptors
|
||||
_threatDataMap[threat].RemoveInterceptor(interceptor);
|
||||
}
|
||||
private void RegisterThreatHit(Interceptor interceptor, Threat threat) {
|
||||
ThreatData threatData = _threatDataMap[threat];
|
||||
if (threatData != null) {
|
||||
threatData.RemoveInterceptor(interceptor);
|
||||
MarkThreatDestroyed(threatData);
|
||||
}
|
||||
}
|
||||
|
||||
private void MarkThreatDestroyed(ThreatData threatData) {
|
||||
if (threatData != null) {
|
||||
threatData.MarkDestroyed();
|
||||
}
|
||||
}
|
||||
|
||||
private void RegisterThreatMiss(Interceptor interceptor, Threat threat) {
|
||||
ThreatData threatData = _threatDataMap[threat];
|
||||
threatData.RemoveInterceptor(interceptor);
|
||||
}
|
||||
|
||||
private void RegisterSimulationEnded() {
|
||||
_threatTable.Clear();
|
||||
_threatDataMap.Clear();
|
||||
_assignmentQueue.Clear();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
[System.Serializable]
|
||||
public enum ThreatStatus {
|
||||
UNASSIGNED,
|
||||
ASSIGNED,
|
||||
DESTROYED
|
||||
}
|
||||
[System.Serializable]
|
||||
public class ThreatData
|
||||
{
|
||||
public Threat Threat;
|
||||
[SerializeField]
|
||||
private ThreatStatus _status;
|
||||
public ThreatStatus Status { get { return _status; } }
|
||||
public string ThreatID;
|
||||
[SerializeField]
|
||||
private List<Interceptor> _assignedInterceptors; // Changed from property to field
|
||||
|
||||
public void AssignInterceptor(Interceptor interceptor) {
|
||||
if(Status == ThreatStatus.DESTROYED) {
|
||||
Debug.LogError($"AssignInterceptor: Threat {ThreatID} is destroyed, cannot assign interceptor");
|
||||
return;
|
||||
}
|
||||
_status = ThreatStatus.ASSIGNED;
|
||||
_assignedInterceptors.Add(interceptor);
|
||||
}
|
||||
|
||||
public void RemoveInterceptor(Interceptor interceptor) {
|
||||
_assignedInterceptors.Remove(interceptor);
|
||||
if(_assignedInterceptors.Count == 0) {
|
||||
_status = ThreatStatus.UNASSIGNED;
|
||||
}
|
||||
}
|
||||
|
||||
public void MarkDestroyed() {
|
||||
_status = ThreatStatus.DESTROYED;
|
||||
}
|
||||
// Constructor remains the same
|
||||
public ThreatData(Threat threat, string threatID)
|
||||
{
|
||||
Threat = threat;
|
||||
_status = ThreatStatus.UNASSIGNED;
|
||||
ThreatID = threatID;
|
||||
_assignedInterceptors = new List<Interceptor>(); // Initialize the list
|
||||
}
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
fileFormatVersion: 2
|
||||
guid: adc0c5dbdb9dc7d498b50cf9a15c2db5
|
|
@ -74,7 +74,7 @@ public class Interceptor : Agent {
|
|||
|
||||
private void OnTriggerEnter(Collider other) {
|
||||
if (other.gameObject.name == "Floor") {
|
||||
this.MarkAsMiss();
|
||||
this.HandleInterceptMiss();
|
||||
}
|
||||
// Check if the collision is with another Agent
|
||||
Agent otherAgent = other.gameObject.GetComponentInParent<Agent>();
|
||||
|
@ -87,13 +87,13 @@ public class Interceptor : Agent {
|
|||
// Set green for hit
|
||||
markerObject.GetComponent<Renderer>().material.color = new Color(0, 1, 0, 0.15f);
|
||||
// Mark both this agent and the other agent as hit
|
||||
this.MarkAsHit();
|
||||
otherAgent.MarkAsHit();
|
||||
this.HandleInterceptHit(otherAgent);
|
||||
otherAgent.HandleInterceptHit(otherAgent);
|
||||
|
||||
} else {
|
||||
// Set red for miss
|
||||
markerObject.GetComponent<Renderer>().material.color = new Color(1, 0, 0, 0.15f);
|
||||
this.MarkAsMiss();
|
||||
this.HandleInterceptMiss();
|
||||
// otherAgent.MarkAsMiss();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -48,6 +48,6 @@ public class Hydra70 : Interceptor {
|
|||
}
|
||||
break;
|
||||
}
|
||||
SimManager.Instance.AssignInterceptorsToThreats(submunitions);
|
||||
IADS.Instance.RequestThreatAssignment(submunitions);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ public class Micromissile : Interceptor {
|
|||
// Check whether the threat should be considered a miss
|
||||
SensorOutput sensorOutput = GetComponent<Sensor>().Sense(_target);
|
||||
if (sensorOutput.velocity.range > 1000f) {
|
||||
this.MarkAsMiss();
|
||||
this.HandleInterceptMiss();
|
||||
}
|
||||
|
||||
// Calculate the acceleration input
|
||||
|
|
|
@ -3,70 +3,261 @@ using System.Collections;
|
|||
using System.IO;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
|
||||
public class SimMonitor : MonoBehaviour
|
||||
{
|
||||
private const float UpdateRate = 0.01f; // 100 Hz
|
||||
private StreamWriter writer;
|
||||
private Coroutine monitorRoutine;
|
||||
private const float _updateRate = 0.1f; // 100 Hz
|
||||
private string _telemetryBinPath;
|
||||
private string _eventLogPath;
|
||||
private Coroutine _monitorRoutine;
|
||||
|
||||
private string _sessionDirectory;
|
||||
|
||||
|
||||
private FileStream _telemetryFileStream;
|
||||
private BinaryWriter _telemetryBinaryWriter;
|
||||
|
||||
[SerializeField]
|
||||
private List<EventRecord> _eventLogCache;
|
||||
|
||||
[System.Serializable]
|
||||
private class EventRecord
|
||||
{
|
||||
public float Time;
|
||||
public float PositionX;
|
||||
public float PositionY;
|
||||
public float PositionZ;
|
||||
public string EventType;
|
||||
public string Details;
|
||||
}
|
||||
|
||||
private void Awake() {
|
||||
InitializeSessionDirectory();
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
SimManager.Instance.OnSimulationStarted += RegisterSimulationStarted;
|
||||
SimManager.Instance.OnSimulationEnded += RegisterSimulationEnded;
|
||||
InitializeFile();
|
||||
monitorRoutine = StartCoroutine(MonitorRoutine());
|
||||
SimManager.Instance.OnNewThreat += RegisterNewThreat;
|
||||
SimManager.Instance.OnNewInterceptor += RegisterNewInterceptor;
|
||||
}
|
||||
|
||||
private void InitializeFile()
|
||||
private void InitializeSessionDirectory() {
|
||||
string timestamp = DateTime.Now.ToString("yyyyMMdd_HHmmss");
|
||||
_sessionDirectory = Application.persistentDataPath + $"\\Telemetry\\Logs\\{timestamp}";
|
||||
Directory.CreateDirectory(_sessionDirectory);
|
||||
Debug.Log($"Monitoring simulation logs to {_sessionDirectory}");
|
||||
}
|
||||
|
||||
private void InitializeLogFiles()
|
||||
{
|
||||
string timestamp = DateTime.Now.ToString("yyyyMMdd_HHmmss");
|
||||
string fileName = $"sim_telemetry_{timestamp}.csv";
|
||||
string directory = Application.persistentDataPath + "/Telemetry/Logs/";
|
||||
Directory.CreateDirectory(directory);
|
||||
string path = Path.Combine(directory, fileName);
|
||||
writer = new StreamWriter(path, false);
|
||||
writer.WriteLine("Time,AgentID,AgentX,AgentY,AgentZ,AgentVX,AgentVY,AgentVZ,AgentState,AgentType");
|
||||
Debug.Log($"Monitoring simulation data to {path}");
|
||||
|
||||
_eventLogPath = Path.Combine(_sessionDirectory, $"sim_events_{timestamp}.csv");
|
||||
|
||||
// Initialize the event log cache
|
||||
_eventLogCache = new List<EventRecord>();
|
||||
|
||||
_telemetryBinPath = Path.Combine(_sessionDirectory, $"sim_telemetry_{timestamp}.bin");
|
||||
|
||||
// Open the file stream and binary writer for telemetry data
|
||||
_telemetryFileStream = new FileStream(_telemetryBinPath, FileMode.Create, FileAccess.Write, FileShare.ReadWrite);
|
||||
_telemetryBinaryWriter = new BinaryWriter(_telemetryFileStream);
|
||||
|
||||
Debug.Log("Log files initialized successfully.");
|
||||
}
|
||||
|
||||
private void CloseLogFiles() {
|
||||
if (_telemetryBinaryWriter != null)
|
||||
{
|
||||
_telemetryBinaryWriter.Flush();
|
||||
_telemetryBinaryWriter.Close();
|
||||
_telemetryBinaryWriter = null;
|
||||
}
|
||||
|
||||
if (_telemetryFileStream != null)
|
||||
{
|
||||
_telemetryFileStream.Close();
|
||||
_telemetryFileStream = null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private IEnumerator MonitorRoutine()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
ExportTelemetry();
|
||||
yield return new WaitForSeconds(UpdateRate);
|
||||
RecordTelemetry();
|
||||
yield return new WaitForSeconds(_updateRate);
|
||||
}
|
||||
}
|
||||
|
||||
private void ExportTelemetry()
|
||||
private void RecordTelemetry()
|
||||
{
|
||||
float time = (float)SimManager.Instance.GetElapsedSimulationTime();
|
||||
foreach (var agent in SimManager.Instance.GetActiveThreats().Cast<Agent>().Concat(SimManager.Instance.GetActiveInterceptors().Cast<Agent>()))
|
||||
{
|
||||
Vector3 pos = agent.transform.position;
|
||||
if(pos == Vector3.zero) {
|
||||
continue;
|
||||
}
|
||||
Vector3 vel = agent.GetComponent<Rigidbody>().linearVelocity;
|
||||
string type = agent is Threat ? "T" : "M";
|
||||
writer.WriteLine($"{time:F2},{agent.name},{pos.x:F2},{pos.y:F2},{pos.z:F2},{vel.x:F2},{vel.y:F2},{vel.z:F2},{(int)agent.GetFlightPhase()},{type}");
|
||||
var agents = SimManager.Instance.GetActiveAgents();
|
||||
if(_telemetryBinaryWriter == null) {
|
||||
Debug.LogWarning("Telemetry binary writer is null");
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < agents.Count; i++)
|
||||
{
|
||||
var agent = agents[i];
|
||||
|
||||
writer.Flush();
|
||||
if (!agent.gameObject.activeInHierarchy)
|
||||
continue;
|
||||
|
||||
Vector3 pos = agent.transform.position;
|
||||
|
||||
if (pos == Vector3.zero)
|
||||
continue;
|
||||
|
||||
Vector3 vel = agent.GetVelocity(); // Ensure GetVelocity() doesn't allocate
|
||||
|
||||
int agentID = agent.GetInstanceID();
|
||||
int flightPhase = (int)agent.GetFlightPhase();
|
||||
byte agentType = (byte)(agent is Threat ? 0 : 1);
|
||||
|
||||
// Write telemetry data directly to the binary file
|
||||
_telemetryBinaryWriter.Write(time);
|
||||
_telemetryBinaryWriter.Write(agentID);
|
||||
_telemetryBinaryWriter.Write(pos.x);
|
||||
_telemetryBinaryWriter.Write(pos.y);
|
||||
_telemetryBinaryWriter.Write(pos.z);
|
||||
_telemetryBinaryWriter.Write(vel.x);
|
||||
_telemetryBinaryWriter.Write(vel.y);
|
||||
_telemetryBinaryWriter.Write(vel.z);
|
||||
_telemetryBinaryWriter.Write(flightPhase);
|
||||
_telemetryBinaryWriter.Write(agentType);
|
||||
}
|
||||
}
|
||||
|
||||
public void ConvertBinaryTelemetryToCsv(string binaryFilePath, string csvFilePath)
|
||||
{
|
||||
try
|
||||
{
|
||||
using FileStream fs = new FileStream(binaryFilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
|
||||
using BinaryReader reader = new BinaryReader(fs);
|
||||
using StreamWriter writer = new StreamWriter(csvFilePath, false);
|
||||
{
|
||||
// Write CSV header
|
||||
writer.WriteLine("Time,AgentID,AgentX,AgentY,AgentZ,AgentVX,AgentVY,AgentVZ,AgentState,AgentType");
|
||||
|
||||
while (reader.BaseStream.Position != reader.BaseStream.Length)
|
||||
{
|
||||
float time = reader.ReadSingle();
|
||||
int agentID = reader.ReadInt32();
|
||||
float posX = reader.ReadSingle();
|
||||
float posY = reader.ReadSingle();
|
||||
float posZ = reader.ReadSingle();
|
||||
float velX = reader.ReadSingle();
|
||||
float velY = reader.ReadSingle();
|
||||
float velZ = reader.ReadSingle();
|
||||
int flightPhase = reader.ReadInt32();
|
||||
byte agentTypeByte = reader.ReadByte();
|
||||
string agentType = agentTypeByte == 0 ? "T" : "M";
|
||||
|
||||
// Write the data to CSV
|
||||
writer.WriteLine($"{time:F2},{agentID},{posX:F2},{posY:F2},{posZ:F2},{velX:F2},{velY:F2},{velZ:F2},{flightPhase},{agentType}");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
Debug.LogWarning($"An IO error occurred while converting binary telemetry to CSV: {e.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private void WriteEventsToFile()
|
||||
{
|
||||
using (StreamWriter writer = new StreamWriter(_eventLogPath, false))
|
||||
{
|
||||
// Write CSV header
|
||||
writer.WriteLine("Time,PositionX,PositionY,PositionZ,Event,Details");
|
||||
|
||||
foreach (var record in _eventLogCache)
|
||||
{
|
||||
writer.WriteLine($"{record.Time:F2},{record.PositionX:F2},{record.PositionY:F2},{record.PositionZ:F2},{record.EventType},{record.Details}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void RegisterSimulationStarted()
|
||||
{
|
||||
InitializeLogFiles();
|
||||
_monitorRoutine = StartCoroutine(MonitorRoutine());
|
||||
}
|
||||
|
||||
private void RegisterSimulationEnded()
|
||||
{
|
||||
writer.Close();
|
||||
StopCoroutine(monitorRoutine);
|
||||
StopCoroutine(_monitorRoutine);
|
||||
CloseLogFiles();
|
||||
WriteEventsToFile();
|
||||
StartCoroutine(ConvertBinaryTelemetryToCsvCoroutine(_telemetryBinPath, Path.ChangeExtension(_telemetryBinPath, ".csv")));
|
||||
}
|
||||
|
||||
private IEnumerator ConvertBinaryTelemetryToCsvCoroutine(string binaryFilePath, string csvFilePath)
|
||||
{
|
||||
yield return null; // Wait for the next frame to ensure RecordTelemetry() has finished
|
||||
ConvertBinaryTelemetryToCsv(binaryFilePath, csvFilePath);
|
||||
}
|
||||
|
||||
public void RegisterNewThreat(Threat threat) {
|
||||
RegisterNewAgent(threat, "NEW_THREAT");
|
||||
}
|
||||
|
||||
public void RegisterNewInterceptor(Interceptor interceptor) {
|
||||
RegisterNewAgent(interceptor, "NEW_INTERCEPTOR");
|
||||
interceptor.OnInterceptMiss += RegisterInterceptorMiss;
|
||||
interceptor.OnInterceptHit += RegisterInterceptorHit;
|
||||
}
|
||||
|
||||
private void RegisterNewAgent(Agent agent, string eventType)
|
||||
{
|
||||
float time = (float)SimManager.Instance.GetElapsedSimulationTime();
|
||||
Vector3 pos = agent.transform.position;
|
||||
var record = new EventRecord
|
||||
{
|
||||
Time = time,
|
||||
PositionX = pos.x,
|
||||
PositionY = pos.y,
|
||||
PositionZ = pos.z,
|
||||
EventType = eventType,
|
||||
Details = agent.name
|
||||
};
|
||||
_eventLogCache.Add(record);
|
||||
}
|
||||
|
||||
public void RegisterInterceptorHit(Interceptor interceptor, Threat threat) {
|
||||
RegisterInterceptEvent(interceptor, threat, true);
|
||||
}
|
||||
|
||||
public void RegisterInterceptorMiss(Interceptor interceptor, Threat threat) {
|
||||
RegisterInterceptEvent(interceptor, threat, false);
|
||||
}
|
||||
|
||||
public void RegisterInterceptEvent(Interceptor interceptor, Threat threat, bool hit)
|
||||
{
|
||||
float time = (float)SimManager.Instance.GetElapsedSimulationTime();
|
||||
Vector3 pos = interceptor.transform.position;
|
||||
string eventType = hit ? "HIT" : "MISS";
|
||||
var record = new EventRecord
|
||||
{
|
||||
Time = time,
|
||||
PositionX = pos.x,
|
||||
PositionY = pos.y,
|
||||
PositionZ = pos.z,
|
||||
EventType = eventType,
|
||||
Details = $"{interceptor.name} and {threat.name}"
|
||||
};
|
||||
_eventLogCache.Add(record);
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
if (writer != null)
|
||||
{
|
||||
writer.Close();
|
||||
}
|
||||
CloseLogFiles();
|
||||
}
|
||||
}
|
|
@ -4,7 +4,7 @@ MonoImporter:
|
|||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
executionOrder: -5
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
@ -20,21 +19,30 @@ public class SimManager : MonoBehaviour {
|
|||
[SerializeField]
|
||||
public SimulationConfig simulationConfig;
|
||||
|
||||
private List<Interceptor> _interceptors = new List<Interceptor>();
|
||||
|
||||
private List<Interceptor> _activeInterceptors = new List<Interceptor>();
|
||||
private List<Threat> _unassignedThreats = new List<Threat>();
|
||||
private List<Threat> _threats = new List<Threat>();
|
||||
private List<Threat> _activeThreats = new List<Threat>();
|
||||
|
||||
|
||||
private List<Interceptor> _interceptorObjects = new List<Interceptor>();
|
||||
private List<Threat> _threatObjects = new List<Threat>();
|
||||
|
||||
private float _elapsedSimulationTime = 0f;
|
||||
private float endTime = 100f; // Set an appropriate end time
|
||||
private bool simulationRunning = false;
|
||||
|
||||
private IAssignment _assignmentScheme;
|
||||
|
||||
|
||||
public delegate void SimulationEventHandler();
|
||||
public event SimulationEventHandler OnSimulationEnded;
|
||||
public event SimulationEventHandler OnSimulationStarted;
|
||||
|
||||
public delegate void NewThreatEventHandler(Threat threat);
|
||||
public event NewThreatEventHandler OnNewThreat;
|
||||
|
||||
|
||||
public delegate void NewInterceptorEventHandler(Interceptor interceptor);
|
||||
public event NewInterceptorEventHandler OnNewInterceptor;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the elapsed simulation time.
|
||||
/// </summary>
|
||||
|
@ -48,12 +56,12 @@ public class SimManager : MonoBehaviour {
|
|||
}
|
||||
|
||||
public List<Threat> GetActiveThreats() {
|
||||
return _activeThreats;
|
||||
return _threatObjects.Where(threat => !threat.IsHit()).ToList();
|
||||
}
|
||||
|
||||
public List<Agent> GetActiveAgents() {
|
||||
return _activeInterceptors.ConvertAll(interceptor => interceptor as Agent)
|
||||
.Concat(_activeThreats.ConvertAll(threat => threat as Agent))
|
||||
.Concat(GetActiveThreats().ConvertAll(threat => threat as Agent))
|
||||
.ToList();
|
||||
}
|
||||
|
||||
|
@ -75,6 +83,7 @@ public class SimManager : MonoBehaviour {
|
|||
StartSimulation();
|
||||
ResumeSimulation();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void SetTimeScale(float timeScale) {
|
||||
|
@ -84,8 +93,9 @@ public class SimManager : MonoBehaviour {
|
|||
}
|
||||
|
||||
public void StartSimulation() {
|
||||
InitializeSimulation();
|
||||
OnSimulationStarted?.Invoke();
|
||||
InitializeSimulation();
|
||||
|
||||
}
|
||||
|
||||
public void PauseSimulation() {
|
||||
|
@ -103,13 +113,14 @@ public class SimManager : MonoBehaviour {
|
|||
}
|
||||
|
||||
private void InitializeSimulation() {
|
||||
// Invoke the simulation started event to let listeners
|
||||
// know to invoke their own handler behavior
|
||||
OnSimulationStarted?.Invoke();
|
||||
List<Interceptor> missiles = new List<Interceptor>();
|
||||
// Create missiles based on config
|
||||
foreach (var swarmConfig in simulationConfig.interceptor_swarm_configs) {
|
||||
for (int i = 0; i < swarmConfig.num_agents; i++) {
|
||||
var interceptor = CreateInterceptor(swarmConfig.agent_config);
|
||||
interceptor.OnAgentHit += RegisterInterceptorHit;
|
||||
interceptor.OnAgentMiss += RegisterInterceptorMiss;
|
||||
CreateInterceptor(swarmConfig.agent_config);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -117,78 +128,38 @@ public class SimManager : MonoBehaviour {
|
|||
// Create targets based on config
|
||||
foreach (var swarmConfig in simulationConfig.threat_swarm_configs) {
|
||||
for (int i = 0; i < swarmConfig.num_agents; i++) {
|
||||
var threat = CreateThreat(swarmConfig.agent_config);
|
||||
if (threat == null) {
|
||||
Debug.LogError($"Failed to create threat: {swarmConfig.agent_config}");
|
||||
continue;
|
||||
}
|
||||
threat.OnAgentHit += RegisterThreatHit;
|
||||
threat.OnAgentMiss += RegisterThreatMiss;
|
||||
CreateThreat(swarmConfig.agent_config);
|
||||
}
|
||||
}
|
||||
|
||||
_assignmentScheme = new ThreatAssignment();
|
||||
|
||||
// Invoke the simulation started event to let listeners
|
||||
// know to invoke their own handler behavior
|
||||
OnSimulationStarted?.Invoke();
|
||||
}
|
||||
|
||||
public void AssignInterceptorsToThreats() {
|
||||
AssignInterceptorsToThreats(_interceptors);
|
||||
IADS.Instance.AssignInterceptorsToThreats(_interceptorObjects);
|
||||
}
|
||||
|
||||
public void RegisterInterceptorHit(Agent interceptor) {
|
||||
public void RegisterInterceptorHit(Interceptor interceptor, Threat threat) {
|
||||
if (interceptor is Interceptor missileComponent) {
|
||||
_activeInterceptors.Remove(missileComponent);
|
||||
}
|
||||
}
|
||||
|
||||
public void RegisterInterceptorMiss(Agent interceptor) {
|
||||
public void RegisterInterceptorMiss(Interceptor interceptor, Threat threat) {
|
||||
if (interceptor is Interceptor missileComponent) {
|
||||
_activeInterceptors.Remove(missileComponent);
|
||||
}
|
||||
}
|
||||
|
||||
public void RegisterThreatHit(Agent threat) {
|
||||
if (threat is Threat targetComponent) {
|
||||
_activeThreats.Remove(targetComponent);
|
||||
}
|
||||
public void RegisterThreatHit(Interceptor interceptor, Threat threat) {
|
||||
// Placeholder
|
||||
}
|
||||
|
||||
public void RegisterThreatMiss(Agent threat) {
|
||||
if (threat is Threat targetComponent) {
|
||||
_unassignedThreats.Add(targetComponent);
|
||||
}
|
||||
public void RegisterThreatMiss(Interceptor interceptor, Threat threat) {
|
||||
Debug.Log($"RegisterThreatMiss: Interceptor {interceptor.name} missed threat {threat.name}");
|
||||
// Placeholder
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Assigns the specified list of missiles to available targets based on the assignment scheme.
|
||||
/// </summary>
|
||||
/// <param name="missilesToAssign">The list of missiles to assign.</param>
|
||||
public void AssignInterceptorsToThreats(List<Interceptor> missilesToAssign) {
|
||||
// Convert Interceptor and Threat lists to Agent lists
|
||||
List<Agent> missileAgents = new List<Agent>(missilesToAssign.ConvertAll(m => m as Agent));
|
||||
// Convert Threat list to Agent list, excluding already assigned targets
|
||||
List<Agent> targetAgents = _unassignedThreats.ToList<Agent>();
|
||||
|
||||
// Perform the assignment
|
||||
IEnumerable<IAssignment.AssignmentItem> assignments =
|
||||
_assignmentScheme.Assign(missileAgents, targetAgents);
|
||||
|
||||
// Apply the assignments to the missiles
|
||||
foreach (var assignment in assignments) {
|
||||
if (assignment.InterceptorIndex < missilesToAssign.Count) {
|
||||
Interceptor interceptor = missilesToAssign[assignment.InterceptorIndex];
|
||||
Threat threat = _unassignedThreats[assignment.ThreatIndex];
|
||||
interceptor.AssignTarget(threat);
|
||||
Debug.Log($"Interceptor {interceptor.name} assigned to threat {threat.name}");
|
||||
}
|
||||
}
|
||||
// TODO this whole function should be optimized
|
||||
_unassignedThreats.RemoveAll(
|
||||
threat => missilesToAssign.Any(interceptor => interceptor.GetAssignedTarget() == threat));
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Creates a interceptor based on the provided configuration.
|
||||
|
@ -196,32 +167,41 @@ public class SimManager : MonoBehaviour {
|
|||
/// <param name="config">Configuration settings for the interceptor.</param>
|
||||
/// <returns>The created Interceptor instance, or null if creation failed.</returns>
|
||||
public Interceptor CreateInterceptor(AgentConfig config) {
|
||||
string prefabName =
|
||||
config.interceptor_type switch { InterceptorType.HYDRA_70 => "Hydra70",
|
||||
InterceptorType.MICROMISSILE => "Micromissile",
|
||||
_ => "Hydra70" };
|
||||
string prefabName = config.interceptor_type switch { InterceptorType.HYDRA_70 => "Hydra70",
|
||||
InterceptorType.MICROMISSILE => "Micromissile",
|
||||
_ => "Hydra70" };
|
||||
|
||||
GameObject missileObject = CreateAgent(config, prefabName);
|
||||
if (missileObject == null)
|
||||
GameObject interceptorObject = CreateAgent(config, prefabName);
|
||||
if (interceptorObject == null)
|
||||
return null;
|
||||
|
||||
// Interceptor-specific logic
|
||||
switch (config.dynamic_config.sensor_config.type) {
|
||||
case SensorType.IDEAL:
|
||||
missileObject.AddComponent<IdealSensor>();
|
||||
interceptorObject.AddComponent<IdealSensor>();
|
||||
break;
|
||||
default:
|
||||
Debug.LogError($"Sensor type '{config.dynamic_config.sensor_config.type}' not found.");
|
||||
break;
|
||||
}
|
||||
|
||||
_interceptors.Add(missileObject.GetComponent<Interceptor>());
|
||||
_activeInterceptors.Add(missileObject.GetComponent<Interceptor>());
|
||||
Interceptor interceptor = interceptorObject.GetComponent<Interceptor>();
|
||||
_interceptorObjects.Add(interceptor);
|
||||
_activeInterceptors.Add(interceptor);
|
||||
|
||||
|
||||
// Subscribe events
|
||||
interceptor.OnInterceptHit += RegisterInterceptorHit;
|
||||
interceptor.OnInterceptMiss += RegisterInterceptorMiss;
|
||||
|
||||
// Assign a unique and simple ID
|
||||
int missileId = _interceptors.Count;
|
||||
missileObject.name = $"{config.interceptor_type}_Interceptor_{missileId}";
|
||||
return missileObject.GetComponent<Interceptor>();
|
||||
int interceptorId = _interceptorObjects.Count;
|
||||
interceptorObject.name = $"{config.interceptor_type}_Interceptor_{interceptorId}";
|
||||
|
||||
// Let listeners know a new interceptor has been created
|
||||
OnNewInterceptor?.Invoke(interceptor);
|
||||
|
||||
return interceptorObject.GetComponent<Interceptor>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -231,23 +211,28 @@ public class SimManager : MonoBehaviour {
|
|||
/// <returns>The created Threat instance, or null if creation failed.</returns>
|
||||
private Threat CreateThreat(AgentConfig config) {
|
||||
string prefabName = config.threat_type switch {
|
||||
ThreatType.DRONE => "Drone", ThreatType.FIXED_WING_MISSILE => "FixedWingMissileThreat",
|
||||
ThreatType.ROLL_STABILIZED_MISSILE => "RollStabilizedMissileThreat",
|
||||
ThreatType.DRONE => "Drone", ThreatType.ANTISHIP_MISSILE => "AntishipMissile",
|
||||
_ => throw new System.ArgumentException($"Unsupported threat type: {config.threat_type}")
|
||||
};
|
||||
GameObject threatObject = CreateAgent(config, prefabName);
|
||||
if (threatObject == null) {
|
||||
Debug.LogError($"Failed to create threat for {prefabName}.");
|
||||
if (threatObject == null)
|
||||
return null;
|
||||
}
|
||||
|
||||
_threats.Add(threatObject.GetComponent<Threat>());
|
||||
_activeThreats.Add(threatObject.GetComponent<Threat>());
|
||||
_unassignedThreats.Add(threatObject.GetComponent<Threat>());
|
||||
|
||||
Threat threat = threatObject.GetComponent<Threat>();
|
||||
// Assign a unique and simple ID
|
||||
int targetId = _threats.Count;
|
||||
int targetId = _threatObjects.Count;
|
||||
threatObject.name = $"{config.threat_type}_Target_{targetId}";
|
||||
|
||||
ThreatData threatData = new ThreatData(threat, threatObject.name);
|
||||
_threatObjects.Add(threat);
|
||||
|
||||
// Subscribe events
|
||||
threat.OnInterceptHit += RegisterThreatHit;
|
||||
threat.OnInterceptMiss += RegisterThreatMiss;
|
||||
|
||||
// Let listeners know a new threat has been created
|
||||
OnNewThreat?.Invoke(threat);
|
||||
|
||||
return threatObject.GetComponent<Threat>();
|
||||
}
|
||||
|
||||
|
@ -297,22 +282,22 @@ public class SimManager : MonoBehaviour {
|
|||
_elapsedSimulationTime = 0f;
|
||||
simulationRunning = IsSimulationRunning();
|
||||
|
||||
// Clear existing missiles and targets
|
||||
foreach (var interceptor in _interceptors) {
|
||||
// Clear existing interceptors and threats
|
||||
foreach (var interceptor in _interceptorObjects) {
|
||||
if (interceptor != null) {
|
||||
Destroy(interceptor.gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var threat in _threats) {
|
||||
foreach (var threat in _threatObjects) {
|
||||
if (threat != null) {
|
||||
Destroy(threat.gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
_interceptors.Clear();
|
||||
_threats.Clear();
|
||||
_unassignedThreats.Clear();
|
||||
_interceptorObjects.Clear();
|
||||
_activeInterceptors.Clear();
|
||||
_threatObjects.Clear();
|
||||
|
||||
StartSimulation();
|
||||
}
|
||||
|
@ -320,8 +305,8 @@ public class SimManager : MonoBehaviour {
|
|||
void Update() {
|
||||
// Check if all missiles have terminated
|
||||
bool allInterceptorsTerminated = true;
|
||||
foreach (var interceptor in _interceptors) {
|
||||
if (interceptor != null && !interceptor.IsHit() && !interceptor.IsMiss()) {
|
||||
foreach (var interceptor in _interceptorObjects) {
|
||||
if (interceptor != null && interceptor.GetFlightPhase() != Agent.FlightPhase.TERMINATED) {
|
||||
allInterceptorsTerminated = false;
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ MonoImporter:
|
|||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
executionOrder: 100
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public class AntishipMissile : MonoBehaviour {
|
||||
// Start is called before the first frame update
|
||||
void Start() {}
|
||||
|
||||
// Update is called once per frame
|
||||
void Update() {}
|
||||
}
|
|
@ -2,7 +2,7 @@ using System.Collections;
|
|||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public class DroneThreat : Threat {
|
||||
public class DroneTarget : Threat {
|
||||
// Start is called before the first frame update
|
||||
protected override void Start() {
|
||||
base.Start();
|
|
@ -1,41 +0,0 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public class FixedWingMissileThreat : Threat {
|
||||
protected override void UpdateBoost(double deltaTime) {
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
protected override void UpdateMidCourse(double deltaTime) {
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Strategy for moving the Threat in a straight path towards its target.
|
||||
/// </summary>
|
||||
public class DirectPathStrategy : NavigationStrategy {
|
||||
public override void Execute(Threat threat, List<Threat> swarmMates, FlightPhase flightPhase,
|
||||
List<Interceptor> interceptors, double deltaTime) {
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Strategy for moving the Threat in an S-curve towards a predefined target.
|
||||
/// </summary>
|
||||
public class SlalomStrategy : NavigationStrategy {
|
||||
private float maxAmplitude;
|
||||
private float periodDistance;
|
||||
|
||||
public SlalomStrategy(float maxAmplitude, float periodDistance) {
|
||||
this.maxAmplitude = maxAmplitude;
|
||||
this.periodDistance = periodDistance;
|
||||
}
|
||||
|
||||
public override void Execute(Threat threat, List<Threat> swarmMates, FlightPhase flightPhase,
|
||||
List<Interceptor> interceptors, double deltaTime) {
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,2 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 4e6c2fbd1e492be448760f5045b13b2e
|
|
@ -1,204 +0,0 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// Base class for missile targets. Uses same set of flight phases as base Hydra-70.
|
||||
/// </summary>
|
||||
public class RollStabilizedMissileThreat : Threat {
|
||||
protected float boostAcceleration = 20;
|
||||
protected float midcourseAcceleration = 0;
|
||||
protected float terminalAcceleration = 22;
|
||||
protected float maxAmplitude = 22;
|
||||
|
||||
public RollStabilizedMissileThreat() {
|
||||
strategy = new DirectPathStrategy();
|
||||
}
|
||||
|
||||
protected override void UpdateBoost(double deltaTime) {
|
||||
// The interceptor only accelerates along its roll axis (forward in Unity)
|
||||
Vector3 rollAxis = transform.forward;
|
||||
|
||||
// Calculate boost acceleration
|
||||
float boostAcceleration =
|
||||
(float)(_staticConfig.boostConfig.boostAcceleration * Constants.kGravity);
|
||||
Vector3 accelerationInput = boostAcceleration * rollAxis;
|
||||
|
||||
// Calculate the total acceleration
|
||||
Vector3 acceleration = CalculateAcceleration(accelerationInput);
|
||||
|
||||
// Apply the acceleration force
|
||||
GetComponent<Rigidbody>().AddForce(acceleration, ForceMode.Acceleration);
|
||||
}
|
||||
|
||||
protected override void UpdateMidCourse(double deltaTime) {
|
||||
Vector3 accelerationInput = Vector3.zero;
|
||||
// Calculate and set the total acceleration
|
||||
Vector3 acceleration = CalculateAcceleration(accelerationInput);
|
||||
GetComponent<Rigidbody>().AddForce(acceleration, ForceMode.Acceleration);
|
||||
}
|
||||
|
||||
protected Vector3 CalculateAcceleration(Vector3 accelerationInput,
|
||||
bool compensateForGravity = false) {
|
||||
Vector3 gravity = Physics.gravity;
|
||||
if (compensateForGravity) {
|
||||
Vector3 gravityProjection = CalculateGravityProjectionOnPitchAndYaw();
|
||||
accelerationInput -= gravityProjection;
|
||||
}
|
||||
|
||||
float airDrag = CalculateDrag();
|
||||
float liftInducedDrag = CalculateLiftInducedDrag(accelerationInput);
|
||||
float dragAcceleration = -(airDrag + liftInducedDrag);
|
||||
|
||||
// Project the drag acceleration onto the forward direction
|
||||
Vector3 dragAccelerationAlongRoll = dragAcceleration * transform.forward;
|
||||
_dragAcceleration = dragAccelerationAlongRoll;
|
||||
|
||||
return accelerationInput + gravity + dragAccelerationAlongRoll;
|
||||
}
|
||||
|
||||
protected float CalculateMaxAcceleration() {
|
||||
float maxReferenceAcceleration =
|
||||
(float)(_staticConfig.accelerationConfig.maxReferenceAcceleration * Constants.kGravity);
|
||||
float referenceSpeed = _staticConfig.accelerationConfig.referenceSpeed;
|
||||
return Mathf.Pow(GetComponent<Rigidbody>().linearVelocity.magnitude / referenceSpeed, 2) *
|
||||
maxReferenceAcceleration;
|
||||
}
|
||||
|
||||
protected Vector3 CalculateGravityProjectionOnPitchAndYaw() {
|
||||
Vector3 gravity = Physics.gravity;
|
||||
Vector3 pitchAxis = transform.right;
|
||||
Vector3 yawAxis = transform.up;
|
||||
|
||||
// Project the gravity onto the pitch and yaw axes
|
||||
float gravityProjectionPitchCoefficient = Vector3.Dot(gravity, pitchAxis);
|
||||
float gravityProjectionYawCoefficient = Vector3.Dot(gravity, yawAxis);
|
||||
|
||||
// Return the sum of the projections
|
||||
return gravityProjectionPitchCoefficient * pitchAxis +
|
||||
gravityProjectionYawCoefficient * yawAxis;
|
||||
}
|
||||
|
||||
private float CalculateDrag() {
|
||||
float dragCoefficient = _staticConfig.liftDragConfig.dragCoefficient;
|
||||
float crossSectionalArea = _staticConfig.bodyConfig.crossSectionalArea;
|
||||
float mass = _staticConfig.bodyConfig.mass;
|
||||
float dynamicPressure = (float)GetDynamicPressure();
|
||||
float dragForce = dragCoefficient * dynamicPressure * crossSectionalArea;
|
||||
return dragForce / mass;
|
||||
}
|
||||
|
||||
private float CalculateLiftInducedDrag(Vector3 accelerationInput) {
|
||||
float liftAcceleration =
|
||||
(accelerationInput - Vector3.Dot(accelerationInput, transform.up) * transform.up).magnitude;
|
||||
float liftDragRatio = _staticConfig.liftDragConfig.liftDragRatio;
|
||||
return Mathf.Abs(liftAcceleration / liftDragRatio);
|
||||
}
|
||||
|
||||
// ===========================================================
|
||||
// STRATEGIES
|
||||
// ===========================================================
|
||||
|
||||
/// <summary>
|
||||
/// Strategy for moving the Threat in a straight path towards its target.
|
||||
/// </summary>
|
||||
public class DirectPathStrategy : NavigationStrategy {
|
||||
DefendPoint target = new DefendPoint();
|
||||
|
||||
private float _navigationGain = 3f; // Typically 3-5
|
||||
private SensorOutput _sensorOutput;
|
||||
private Vector3 _accelerationCommand;
|
||||
private double _elapsedTime = 0;
|
||||
|
||||
public override void Execute(Threat threat, List<Threat> swarmMates, FlightPhase flightPhase,
|
||||
List<Interceptor> interceptors, double deltaTime) {
|
||||
RollStabilizedMissileThreat missileThreat = threat as RollStabilizedMissileThreat;
|
||||
if (missileThreat == null) {
|
||||
Debug.LogError("DirectPathStrategy can only be used with RollStabilizedMissileThreat");
|
||||
return;
|
||||
}
|
||||
|
||||
_elapsedTime += deltaTime;
|
||||
Vector3 accelerationInput = Vector3.zero;
|
||||
|
||||
if (target != null) {
|
||||
// Correct the state of the threat model at the sensor frequency
|
||||
float sensorUpdatePeriod =
|
||||
1f / missileThreat._agentConfig.dynamic_config.sensor_config.frequency;
|
||||
if (_elapsedTime >= sensorUpdatePeriod) {
|
||||
_sensorOutput = new SensorOutput();
|
||||
missileThreat.GetComponent<Sensor>().Sense(target);
|
||||
Debug.Log(_sensorOutput.velocity.range);
|
||||
_elapsedTime = 0;
|
||||
}
|
||||
|
||||
// Check whether the threat should be considered a miss
|
||||
SensorOutput sensorOutput = missileThreat.GetComponent<Sensor>().Sense(target);
|
||||
if (sensorOutput.velocity.range > 1000f) {
|
||||
missileThreat.MarkAsMiss();
|
||||
}
|
||||
|
||||
// Calculate the acceleration input
|
||||
accelerationInput = CalculateAccelerationCommand(missileThreat, _sensorOutput);
|
||||
} else {
|
||||
Debug.LogError("DirectPathStrategy requires a target to be set");
|
||||
}
|
||||
|
||||
// Calculate and set the total acceleration
|
||||
Vector3 acceleration =
|
||||
missileThreat.CalculateAcceleration(accelerationInput, compensateForGravity: true);
|
||||
missileThreat.GetComponent<Rigidbody>().AddForce(acceleration, ForceMode.Acceleration);
|
||||
}
|
||||
|
||||
private Vector3 CalculateAccelerationCommand(Threat threat, SensorOutput sensorOutput) {
|
||||
RollStabilizedMissileThreat missileThreat = threat as RollStabilizedMissileThreat;
|
||||
|
||||
// Implement Proportional Navigation guidance law
|
||||
Vector3 accelerationCommand;
|
||||
|
||||
// Extract relevant information from sensor output
|
||||
float los_rate_az = sensorOutput.velocity.azimuth;
|
||||
float los_rate_el = sensorOutput.velocity.elevation;
|
||||
float closing_velocity =
|
||||
-sensorOutput.velocity
|
||||
.range; // Negative because closing velocity is opposite to range rate
|
||||
|
||||
// Navigation gain (adjust as needed)
|
||||
float N = _navigationGain;
|
||||
|
||||
// Calculate acceleration commands in azimuth and elevation planes
|
||||
float acc_az = N * closing_velocity * los_rate_az;
|
||||
float acc_el = N * closing_velocity * los_rate_el;
|
||||
|
||||
// Convert acceleration commands to craft body frame
|
||||
accelerationCommand =
|
||||
missileThreat.transform.right * acc_az + missileThreat.transform.up * acc_el;
|
||||
|
||||
// Clamp the acceleration command to the maximum acceleration
|
||||
float maxAcceleration = missileThreat.CalculateMaxAcceleration();
|
||||
accelerationCommand = Vector3.ClampMagnitude(accelerationCommand, maxAcceleration);
|
||||
|
||||
// Update the stored acceleration command for debugging
|
||||
_accelerationCommand = accelerationCommand;
|
||||
return accelerationCommand;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Strategy for moving the Threat in a spiral towards a predefined target.
|
||||
/// </summary>
|
||||
public class SpiralStrategy : NavigationStrategy {
|
||||
private float spiralRadius;
|
||||
private float periodDistance;
|
||||
|
||||
public SpiralStrategy(float spiralRadius, float periodDistance) {
|
||||
this.spiralRadius = spiralRadius;
|
||||
this.periodDistance = periodDistance;
|
||||
}
|
||||
|
||||
public override void Execute(Threat threat, List<Threat> swarmMates, FlightPhase flightPhase,
|
||||
List<Interceptor> interceptors, double deltaTime) {
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,29 +3,6 @@ using System.Collections.Generic;
|
|||
using UnityEngine;
|
||||
|
||||
public abstract class Threat : Agent {
|
||||
/// <summary>
|
||||
/// Strategy for moving the Threat towards a predefined target.
|
||||
/// </summary>
|
||||
public abstract class NavigationStrategy {
|
||||
/// <summary>
|
||||
/// Execute one timestep of the strategy for the given threat and flight phase. Should only
|
||||
/// apply normal forces to the threat. Can also change the threat's flight phase. Should NOT
|
||||
/// manage thrust.
|
||||
/// </summary>
|
||||
/// <param name="threat">Parent Threat object</param>
|
||||
/// <param name="swarmMates">List of other threats in the swarm</param>
|
||||
/// <param name="flightPhase">Current flight phase</param>
|
||||
/// <param name="interceptors">List of active interceptors</param>
|
||||
/// <param name="deltaTime">Timestep</param>
|
||||
public abstract void Execute(Threat threat, List<Threat> swarmMates, FlightPhase flightPhase,
|
||||
List<Interceptor> interceptors, double deltaTime);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Navigation strategy that this threat will use to move towards its target.
|
||||
/// </summary>
|
||||
public NavigationStrategy strategy;
|
||||
|
||||
public override bool IsAssignable() {
|
||||
return false;
|
||||
}
|
||||
|
@ -36,18 +13,5 @@ public abstract class Threat : Agent {
|
|||
|
||||
protected override void FixedUpdate() {
|
||||
base.FixedUpdate();
|
||||
// NOTE: no swarm-mates for now
|
||||
strategy.Execute(this, new List<Threat>(), GetFlightPhase(),
|
||||
SimManager.Instance.GetActiveInterceptors(), Time.fixedDeltaTime);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// OVERRIDE: THIS SHOULD NEVER BE CALLED; threats always start in midcourse or (at the very
|
||||
/// earliest) boost phase.
|
||||
/// </summary>
|
||||
/// <param name="deltaTime"></param>
|
||||
/// <exception cref="System.NotImplementedException"></exception>
|
||||
protected override void UpdateReady(double deltaTime) {
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"name": "bamlab.micromissiles",
|
||||
"rootNamespace": "",
|
||||
"references": [
|
||||
"GUID:6055be8ebefd69e48b49212b09b47b2f",
|
||||
"GUID:c668b7a00ffe56a498ddb1fc9f96f4e6"
|
||||
],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": false
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
fileFormatVersion: 2
|
||||
guid: a4172237088e66b4190f0126eef67443
|
||||
PrefabImporter:
|
||||
guid: af8bba08a36038347823e2f46bdc9857
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
|
@ -1,146 +0,0 @@
|
|||
{
|
||||
"timeScale": 1,
|
||||
"interceptor_swarm_configs": [
|
||||
{
|
||||
"num_agents": 1,
|
||||
"agent_config": {
|
||||
"interceptor_type": "HYDRA_70",
|
||||
"threat_type": "ROLL_STABILIZED_MISSILE",
|
||||
"initial_state": {
|
||||
"position": {
|
||||
"x": 0,
|
||||
"y": 20,
|
||||
"z": 0
|
||||
},
|
||||
"rotation": {
|
||||
"x": -45,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"velocity": {
|
||||
"x": 0,
|
||||
"y": 10,
|
||||
"z": 10
|
||||
}
|
||||
},
|
||||
"standard_deviation": {
|
||||
"position": {
|
||||
"x": 10,
|
||||
"y": 0,
|
||||
"z": 10
|
||||
},
|
||||
"velocity": {
|
||||
"x": 5,
|
||||
"y": 0,
|
||||
"z": 1
|
||||
}
|
||||
},
|
||||
"dynamic_config": {
|
||||
"launch_config": {
|
||||
"launch_time": 0
|
||||
},
|
||||
"sensor_config": {
|
||||
"type": "IDEAL",
|
||||
"frequency": 100
|
||||
}
|
||||
},
|
||||
"submunitions_config": {
|
||||
"num_submunitions": 7,
|
||||
"launch_config": {
|
||||
"launch_time": 4
|
||||
},
|
||||
"agent_config": {
|
||||
"interceptor_type": "MICROMISSILE",
|
||||
"initial_state": {
|
||||
"position": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"rotation": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"velocity": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
}
|
||||
},
|
||||
"standard_deviation": {
|
||||
"position": {
|
||||
"x": 5,
|
||||
"y": 5,
|
||||
"z": 5
|
||||
},
|
||||
"velocity": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
}
|
||||
},
|
||||
"dynamic_config": {
|
||||
"launch_config": {
|
||||
"launch_time": 0
|
||||
},
|
||||
"sensor_config": {
|
||||
"type": "IDEAL",
|
||||
"frequency": 100
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"threat_swarm_configs": [
|
||||
{
|
||||
"num_agents": 7,
|
||||
"agent_config": {
|
||||
"threat_type": "ROLL_STABILIZED_MISSILE",
|
||||
"initial_state": {
|
||||
"position": {
|
||||
"x": 0,
|
||||
"y": 600,
|
||||
"z": 6000
|
||||
},
|
||||
"rotation": {
|
||||
"x": 90,
|
||||
"y": 50,
|
||||
"z": 0
|
||||
},
|
||||
"velocity": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": -200
|
||||
}
|
||||
},
|
||||
"standard_deviation": {
|
||||
"position": {
|
||||
"x": 1000,
|
||||
"y": 200,
|
||||
"z": 100
|
||||
},
|
||||
"velocity": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 25
|
||||
}
|
||||
},
|
||||
"dynamic_config": {
|
||||
"launch_config": {
|
||||
"launch_time": 0
|
||||
},
|
||||
"sensor_config": {
|
||||
"type": "IDEAL",
|
||||
"frequency": 0
|
||||
}
|
||||
},
|
||||
"submunitions_config": {
|
||||
"num_submunitions": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
{
|
||||
"accelerationConfig": {
|
||||
"maxReferenceAcceleration": 300,
|
||||
"referenceSpeed": 1000
|
||||
},
|
||||
"boostConfig": {
|
||||
"boostTime": 0.3,
|
||||
"boostAcceleration": 350
|
||||
},
|
||||
"liftDragConfig": {
|
||||
"liftCoefficient": 0.2,
|
||||
"dragCoefficient": 0.7,
|
||||
"liftDragRatio": 5
|
||||
},
|
||||
"bodyConfig": {
|
||||
"mass": 0.37,
|
||||
"crossSectionalArea": 0.0003,
|
||||
"finArea": 0.0006,
|
||||
"bodyArea": 0.01
|
||||
},
|
||||
"hitConfig": {
|
||||
"hitRadius": 1,
|
||||
"killProbability": 0.9
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 5ab47dc725c65cb4cb1fa6948fb0c9a7
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: c80e4daffe8e47e4b8e151adf0b21a86
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,25 @@
|
|||
using NUnit.Framework;
|
||||
using UnityEngine;
|
||||
using UnityEngine.TestTools;
|
||||
using System.Collections;
|
||||
|
||||
public class SanityTest
|
||||
{
|
||||
[Test]
|
||||
public void SanityTestSimplePasses()
|
||||
{
|
||||
// Use the Assert class to test conditions
|
||||
Assert.Pass("This test passes.");
|
||||
}
|
||||
|
||||
// A UnityTest behaves like a coroutine in Play Mode. In Edit Mode you can use
|
||||
// `yield return null;` to skip a frame.
|
||||
[UnityTest]
|
||||
public IEnumerator SanityTestWithEnumeratorPasses()
|
||||
{
|
||||
// Use the Assert class to test conditions.
|
||||
// Use yield to skip a frame.
|
||||
yield return null;
|
||||
Assert.Pass("This test passes after skipping a frame.");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
fileFormatVersion: 2
|
||||
guid: b48cf6e434723a449a49186eeda32d3f
|
|
@ -0,0 +1,138 @@
|
|||
using NUnit.Framework;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.TestTools;
|
||||
using System.Linq;
|
||||
|
||||
public class ThreatAssignmentTests
|
||||
{
|
||||
[Test]
|
||||
public void Assign_Should_Assign_All_Interceptors_And_Threats()
|
||||
{
|
||||
// Arrange
|
||||
ThreatAssignment threatAssignment = new ThreatAssignment();
|
||||
|
||||
// Create interceptors
|
||||
List<Interceptor> interceptors = new List<Interceptor>
|
||||
{
|
||||
new GameObject("Interceptor 1").AddComponent<Micromissile>(),
|
||||
new GameObject("Interceptor 2").AddComponent<Micromissile>(),
|
||||
new GameObject("Interceptor 3").AddComponent<Micromissile>()
|
||||
};
|
||||
|
||||
// Create threats
|
||||
Threat threat1 = new GameObject("Threat 1").AddComponent<DroneTarget>();
|
||||
Threat threat2 = new GameObject("Threat 2").AddComponent<DroneTarget>();
|
||||
Threat threat3 = new GameObject("Threat 3").AddComponent<DroneTarget>();
|
||||
|
||||
// Add Rigidbody components to threats to set velocities
|
||||
Rigidbody rb1 = threat1.gameObject.AddComponent<Rigidbody>();
|
||||
Rigidbody rb2 = threat2.gameObject.AddComponent<Rigidbody>();
|
||||
Rigidbody rb3 = threat3.gameObject.AddComponent<Rigidbody>();
|
||||
|
||||
// Set positions and velocities
|
||||
threat1.transform.position = Vector3.forward * -20f;
|
||||
threat2.transform.position = Vector3.forward * -20f;
|
||||
threat3.transform.position = Vector3.forward * -20f;
|
||||
|
||||
rb1.linearVelocity = Vector3.forward * 5f;
|
||||
rb2.linearVelocity = Vector3.forward * 10f;
|
||||
rb3.linearVelocity = Vector3.forward * 15f;
|
||||
|
||||
// Create threat data
|
||||
List<ThreatData> threats = new List<ThreatData>
|
||||
{
|
||||
new ThreatData(threat1, "Threat1ID"),
|
||||
new ThreatData(threat2, "Threat2ID"),
|
||||
new ThreatData(threat3, "Threat3ID")
|
||||
};
|
||||
|
||||
// Act
|
||||
IEnumerable<IAssignment.AssignmentItem> assignments = threatAssignment.Assign(interceptors, threats);
|
||||
|
||||
// Assert
|
||||
Assert.AreEqual(3, assignments.Count(), "All interceptors should be assigned");
|
||||
|
||||
HashSet<Interceptor> assignedInterceptors = new HashSet<Interceptor>();
|
||||
HashSet<Threat> assignedThreats = new HashSet<Threat>();
|
||||
|
||||
foreach (var assignment in assignments)
|
||||
{
|
||||
Assert.IsNotNull(assignment.Interceptor, "Interceptor should not be null");
|
||||
Assert.IsNotNull(assignment.Threat, "Threat should not be null");
|
||||
assignedInterceptors.Add(assignment.Interceptor);
|
||||
assignedThreats.Add(assignment.Threat);
|
||||
}
|
||||
|
||||
Assert.AreEqual(3, assignedInterceptors.Count, "All interceptors should be unique");
|
||||
Assert.AreEqual(3, assignedThreats.Count, "All threats should be assigned");
|
||||
|
||||
// Verify that threats are assigned in order of their threat level (based on velocity and distance)
|
||||
var orderedAssignments = assignments.OrderByDescending(a => a.Threat.GetVelocity().magnitude / Vector3.Distance(a.Threat.transform.position, Vector3.zero)).ToList();
|
||||
Assert.AreEqual(threat3, orderedAssignments[0].Threat, "Highest threat should be assigned first");
|
||||
Assert.AreEqual(threat2, orderedAssignments[1].Threat, "Second highest threat should be assigned second");
|
||||
Assert.AreEqual(threat1, orderedAssignments[2].Threat, "Lowest threat should be assigned last");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Assign_Should_Handle_More_Interceptors_Than_Threats()
|
||||
{
|
||||
// Arrange
|
||||
ThreatAssignment threatAssignment = new ThreatAssignment();
|
||||
|
||||
// Create interceptors
|
||||
List<Interceptor> interceptors = new List<Interceptor>
|
||||
{
|
||||
new GameObject("Interceptor 1").AddComponent<Micromissile>(),
|
||||
new GameObject("Interceptor 2").AddComponent<Micromissile>(),
|
||||
new GameObject("Interceptor 3").AddComponent<Micromissile>()
|
||||
};
|
||||
|
||||
// Create threats
|
||||
Threat threat1 = new GameObject("Threat 1").AddComponent<DroneTarget>();
|
||||
Threat threat2 = new GameObject("Threat 2").AddComponent<DroneTarget>();
|
||||
|
||||
// Add Rigidbody components to threats to set velocities
|
||||
Rigidbody rb1 = threat1.gameObject.AddComponent<Rigidbody>();
|
||||
Rigidbody rb2 = threat2.gameObject.AddComponent<Rigidbody>();
|
||||
|
||||
// Set positions and velocities
|
||||
threat1.transform.position = Vector3.up * 10f;
|
||||
threat2.transform.position = Vector3.right * 5f;
|
||||
|
||||
rb1.linearVelocity = Vector3.forward * 10f;
|
||||
rb2.linearVelocity = Vector3.forward * 15f;
|
||||
|
||||
// Create threat data
|
||||
List<ThreatData> threats = new List<ThreatData>
|
||||
{
|
||||
new ThreatData(threat1, "Threat1ID"),
|
||||
new ThreatData(threat2, "Threat2ID")
|
||||
};
|
||||
|
||||
// Act
|
||||
IEnumerable<IAssignment.AssignmentItem> assignments = threatAssignment.Assign(interceptors, threats);
|
||||
|
||||
// Assert
|
||||
Assert.AreEqual(2, assignments.Count(), "All threats should be assigned");
|
||||
|
||||
HashSet<Interceptor> assignedInterceptors = new HashSet<Interceptor>();
|
||||
HashSet<Threat> assignedThreats = new HashSet<Threat>();
|
||||
|
||||
foreach (var assignment in assignments)
|
||||
{
|
||||
Assert.IsNotNull(assignment.Interceptor, "Interceptor should not be null");
|
||||
Assert.IsNotNull(assignment.Threat, "Threat should not be null");
|
||||
assignedInterceptors.Add(assignment.Interceptor);
|
||||
assignedThreats.Add(assignment.Threat);
|
||||
}
|
||||
|
||||
Assert.AreEqual(2, assignedInterceptors.Count, "Two interceptors should be assigned");
|
||||
Assert.AreEqual(2, assignedThreats.Count, "Both threats should be assigned");
|
||||
|
||||
// Verify that threats are assigned in order of their threat level (based on velocity and distance)
|
||||
var orderedAssignments = assignments.OrderByDescending(a => a.Threat.GetVelocity().magnitude / Vector3.Distance(a.Threat.transform.position, Vector3.zero)).ToList();
|
||||
Assert.AreEqual(threat2, orderedAssignments[0].Threat, "Higher threat should be assigned first");
|
||||
Assert.AreEqual(threat1, orderedAssignments[1].Threat, "Lower threat should be assigned second");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 7ddf271569a78ee4e995192d4df0ef3f
|
|
@ -0,0 +1,24 @@
|
|||
{
|
||||
"name": "bamlab.test.editmode",
|
||||
"rootNamespace": "",
|
||||
"references": [
|
||||
"UnityEngine.TestRunner",
|
||||
"UnityEditor.TestRunner",
|
||||
"bamlab.micromissiles"
|
||||
],
|
||||
"includePlatforms": [
|
||||
"Editor"
|
||||
],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": true,
|
||||
"precompiledReferences": [
|
||||
"nunit.framework.dll"
|
||||
],
|
||||
"autoReferenced": false,
|
||||
"defineConstraints": [
|
||||
"UNITY_INCLUDE_TESTS"
|
||||
],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": false
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 9c1ccc1cc7ad8cb4aa0b59a0afd50568
|
||||
PrefabImporter:
|
||||
guid: d15c92e585e721749b63d85007276dbe
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: fb45bee6d70202941a0bab2fe23f0ffb
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,25 @@
|
|||
using System.Collections;
|
||||
using NUnit.Framework;
|
||||
using UnityEngine;
|
||||
using UnityEngine.TestTools;
|
||||
|
||||
public class SanityTest
|
||||
{
|
||||
[UnityTest]
|
||||
public IEnumerator SanityCheck()
|
||||
{
|
||||
// Arrange
|
||||
GameObject testObject = new GameObject("TestObject");
|
||||
|
||||
// Act
|
||||
testObject.AddComponent<BoxCollider>();
|
||||
|
||||
// Assert
|
||||
Assert.IsTrue(testObject.GetComponent<BoxCollider>() != null, "BoxCollider should be added to the test object");
|
||||
|
||||
// Clean up
|
||||
Object.Destroy(testObject);
|
||||
|
||||
yield return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 2e04183212e40bf43a2625427494a839
|
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"name": "bamlab.test.playmode",
|
||||
"rootNamespace": "",
|
||||
"references": [
|
||||
"UnityEngine.TestRunner",
|
||||
"UnityEditor.TestRunner",
|
||||
"bamlab.micromissiles"
|
||||
],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": true,
|
||||
"precompiledReferences": [
|
||||
"nunit.framework.dll"
|
||||
],
|
||||
"autoReferenced": false,
|
||||
"defineConstraints": [
|
||||
"UNITY_INCLUDE_TESTS"
|
||||
],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": false
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
fileFormatVersion: 2
|
||||
guid: e06647a307e3eb742b52b0482094df98
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -55,7 +55,18 @@ MonoBehaviour:
|
|||
- rid: 162646946419048467
|
||||
- rid: 162646946419048468
|
||||
m_RuntimeSettings:
|
||||
m_List: []
|
||||
m_List:
|
||||
- rid: 162646946419048448
|
||||
- rid: 162646946419048450
|
||||
- rid: 162646946419048451
|
||||
- rid: 162646946419048453
|
||||
- rid: 162646946419048455
|
||||
- rid: 162646946419048457
|
||||
- rid: 162646946419048458
|
||||
- rid: 162646946419048460
|
||||
- rid: 162646946419048461
|
||||
- rid: 162646946419048465
|
||||
- rid: 162646946419048468
|
||||
m_AssetVersion: 8
|
||||
m_ObsoleteDefaultVolumeProfile: {fileID: 0}
|
||||
m_RenderingLayerNames:
|
||||
|
|
|
@ -1,5 +1,26 @@
|
|||
{
|
||||
"m_Dictionary": {
|
||||
"m_DictionaryValues": []
|
||||
"m_DictionaryValues": [
|
||||
{
|
||||
"type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
|
||||
"key": "IncludeAssemblies",
|
||||
"value": "{\"m_Value\":\"bamlab.micromissiles,bamlab.test\"}"
|
||||
},
|
||||
{
|
||||
"type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
|
||||
"key": "Path",
|
||||
"value": "{\"m_Value\":\"{ProjectPath}\"}"
|
||||
},
|
||||
{
|
||||
"type": "System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
|
||||
"key": "HistoryPath",
|
||||
"value": "{\"m_Value\":\"{ProjectPath}\"}"
|
||||
},
|
||||
{
|
||||
"type": "System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
|
||||
"key": "EnableCodeCoverage",
|
||||
"value": "{\"m_Value\":true}"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
|
@ -61,6 +61,11 @@
|
|||
"type": "UnityEngine.PhysicMaterial",
|
||||
"defaultInstantiationMode": 0
|
||||
},
|
||||
{
|
||||
"userAdded": false,
|
||||
"type": "UnityEngine.PhysicsMaterial",
|
||||
"defaultInstantiationMode": 0
|
||||
},
|
||||
{
|
||||
"userAdded": false,
|
||||
"type": "UnityEngine.PhysicsMaterial2D",
|
||||
|
|
101
README.md
101
README.md
|
@ -2,6 +2,15 @@
|
|||
|
||||
![Sim Salvo Animation](docs/images/sim_salvo_animation.gif)
|
||||
|
||||
[![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/PisterLab/micromissiles-unity/build.yaml?link=https%3A%2F%2Fgithub.com%2FPisterLab%2Fmicromissiles-unity%2Factions%2Fworkflows%2Fbuild.yaml)](https://github.com/PisterLab/micromissiles-unity/actions/workflows/build.yaml)
|
||||
[![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/PisterLab/micromissiles-unity/test.yaml?label=tests&link=https%3A%2F%2Fgithub.com%2FPisterLab%2Fmicromissiles-unity%2Factions%2Fworkflows%2Ftest.yaml)](https://github.com/PisterLab/micromissiles-unity/actions/workflows/test.yaml)
|
||||
[![GitHub Release](https://img.shields.io/github/v/release/PisterLab/micromissiles-unity?link=https%3A%2F%2Fgithub.com%2FPisterLab%2Fmicromissiles-unity%2Freleases%2Flatest)](https://github.com/PisterLab/micromissiles-unity/releases/latest)
|
||||
[![Static Badge](https://img.shields.io/badge/%F0%9F%93%93-Documentation-blue?labelColor=white)](https://pisterlab.github.io/micromissiles-unity/)
|
||||
|
||||
# Documentation
|
||||
|
||||
Documentation is hosted on the [micromissiles-unity GitHub Pages site](https://pisterlab.github.io/micromissiles-unity/).
|
||||
|
||||
# Quick Start
|
||||
|
||||
We generate pre-built standalone binaries for Windows and Mac users from the `release` branch. These binaries are intended for non-development users who just want to run the application and modify a few configurations along the way.
|
||||
|
@ -24,91 +33,9 @@ You can find the latest release [here](https://github.com/PisterLab/micromissile
|
|||
* Navigate to `Privacy & Security`.
|
||||
* Click on `Open Anyway` to bypass Apple's developer check.
|
||||
|
||||
# Development
|
||||
# Next Steps
|
||||
|
||||
This guide will help you set up and run the project in development mode. You'll learn how to install Unity Hub, open the project, and navigate the main scene.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [Prerequisites](#prerequisites)
|
||||
- [Installation Steps](#installation-steps)
|
||||
- [1. Install Unity Hub](#1-install-unity-hub)
|
||||
- [2. Clone the Project Repository](#2-clone-the-project-repository)
|
||||
- [3. Launch the Project via Unity Hub](#3-launch-the-project-via-unity-hub)
|
||||
- [4. Open the Main Scene](#4-open-the-main-scene)
|
||||
- [Next Steps](#next-steps)
|
||||
- [Additional Resources](#additional-resources)
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- A computer with internet access.
|
||||
- Administrative privileges to install software.
|
||||
- [Git](https://git-scm.com/downloads) installed on your system (optional, for cloning the repository).
|
||||
|
||||
## Installation Steps
|
||||
|
||||
### 1. Install Unity Hub
|
||||
|
||||
Unity Hub is a desktop application that manages your Unity projects and installations. It simplifies the process of installing different Unity versions and launching projects.
|
||||
|
||||
**Steps to Install Unity Hub:**
|
||||
|
||||
1. Visit the [Unity Download Page](https://unity3d.com/get-unity/download).
|
||||
2. Click on **"Download Unity Hub"**.
|
||||
3. Run the downloaded installer and follow the on-screen instructions to complete the installation.
|
||||
|
||||
### 2. Clone the Project Repository
|
||||
|
||||
Obtain the project source code by cloning the repository from GitHub.
|
||||
|
||||
```bash
|
||||
git clone https://github.com/PisterLab/micromissiles-unity.git
|
||||
```
|
||||
Alternatively, you can download the repository as a ZIP file and extract it to a preferred location.
|
||||
|
||||
### 3. Launch the Project via Unity Hub
|
||||
|
||||
![Unity Hub](docs/images/unity_hub.png)
|
||||
|
||||
1. **Open Unity Hub**.
|
||||
|
||||
2. **Add the Project to Unity Hub**:
|
||||
- Navigate to the **"Projects"** tab.
|
||||
- Click on the **"ADD"** button.
|
||||
- Browse to the folder where you cloned or extracted the project.
|
||||
- Select the folder containing the `Assets` folder and click on **"Select Folder"**.
|
||||
|
||||
3. **Install the Required Unity Version**:
|
||||
- Unity Hub will detect if the project requires a Unity version that is not currently installed.
|
||||
- A notification or warning icon may appear next to the project name.
|
||||
- Click on the notification and select **"Install Unity **[version]**"**.
|
||||
- Unity Hub will download and install the required Unity version automatically.
|
||||
|
||||
4. **Open the Project**:
|
||||
- Once the required Unity version is installed, click on the project name in Unity Hub to open it.
|
||||
|
||||
### 4. Open the Main Scene
|
||||
|
||||
After the project opens in Unity:
|
||||
|
||||
1. In the **Project** window (usually located at the bottom), navigate to:
|
||||
|
||||
```
|
||||
Assets/Scenes/
|
||||
```
|
||||
|
||||
2. Find the main scene file, usually named `MainScene.unity`.
|
||||
|
||||
3. Double-click on `MainScene.unity` to open it.
|
||||
|
||||
4. The scene will load in the **Scene** view. You can now run the simulation by clicking the **Play** button at the top of the Unity Editor.
|
||||
|
||||
## Next Steps
|
||||
|
||||
- Familiarize yourself with the [**Keybinds and Controls**](docs/Keybinds_and_Controls.md) to navigate and interact with the simulation.
|
||||
- Learn how to configure the simulation settings by reading the [**Simulation Configuration Guide**](docs/Simulation_Config_Guide.md).
|
||||
|
||||
## Additional Resources
|
||||
|
||||
- [Keybinds and Controls](docs/Keybinds_and_Controls.md)
|
||||
- [Simulation Configuration Guide](docs/Simulation_Config_Guide.md)
|
||||
- To get started with development, see the [**Development Guide**](https://pisterlab.github.io/micromissiles-unity/Development_Guide.html).
|
||||
- Familiarize yourself with the [**Keybinds and Controls**](https://pisterlab.github.io/micromissiles-unity/Keybinds_and_Controls.html) to navigate and interact with the simulation.
|
||||
- Learn how to configure the simulation settings by reading the [**Simulation Configuration Guide**](https://pisterlab.github.io/micromissiles-unity/Simulation_Config_Guide.html).
|
||||
- Learn how to analyze the simulation logs by reading the [**Simulation Logging Guide**](https://pisterlab.github.io/micromissiles-unity/Simulation_Logging.html).
|
|
@ -1,82 +0,0 @@
|
|||
import os
|
||||
import glob
|
||||
import argparse
|
||||
import pandas as pd
|
||||
import matplotlib.pyplot as plt
|
||||
from mpl_toolkits.mplot3d import Axes3D
|
||||
import numpy as np
|
||||
|
||||
def find_latest_telemetry_file(directory='./Logs/'):
|
||||
list_of_files = glob.glob(os.path.join(directory, 'sim_telemetry_*.csv'))
|
||||
if not list_of_files:
|
||||
print(f"No telemetry files found in {directory}")
|
||||
return None
|
||||
latest_file = max(list_of_files, key=os.path.getctime)
|
||||
print(f"Using latest telemetry file: {latest_file}")
|
||||
return latest_file
|
||||
|
||||
def plot_telemetry(file_path):
|
||||
# Read the telemetry CSV file
|
||||
df = pd.read_csv(file_path)
|
||||
|
||||
|
||||
# Create a 3D plot
|
||||
fig = plt.figure(figsize=(12, 8))
|
||||
ax = fig.add_subplot(111, projection='3d')
|
||||
|
||||
# Define colors for different agent types
|
||||
colors = {'T': 'red', 'M': 'blue'}
|
||||
|
||||
# Group data by AgentID
|
||||
for agent_id, agent_data in df.groupby('AgentID'):
|
||||
agent_type = agent_data['AgentType'].iloc[0]
|
||||
color = colors.get(agent_type, 'black')
|
||||
downsampled = agent_data.iloc[::10]
|
||||
|
||||
ax.plot(
|
||||
downsampled['AgentX'],
|
||||
downsampled['AgentZ'],
|
||||
downsampled['AgentY'],
|
||||
color=color,
|
||||
alpha=0.5,
|
||||
linewidth=0.5,
|
||||
label=f"{agent_type}"
|
||||
)
|
||||
|
||||
|
||||
ax.set_xlabel('X (m)')
|
||||
ax.set_ylabel('Z (m)')
|
||||
ax.set_zlabel('Y (m)')
|
||||
|
||||
|
||||
ax.view_init(elev=20, azim=45)
|
||||
|
||||
# Add a ground plane
|
||||
x_min, x_max = ax.get_xlim()
|
||||
z_min, z_max = ax.get_ylim()
|
||||
xx, zz = np.meshgrid(np.linspace(x_min, x_max, 2), np.linspace(z_min, z_max, 2))
|
||||
yy = np.zeros_like(xx)
|
||||
ax.plot_surface(xx, zz, yy, alpha=0.2, color='green')
|
||||
|
||||
plt.title('Agents Trajectories (X: Right, Z: Forward, Y: Up)')
|
||||
legend = [
|
||||
plt.Line2D([0], [0], color='red', lw=2, label='Threat'),
|
||||
plt.Line2D([0], [0], color='blue', lw=2, label='Interceptor')
|
||||
]
|
||||
plt.legend(handles=legend)
|
||||
plt.tight_layout()
|
||||
plt.show()
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(description='Visualize telemetry data.')
|
||||
parser.add_argument('file', nargs='?', default=None, help='Path to telemetry CSV file.')
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.file:
|
||||
file_path = args.file
|
||||
else:
|
||||
file_path = find_latest_telemetry_file()
|
||||
if file_path is None:
|
||||
exit(1)
|
||||
|
||||
plot_telemetry(file_path)
|
|
@ -0,0 +1,198 @@
|
|||
import os
|
||||
import glob
|
||||
import argparse
|
||||
import platform
|
||||
import pandas as pd
|
||||
import matplotlib.pyplot as plt
|
||||
from mpl_toolkits.mplot3d import Axes3D
|
||||
import numpy as np
|
||||
|
||||
|
||||
|
||||
def get_logs_directory():
|
||||
if platform.system() == "Windows":
|
||||
return os.path.expandvars(r"%USERPROFILE%\AppData\LocalLow\BAMLAB\micromissiles\Telemetry\Logs")
|
||||
elif platform.system() == "Darwin": # macOS
|
||||
return os.path.expanduser("~/Library/Application Support/BAMLAB/micromissiles/Telemetry/Logs")
|
||||
else:
|
||||
raise NotImplementedError(f"Unsupported platform: {platform.system()}")
|
||||
|
||||
def find_latest_file(directory, file_pattern):
|
||||
list_of_files = glob.glob(os.path.join(directory, file_pattern))
|
||||
if not list_of_files:
|
||||
print(f"No files matching '{file_pattern}' found in {directory}")
|
||||
return None
|
||||
latest_file = max(list_of_files, key=os.path.getctime)
|
||||
print(f"Using latest file: {latest_file}")
|
||||
return latest_file
|
||||
|
||||
def find_latest_telemetry_file():
|
||||
logs_dir = get_logs_directory()
|
||||
latest_log_dir = max(glob.glob(os.path.join(logs_dir, "*")), key=os.path.getctime)
|
||||
return find_latest_file(latest_log_dir, 'sim_telemetry_*.csv')
|
||||
|
||||
def find_latest_event_log():
|
||||
latest_telemetry_file = find_latest_telemetry_file()
|
||||
if latest_telemetry_file:
|
||||
return latest_telemetry_file.replace('sim_telemetry_', 'sim_events_')
|
||||
else:
|
||||
return None
|
||||
|
||||
def plot_telemetry(telemetry_file_path, event_file_path):
|
||||
# Read the telemetry CSV file
|
||||
df = pd.read_csv(telemetry_file_path)
|
||||
|
||||
# Read the event CSV file
|
||||
event_df = pd.read_csv(event_file_path)
|
||||
|
||||
# Sanitize the 'Event' column to ensure consistency
|
||||
event_df['Event'] = event_df['Event'].str.upper().str.strip()
|
||||
|
||||
# Debugging: Print unique event types to verify correct parsing
|
||||
unique_events = event_df['Event'].unique()
|
||||
print(f"Unique Events Found: {unique_events}")
|
||||
|
||||
# Create a 3D plot
|
||||
fig = plt.figure(figsize=(14, 10))
|
||||
ax = fig.add_subplot(111, projection='3d')
|
||||
|
||||
# Define colors for different agent types
|
||||
colors = {'T': 'red', 'M': 'blue'}
|
||||
|
||||
# Group data by AgentID
|
||||
agent_types = set()
|
||||
for agent_id, agent_data in df.groupby('AgentID'):
|
||||
agent_type = agent_data['AgentType'].iloc[0]
|
||||
color = colors.get(agent_type, 'black')
|
||||
downsampled = agent_data.iloc[::10]
|
||||
|
||||
ax.plot(
|
||||
downsampled['AgentX'],
|
||||
downsampled['AgentZ'],
|
||||
downsampled['AgentY'],
|
||||
color=color,
|
||||
alpha=0.5,
|
||||
linewidth=0.5,
|
||||
label=f"Agent Type: {agent_type}" # Optional: More descriptive labels
|
||||
)
|
||||
agent_types.add(agent_type)
|
||||
|
||||
# Define event markers with higher zorder for visibility
|
||||
event_markers = {
|
||||
'HIT': ('o', 'green', 'Hit'),
|
||||
'MISS': ('x', 'red', 'Miss'),
|
||||
'NEW_THREAT': ('^', 'orange', 'New Threat'),
|
||||
'NEW_INTERCEPTOR': ('s', 'blue', 'New Interceptor')
|
||||
}
|
||||
|
||||
# Plot events
|
||||
for event_type, (marker, color, label) in event_markers.items():
|
||||
event_data = event_df[event_df['Event'] == event_type]
|
||||
if not event_data.empty:
|
||||
ax.scatter(
|
||||
event_data['PositionX'],
|
||||
event_data['PositionZ'],
|
||||
event_data['PositionY'],
|
||||
c=color,
|
||||
marker=marker,
|
||||
s=100, # Increased marker size for better visibility
|
||||
label=label,
|
||||
edgecolors='k', # Adding black edges for contrast
|
||||
depthshade=True,
|
||||
zorder=5 # Ensure markers are on top
|
||||
)
|
||||
|
||||
# Set labels
|
||||
ax.set_xlabel('X (m)', fontsize=12)
|
||||
ax.set_ylabel('Z (m)', fontsize=12)
|
||||
ax.set_zlabel('Y (m)', fontsize=12)
|
||||
|
||||
# Set view angle for better visualization
|
||||
ax.view_init(elev=20, azim=45)
|
||||
|
||||
# Add a ground plane for reference
|
||||
x_min, x_max = ax.get_xlim()
|
||||
z_min, z_max = ax.get_ylim()
|
||||
xx, zz = np.meshgrid(np.linspace(x_min, x_max, 2), np.linspace(z_min, z_max, 2))
|
||||
yy = np.zeros_like(xx)
|
||||
ax.plot_surface(xx, zz, yy, alpha=0.2, color='green')
|
||||
|
||||
plt.title('Agents Trajectories and Events (X: Right, Z: Forward, Y: Up)', fontsize=14)
|
||||
|
||||
# Optimize legend to prevent overcrowding
|
||||
handles, labels = ax.get_legend_handles_labels()
|
||||
# Remove duplicate labels
|
||||
unique = dict(zip(labels, handles))
|
||||
ax.legend(unique.values(), unique.keys(), loc='upper left', bbox_to_anchor=(1, 1), fontsize=10)
|
||||
|
||||
plt.tight_layout()
|
||||
plt.show()
|
||||
|
||||
def print_summary(telemetry_file_path, event_file_path):
|
||||
# Read the telemetry CSV file
|
||||
df = pd.read_csv(telemetry_file_path)
|
||||
|
||||
# Read the event CSV file
|
||||
event_df = pd.read_csv(event_file_path)
|
||||
|
||||
# Sanitize the 'Event' column to ensure consistency
|
||||
event_df['Event'] = event_df['Event'].str.upper().str.strip()
|
||||
|
||||
# Print total number of events
|
||||
total_events = len(event_df)
|
||||
print(f"Total number of events: {total_events}")
|
||||
|
||||
# Print counts of each event type
|
||||
event_counts = event_df['Event'].value_counts()
|
||||
print("\nEvent Counts:")
|
||||
for event_type, count in event_counts.items():
|
||||
print(f" {event_type}: {count}")
|
||||
|
||||
# Calculate the time duration of the events
|
||||
if 'Time' in event_df.columns:
|
||||
start_time = event_df['Time'].min()
|
||||
end_time = event_df['Time'].max()
|
||||
duration = end_time - start_time
|
||||
print(f"\nTotal duration of events: {duration:.2f} seconds (from {start_time:.2f} to {end_time:.2f})")
|
||||
else:
|
||||
print("\n'Time' column not found in event data.")
|
||||
|
||||
|
||||
if 'Time' in event_df.columns:
|
||||
hits = event_df[event_df['Event'] == 'HIT']
|
||||
misses = event_df[event_df['Event'] == 'MISS']
|
||||
|
||||
if not hits.empty:
|
||||
first_hit_time = hits['Time'].min()
|
||||
last_hit_time = hits['Time'].max()
|
||||
print(f"\nFirst hit at {first_hit_time:.2f} seconds, last hit at {last_hit_time:.2f} seconds")
|
||||
else:
|
||||
print("\nNo hits recorded.")
|
||||
|
||||
if not misses.empty:
|
||||
first_miss_time = misses['Time'].min()
|
||||
last_miss_time = misses['Time'].max()
|
||||
print(f"First miss at {first_miss_time:.2f} seconds, last miss at {last_miss_time:.2f} seconds")
|
||||
else:
|
||||
print("No misses recorded.")
|
||||
else:
|
||||
print("\n'Time' column not found in event data.")
|
||||
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(description='Visualize telemetry data and events.')
|
||||
parser.add_argument('telemetry_file', nargs='?', default=None, help='Path to telemetry CSV file.')
|
||||
parser.add_argument('event_file', nargs='?', default=None, help='Path to event CSV file.')
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.telemetry_file and args.event_file:
|
||||
telemetry_file_path = args.telemetry_file
|
||||
event_file_path = args.event_file
|
||||
else:
|
||||
telemetry_file_path = find_latest_telemetry_file()
|
||||
event_file_path = find_latest_event_log()
|
||||
if telemetry_file_path is None or event_file_path is None:
|
||||
exit(1)
|
||||
print_summary(telemetry_file_path, event_file_path)
|
||||
plot_telemetry(telemetry_file_path, event_file_path)
|
|
@ -0,0 +1,5 @@
|
|||
node_modules/
|
||||
package-lock.json
|
||||
.vuepress/dist/
|
||||
.vitepress/cache/
|
||||
.vitepress/dist/
|
|
@ -0,0 +1,40 @@
|
|||
import { defineConfig } from 'vitepress'
|
||||
|
||||
// https://vitepress.dev/reference/site-config
|
||||
export default defineConfig({
|
||||
title: "micromissiles-unity",
|
||||
description: "Swarm-on-swarm simulator using micromissiles for point defense",
|
||||
base: '/micromissiles-unity/',
|
||||
themeConfig: {
|
||||
// https://vitepress.dev/reference/default-theme-config
|
||||
nav: [
|
||||
{ text: 'Home', link: '/' },
|
||||
{ text: 'Documentation', link: '/Keybinds_and_Controls' },
|
||||
{ text: 'Development Guide', link: '/Development_Guide' }
|
||||
],
|
||||
|
||||
sidebar: [
|
||||
{
|
||||
text: 'Documentation',
|
||||
items: [
|
||||
{ text: 'Keybinds and Controls', link: '/Keybinds_and_Controls' },
|
||||
{ text: 'Simulation Configuration Guide', link: '/Simulation_Config_Guide' },
|
||||
{ text: 'Simulation Logging', link: '/Simulation_Logging' },
|
||||
{ text: 'Coverage Reports', link: '/coverage/editmode/Report/' },
|
||||
{ text: 'Development Guide', link: '/Development_Guide' }
|
||||
]
|
||||
}
|
||||
],
|
||||
|
||||
socialLinks: [
|
||||
{ icon: 'github', link: 'https://github.com/PisterLab/micromissiles-unity' }
|
||||
],
|
||||
search: {
|
||||
provider: 'local'
|
||||
},
|
||||
footer: {
|
||||
message: 'Released under the <a href="https://github.com/PisterLab/micromissiles-unity/blob/main/LICENSE">BSD-3-Clause License</a>.',
|
||||
copyright: 'Copyright © 2024-present, The Regents of the University of California (Regents). All Rights Reserved.'
|
||||
}
|
||||
}
|
||||
})
|
|
@ -0,0 +1,84 @@
|
|||
# Development Guide
|
||||
|
||||
This guide will help you set up and run the project in development mode. You'll learn how to install Unity Hub, open the project, and navigate the main scene.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [Prerequisites](#prerequisites)
|
||||
- [Installation Steps](#installation-steps)
|
||||
- [1. Install Unity Hub](#1-install-unity-hub)
|
||||
- [2. Clone the Project Repository](#2-clone-the-project-repository)
|
||||
- [3. Launch the Project via Unity Hub](#3-launch-the-project-via-unity-hub)
|
||||
- [4. Open the Main Scene](#4-open-the-main-scene)
|
||||
- [Next Steps](#next-steps)
|
||||
- [Additional Resources](#additional-resources)
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- A computer with internet access.
|
||||
- Administrative privileges to install software.
|
||||
- [Git](https://git-scm.com/downloads) installed on your system (optional, for cloning the repository).
|
||||
|
||||
## Installation Steps
|
||||
|
||||
### 1. Install Unity Hub
|
||||
|
||||
Unity Hub is a desktop application that manages your Unity projects and installations. It simplifies the process of installing different Unity versions and launching projects.
|
||||
|
||||
**Steps to Install Unity Hub:**
|
||||
|
||||
1. Visit the [Unity Download Page](https://unity3d.com/get-unity/download).
|
||||
2. Click on **"Download Unity Hub"**.
|
||||
3. Run the downloaded installer and follow the on-screen instructions to complete the installation.
|
||||
|
||||
### 2. Clone the Project Repository
|
||||
|
||||
Obtain the project source code by cloning the repository from GitHub.
|
||||
|
||||
```bash
|
||||
git clone https://github.com/PisterLab/micromissiles-unity.git
|
||||
```
|
||||
Alternatively, you can download the repository as a ZIP file and extract it to a preferred location.
|
||||
|
||||
### 3. Launch the Project via Unity Hub
|
||||
|
||||
![Unity Hub](./images/unity_hub.png)
|
||||
|
||||
1. **Open Unity Hub**.
|
||||
|
||||
2. **Add the Project to Unity Hub**:
|
||||
- Navigate to the **"Projects"** tab.
|
||||
- Click on the **"ADD"** button.
|
||||
- Browse to the folder where you cloned or extracted the project.
|
||||
- Select the folder containing the `Assets` folder and click on **"Select Folder"**.
|
||||
|
||||
3. **Install the Required Unity Version**:
|
||||
- Unity Hub will detect if the project requires a Unity version that is not currently installed.
|
||||
- A notification or warning icon may appear next to the project name.
|
||||
- Click on the notification and select **"Install Unity **[version]**"**.
|
||||
- Unity Hub will download and install the required Unity version automatically.
|
||||
|
||||
4. **Open the Project**:
|
||||
- Once the required Unity version is installed, click on the project name in Unity Hub to open it.
|
||||
|
||||
### 4. Open the Main Scene
|
||||
|
||||
After the project opens in Unity:
|
||||
|
||||
1. In the **Project** window (usually located at the bottom), navigate to:
|
||||
|
||||
```
|
||||
Assets/Scenes/
|
||||
```
|
||||
|
||||
2. Find the main scene file, usually named `MainScene.unity`.
|
||||
|
||||
3. Double-click on `MainScene.unity` to open it.
|
||||
|
||||
4. The scene will load in the **Scene** view. You can now run the simulation by clicking the **Play** button at the top of the Unity Editor.
|
||||
|
||||
|
||||
## Additional Resources
|
||||
|
||||
- [Keybinds and Controls](Keybinds_and_Controls.md)
|
||||
- [Simulation Configuration Guide](Simulation_Config_Guide.md)
|
|
@ -0,0 +1,85 @@
|
|||
# Markdown Extension Examples
|
||||
|
||||
This page demonstrates some of the built-in markdown extensions provided by VitePress.
|
||||
|
||||
## Syntax Highlighting
|
||||
|
||||
VitePress provides Syntax Highlighting powered by [Shiki](https://github.com/shikijs/shiki), with additional features like line-highlighting:
|
||||
|
||||
**Input**
|
||||
|
||||
````md
|
||||
```js{4}
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
msg: 'Highlighted!'
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
````
|
||||
|
||||
**Output**
|
||||
|
||||
```js{4}
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
msg: 'Highlighted!'
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Custom Containers
|
||||
|
||||
**Input**
|
||||
|
||||
```md
|
||||
::: info
|
||||
This is an info box.
|
||||
:::
|
||||
|
||||
::: tip
|
||||
This is a tip.
|
||||
:::
|
||||
|
||||
::: warning
|
||||
This is a warning.
|
||||
:::
|
||||
|
||||
::: danger
|
||||
This is a dangerous warning.
|
||||
:::
|
||||
|
||||
::: details
|
||||
This is a details block.
|
||||
:::
|
||||
```
|
||||
|
||||
**Output**
|
||||
|
||||
::: info
|
||||
This is an info box.
|
||||
:::
|
||||
|
||||
::: tip
|
||||
This is a tip.
|
||||
:::
|
||||
|
||||
::: warning
|
||||
This is a warning.
|
||||
:::
|
||||
|
||||
::: danger
|
||||
This is a dangerous warning.
|
||||
:::
|
||||
|
||||
::: details
|
||||
This is a details block.
|
||||
:::
|
||||
|
||||
## More
|
||||
|
||||
Check out the documentation for the [full list of markdown extensions](https://vitepress.dev/guide/markdown).
|
|
@ -9,13 +9,13 @@ The main configuration files you will work with are located in the `Assets/Strea
|
|||
- **Simulation Configurations**:
|
||||
- **`1_salvo_1_hydra_7_drones.json`**: A simple, barebones example of a simulation configuration featuring a single salvo in a 7-on-7 scenario.
|
||||
- **`3_salvo_10_hydra_200_drones.json`**: A more complex example with three salvos, illustrating a 210-on-200 scenario. This demonstrates how to set up multiple salvos within the simulation.
|
||||
- **C# Script**: [`SimulationConfig.cs`](Assets/Scripts/Config/SimulationConfig.cs)
|
||||
- **C# Script**: [`SimulationConfig.cs`](https://github.com/PisterLab/micromissiles-unity/blob/master/Assets/Scripts/Config/StaticConfig.cs)
|
||||
|
||||
- **Model Configurations** (found in `Assets/StreamingAssets/Configs/Models/`):
|
||||
- **`micromissile.json`**
|
||||
- **`hydra70.json`**
|
||||
- **`drone.json`**
|
||||
- **C# Script**: [`StaticConfig.cs`](Assets/Scripts/Config/StaticConfig.cs)
|
||||
- **C# Script**: [`StaticConfig.cs`](https://github.com/PisterLab/micromissiles-unity/blob/master/Assets/Scripts/Config/StaticConfig.cs)
|
||||
|
||||
### File Locations
|
||||
|
||||
|
@ -37,7 +37,7 @@ The simulation configurations are defined in JSON files that specify the initial
|
|||
|
||||
This is a basic configuration featuring a single salvo with one interceptor type (`HYDRA_70`) and seven threat drones.
|
||||
|
||||
```json:Assets/StreamingAssets/Configs/1_salvo_1_hydra_7_drones.json
|
||||
```json
|
||||
{
|
||||
"timeScale": 1,
|
||||
"interceptor_swarm_configs": [
|
||||
|
@ -89,7 +89,7 @@ This is a basic configuration featuring a single salvo with one interceptor type
|
|||
|
||||
This configuration demonstrates a more complex scenario with three salvos, each launching ten `HYDRA_70` missiles at different times against 200 threat drones. This results in a total of 210 missiles (including submunitions) engaging 200 targets.
|
||||
|
||||
```json:Assets/StreamingAssets/Configs/3_salvo_10_hydra_200_drones.json
|
||||
```json
|
||||
{
|
||||
"timeScale": 1,
|
||||
"interceptor_swarm_configs": [
|
||||
|
@ -265,7 +265,7 @@ To define a new inte or threat model:
|
|||
|
||||
This script defines the data structures used to interpret the JSON simulation configuration files.
|
||||
|
||||
[Assets/Scripts/Config/SimulationConfig.cs](../../Assets/Scripts/Config/SimulationConfig.cs)
|
||||
[Assets/Scripts/Config/SimulationConfig.cs](https://github.com/PisterLab/micromissiles-unity/blob/master/Assets/Scripts/Config/SimulationConfig.cs)
|
||||
|
||||
**Classes**:
|
||||
|
||||
|
@ -281,10 +281,10 @@ This script defines the data structures used to interpret the JSON simulation co
|
|||
|
||||
This script defines the classes corresponding to the model configuration JSON structure.
|
||||
|
||||
[Assets/Scripts/Config/StaticConfig.cs](../../Assets/Scripts/Config/StaticConfig.cs)
|
||||
[Assets/Scripts/Config/StaticConfig.cs](https://github.com/PisterLab/micromissiles-unity/blob/master/Assets/Scripts/Config/StaticConfig.cs)
|
||||
|
||||
For example:
|
||||
```csharp:Assets/Scripts/Config/StaticConfig.cs
|
||||
```csharp
|
||||
[Serializable]
|
||||
public class StaticConfig {
|
||||
[Serializable]
|
||||
|
@ -335,8 +335,8 @@ While the simulation is running, you can load a new Simulation Configuration JSO
|
|||
|
||||
For further assistance, refer to the comments and documentation within the code files:
|
||||
|
||||
- [`SimManager.cs`](Assets/Scripts/SimManager.cs): Manages simulation state and agent creation.
|
||||
- [`InputManager.cs`](Assets/Scripts/Managers/InputManager.cs): Handles user input and interactions.
|
||||
- [`SimManager.cs`](https://github.com/PisterLab/micromissiles-unity/blob/master/Assets/Scripts/SimManager.cs): Manages simulation state and agent creation.
|
||||
- [`InputManager.cs`](https://github.com/PisterLab/micromissiles-unity/blob/master/Assets/Scripts/Managers/InputManager.cs): Handles user input and interactions.
|
||||
|
||||
---
|
||||
|
||||
|
|
|
@ -1,12 +1,259 @@
|
|||
# Simulation Logging
|
||||
# Simulation Logging
|
||||
|
||||
This guide provides instructions on how to access and interpret the simulation logs, how they are structured by the `SimMonitor` class, and how to utilize the provided `visualize_log.py` script to analyze simulation data. Additionally, it offers guidance on creating your own scripts for custom analysis.
|
||||
|
||||
## Overview
|
||||
|
||||
![Python simulation log visualizer](./images/sim_visualizer.png)
|
||||
|
||||
Simulation logs capture detailed telemetry and event data from each simulation run. These logs are essential for debugging, performance analysis, and understanding the behavior of agents within the simulation.
|
||||
|
||||
Logs are exported to the `Telemetry/Logs` folder in your operating system's [persistent data path](https://docs.unity3d.com/ScriptReference/Application-persistentDataPath.html).
|
||||
|
||||
For example, on Windows, the logs will be exported to
|
||||
`C:\Users\<user>\AppData\LocalLow\BAMLAB\micromissiles\Telemetry`.
|
||||
For example, on Windows, the logs are exported to:
|
||||
|
||||
On MacOS, the logs will be exported to
|
||||
`~/Library/Application Support/BAMLAB/micromissiles/Telemetry`.
|
||||
```
|
||||
C:\Users\<user>\AppData\LocalLow\BAMLAB\micromissiles\Telemetry\Logs
|
||||
```
|
||||
|
||||
On macOS, the logs are exported to:
|
||||
|
||||
```
|
||||
~/Library/Application Support/BAMLAB/micromissiles/Telemetry/Logs
|
||||
```
|
||||
|
||||
`visualize_log.py` is an example script provided to help visualize and interpret the simulation logs. It is included in the `Tools` directory of the release download.
|
||||
|
||||
|
||||
## Understanding Log Files and Directory Structure
|
||||
|
||||
### Log Directory Structure
|
||||
|
||||
Simulation logs are organized into timestamped directories within the `Logs` folder. Each simulation run generates a new directory named with the timestamp of the run.
|
||||
|
||||
For example:
|
||||
|
||||
```
|
||||
Telemetry/
|
||||
└── Logs/
|
||||
├── 20241002_101305/
|
||||
│ ├── sim_telemetry_20241002_101311.csv
|
||||
│ ├── sim_events_20241002_101311.csv
|
||||
│ │
|
||||
│ ├── sim_telemetry_20241002_101306.csv
|
||||
│ └── sim_events_20241002_101306.csv
|
||||
├── 20241002_012122/
|
||||
│ ├── sim_telemetry_20241002_012122.csv
|
||||
│ └── sim_events_20241002_012122.csv
|
||||
└── ...
|
||||
```
|
||||
|
||||
Each simulation run produces two main CSV files:
|
||||
|
||||
- **Telemetry Log (`sim_telemetry_*.csv`)**: Contains detailed state information for each agent at each time step.
|
||||
- **Event Log (`sim_events_*.csv`)**: Records significant events such as hits, misses, agent creation, and destruction.
|
||||
|
||||
### Log Files Generated by `SimMonitor`
|
||||
|
||||
The logging system is managed by the `SimMonitor` class in the simulation codebase.
|
||||
|
||||
```csharp
|
||||
public class SimMonitor : MonoBehaviour
|
||||
{
|
||||
// Responsible for logging simulation data
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
**Key Responsibilities of `SimMonitor`:**
|
||||
|
||||
- Collecting agent state data at each simulation step.
|
||||
- Writing telemetry data to `sim_telemetry_*.csv`.
|
||||
- Recording significant events to `sim_events_*.csv`.
|
||||
- Organizing logs into timestamped directories for each simulation run.
|
||||
|
||||
### Telemetry Log Structure
|
||||
|
||||
The telemetry log provides a snapshot of the simulation at each time step for every agent. Key columns include:
|
||||
|
||||
- **`Time`**: Simulation time at the log entry.
|
||||
- **`AgentID`**: Unique identifier for each agent.
|
||||
- **`AgentType`**: Type of the agent (e.g., interceptor, threat).
|
||||
- **`AgentX`**, **`AgentY`**, **`AgentZ`**: Position coordinates of the agent.
|
||||
- **`AgentVelocityX`**, **`AgentVelocityY`**, **`AgentVelocityZ`**: Velocity components.
|
||||
- **`AgentStatus`**: Current status of the agent (e.g., active, destroyed).
|
||||
|
||||
### Event Log Structure
|
||||
|
||||
The event log records significant occurrences within the simulation. Key columns include:
|
||||
|
||||
- **`Time`**: Time when the event occurred.
|
||||
- **`PositionX`**, **`PositionY`**, **`PositionZ`**: Position where the event occurred.
|
||||
- **`EventType`**: Type of event (e.g., `HIT`, `MISS`, `NEW_THREAT`, `NEW_INTERCEPTOR`).
|
||||
- **`Details`**: Additional details about the event.
|
||||
|
||||
|
||||
## Running the `visualize_log.py` Script
|
||||
|
||||
The `visualize_log.py` script helps visualize agent trajectories and significant events in a 3D plot.
|
||||
|
||||
### Locating the Script
|
||||
|
||||
After downloading and extracting the release package, you can find the script at:
|
||||
|
||||
```
|
||||
Tools/visualize_log.py
|
||||
```
|
||||
|
||||
Make sure you have Python 3 installed on your system, along with the required libraries to run the script.
|
||||
|
||||
### Required Python Libraries
|
||||
|
||||
The script depends on the following Python libraries:
|
||||
|
||||
- **`pandas`**
|
||||
- **`matplotlib`**
|
||||
- **`numpy`**
|
||||
|
||||
You can install them using `pip`:
|
||||
|
||||
```bash
|
||||
pip install pandas matplotlib numpy
|
||||
```
|
||||
|
||||
### Usage
|
||||
|
||||
#### Navigate to the Tools Directory
|
||||
|
||||
Open a terminal or command prompt and navigate to the `Tools` directory:
|
||||
|
||||
```bash
|
||||
cd path/to/Tools/
|
||||
```
|
||||
|
||||
#### Run the Script
|
||||
|
||||
To visualize the most recent simulation logs:
|
||||
|
||||
```bash
|
||||
python visualize_log.py
|
||||
```
|
||||
|
||||
**What the Script Does:**
|
||||
|
||||
- **Automatically Finds the Latest Logs**: If no arguments are provided, it locates the most recent `sim_telemetry_*.csv` and `sim_events_*.csv` files.
|
||||
- **Prints a Summary**: Outputs a summary of events, including total counts and timing of hits and misses.
|
||||
- **Generates a 3D Plot**: Displays agent trajectories and marks events such as hits and misses.
|
||||
|
||||
#### Specifying Log Files Manually
|
||||
|
||||
You can also provide specific file paths as arguments:
|
||||
|
||||
```bash
|
||||
python visualize_log.py path/to/sim_telemetry_file.csv path/to/sim_events_file.csv
|
||||
```
|
||||
|
||||
### Example Output
|
||||
|
||||
```
|
||||
Total number of events: 150
|
||||
|
||||
Event Counts:
|
||||
HIT: 120
|
||||
MISS: 30
|
||||
|
||||
First hit at 5.00 seconds, last hit at 15.00 seconds
|
||||
|
||||
[3D plot window opens showing trajectories and events]
|
||||
```
|
||||
|
||||
### Interpreting the Plot
|
||||
|
||||
The 3D plot displays:
|
||||
|
||||
- **Agent Trajectories**: Lines representing the paths of interceptors and threats.
|
||||
- **Colors** indicate agent types (e.g., blue for interceptors, red for threats).
|
||||
- **Event Markers**: Symbols marking where events occurred.
|
||||
- **Hits**: Marked with green circles.
|
||||
- **Misses**: Marked with red crosses.
|
||||
|
||||
### Adjusting the Visualization
|
||||
|
||||
- **View Angle**: You can rotate the 3D plot by clicking and dragging to view the simulation from different perspectives.
|
||||
- **Zoom**: Use the scroll wheel to zoom in and out.
|
||||
|
||||
## Writing Your Own Scripts
|
||||
|
||||
The simulation logs are in CSV format, making them accessible for custom analysis and visualization.
|
||||
|
||||
### Getting Started
|
||||
|
||||
- **Choose a Programming Language**: Python or MATLAB are recommended for ease-of-use and data analysis capabilities.
|
||||
|
||||
For example, using Python and the `pandas` library, you can load the telemetry and event data like this:
|
||||
|
||||
```python
|
||||
import pandas as pd
|
||||
|
||||
telemetry_df = pd.read_csv('path/to/sim_telemetry_*.csv')
|
||||
event_df = pd.read_csv('path/to/sim_events_*.csv')
|
||||
```
|
||||
|
||||
### Visualization
|
||||
|
||||
- **2D Plots**: Use `matplotlib` to create time-series plots:
|
||||
|
||||
```python
|
||||
import matplotlib.pyplot as plt
|
||||
|
||||
plt.plot(telemetry_df['Time'], telemetry_df['AgentY'])
|
||||
plt.xlabel('Time (s)')
|
||||
plt.ylabel('Altitude (m)')
|
||||
plt.title('Agent Altitude Over Time')
|
||||
plt.show()
|
||||
```
|
||||
|
||||
- **3D Plots**: Use `mpl_toolkits.mplot3d` for 3D trajectory plots.
|
||||
|
||||
### Sample Script: Calculating Miss Distances
|
||||
|
||||
```python
|
||||
import pandas as pd
|
||||
import numpy as np
|
||||
|
||||
# Load telemetry and event data
|
||||
telemetry_df = pd.read_csv('path/to/sim_telemetry_*.csv')
|
||||
event_df = pd.read_csv('path/to/sim_events_*.csv')
|
||||
|
||||
# Filter miss events
|
||||
miss_events = event_df[event_df['Event'] == 'MISS']
|
||||
|
||||
# Calculate miss distances
|
||||
miss_distances = []
|
||||
for idx, miss in miss_events.iterrows():
|
||||
agent_id = miss['AgentID']
|
||||
time = miss['Time']
|
||||
# Get agent position at the time of miss
|
||||
agent_state = telemetry_df[(telemetry_df['AgentID'] == agent_id) & (telemetry_df['Time'] == time)]
|
||||
if not agent_state.empty:
|
||||
x = agent_state['AgentX'].values[0]
|
||||
y = agent_state['AgentY'].values[0]
|
||||
z = agent_state['AgentZ'].values[0]
|
||||
# Calculate distance to target or predefined point
|
||||
distance = np.sqrt(x**2 + y**2 + z**2)
|
||||
miss_distances.append(distance)
|
||||
|
||||
# Output average miss distance
|
||||
average_miss_distance = np.mean(miss_distances)
|
||||
print(f'Average Miss Distance: {average_miss_distance:.2f} meters')
|
||||
```
|
||||
|
||||
### Suggestions for Analysis
|
||||
|
||||
- **Performance Metrics**: Determine interception success rates, average time to intercept, or hit accuracy.
|
||||
- **Behavioral Analysis**: Examine how changes in simulation configurations affect agent behavior.
|
||||
- **Batch Processing**: Automate analysis over multiple simulation runs to compare different scenarios.
|
||||
|
||||
## Additional Resources
|
||||
|
||||
- **Python Documentation**: [pandas](https://pandas.pydata.org/), [matplotlib](https://matplotlib.org/), [NumPy](https://numpy.org/)
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 254 KiB |
|
@ -0,0 +1,41 @@
|
|||
---
|
||||
# https://vitepress.dev/reference/default-theme-home-page
|
||||
layout: home
|
||||
|
||||
hero:
|
||||
name: "micromissiles-unity"
|
||||
|
||||
tagline: "Swarm-on-swarm simulator using micromissiles for point defense"
|
||||
actions:
|
||||
- theme: brand
|
||||
text: Documentation
|
||||
link: /Keybinds_and_Controls
|
||||
- theme: alt
|
||||
text: Development Guide
|
||||
link: /Development_Guide
|
||||
|
||||
---
|
||||
|
||||
# Quick Start
|
||||
|
||||
We generate pre-built standalone binaries for Windows and Mac users from the `release` branch. These binaries are intended for non-development users who just want to run the application and modify a few configurations along the way.
|
||||
|
||||
You can find the latest release [here](https://github.com/PisterLab/micromissiles-unity/releases/latest).
|
||||
|
||||
## Windows
|
||||
|
||||
1. Download the zip file for Windows: `micromissiles-<version>-windows_x86_64.zip`.
|
||||
2. Unzip the zip file. The zip file should contain a single directory called `micromissiles-<version>-windows_x86_64`.
|
||||
3. In the `micromissiles-<version>-windows_x86_64` directory, run `micromissiles-<version>-StandaloneWindows64.exe`.
|
||||
|
||||
## Mac
|
||||
|
||||
1. Download the tarball file for Darwin: `micromissiles-<version>-darwin.tar.gz`.
|
||||
2. Untar the tarball. The tarball should contain a single directory called `micromissiles-<version>-darwin`.
|
||||
3. In the `micromissiles-<version>-darwin` directory, run the app file.
|
||||
|
||||
|
||||
# Next Steps
|
||||
|
||||
- Familiarize yourself with the [**Keybinds and Controls**](Keybinds_and_Controls.md) to navigate and interact with the simulation.
|
||||
- Learn how to configure the simulation settings by reading the [**Simulation Configuration Guide**](Simulation_Config_Guide.md).
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"scripts": {
|
||||
"docs:dev": "vitepress dev docs",
|
||||
"docs:build": "vitepress build docs",
|
||||
"docs:preview": "vitepress preview docs"
|
||||
},
|
||||
"dependencies": {
|
||||
"vue": "^3.x.x",
|
||||
"vitepress": "^1.3.4"
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue