An open source Danmaku development kit for Unity3D.
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Basic danmaku collisions

james713 bd213889 defb173e

+286 -20
+13
Assets/DanmakuPoolTest.cs
··· 14 14 public DanmakuState State; 15 15 IFireable fireable; 16 16 float timer; 17 + RaycastHit2D[] raycastCache; 17 18 18 19 void Start () { 19 20 pool = new DanmakuPool(PoolSize); ··· 24 25 if (Renderer != null) { 25 26 Renderer.Pool = pool; 26 27 } 28 + raycastCache = new RaycastHit2D[256]; 27 29 } 28 30 29 31 /// <summary> 30 32 /// Update is called every frame, if the MonoBehaviour is enabled. 31 33 /// </summary> 32 34 void Update() { 35 + pool.ColliderRadius = 1; 33 36 pool.Update().Complete(); 34 37 timer += Time.deltaTime; 35 38 if (timer > 1/20f) { 36 39 State.Rotation += 20 * Mathf.Deg2Rad; 37 40 fireable.Fire(State); 38 41 timer = 0; 42 + } 43 + foreach (var danmaku in pool) { 44 + var layerMask = pool.CollisionMasks[danmaku.Id]; 45 + if (layerMask == 0) continue; 46 + var oldPosition = pool.OldPositions[danmaku.Id]; 47 + var direction = oldPosition - danmaku.Position; 48 + var distance = direction.magnitude; 49 + var hits = Physics2D.CircleCastNonAlloc(oldPosition, pool.ColliderRadius, direction, raycastCache, distance, layerMask); 50 + if (hits <= 0) continue; 51 + danmaku.Destroy(); 39 52 } 40 53 } 41 54
+116 -4
Assets/Test Scene.unity
··· 170 170 Min: 20 171 171 Max: 20 172 172 AngularVelocity: 173 - Min: 0 174 - Max: 0 173 + Min: 0.19625 174 + Max: 0.19625 175 175 Color: {r: 1, g: 0, b: 0, a: 1} 176 176 --- !u!81 &872241322 177 177 AudioListener: ··· 207 207 far clip plane: 1000 208 208 field of view: 60 209 209 orthographic: 1 210 - orthographic size: 10 210 + orthographic size: 30 211 211 m_Depth: -1 212 212 m_CullingMask: 213 213 serializedVersion: 2 ··· 249 249 m_EditorClassIdentifier: 250 250 Bounds: 251 251 m_Center: {x: 0, y: 0, z: 0} 252 - m_Extent: {x: 25, y: 25, z: 2} 252 + m_Extent: {x: 50, y: 50, z: 2} 253 253 --- !u!1 &1481724626 254 254 GameObject: 255 255 m_ObjectHideFlags: 0 ··· 315 315 m_UseColorTemperature: 0 316 316 m_ShadowRadius: 0 317 317 m_ShadowAngle: 0 318 + --- !u!1 &1882949158 319 + GameObject: 320 + m_ObjectHideFlags: 0 321 + m_PrefabParentObject: {fileID: 0} 322 + m_PrefabInternal: {fileID: 0} 323 + serializedVersion: 5 324 + m_Component: 325 + - component: {fileID: 1882949161} 326 + - component: {fileID: 1882949160} 327 + - component: {fileID: 1882949159} 328 + - component: {fileID: 1882949162} 329 + m_Layer: 0 330 + m_Name: New Sprite 331 + m_TagString: Untagged 332 + m_Icon: {fileID: 0} 333 + m_NavMeshLayer: 0 334 + m_StaticEditorFlags: 0 335 + m_IsActive: 1 336 + --- !u!212 &1882949159 337 + SpriteRenderer: 338 + m_ObjectHideFlags: 0 339 + m_PrefabParentObject: {fileID: 0} 340 + m_PrefabInternal: {fileID: 0} 341 + m_GameObject: {fileID: 1882949158} 342 + m_Enabled: 1 343 + m_CastShadows: 0 344 + m_ReceiveShadows: 0 345 + m_DynamicOccludee: 1 346 + m_MotionVectors: 1 347 + m_LightProbeUsage: 1 348 + m_ReflectionProbeUsage: 1 349 + m_RenderingLayerMask: 4294967295 350 + m_Materials: 351 + - {fileID: 10754, guid: 0000000000000000f000000000000000, type: 0} 352 + m_StaticBatchInfo: 353 + firstSubMesh: 0 354 + subMeshCount: 0 355 + m_StaticBatchRoot: {fileID: 0} 356 + m_ProbeAnchor: {fileID: 0} 357 + m_LightProbeVolumeOverride: {fileID: 0} 358 + m_ScaleInLightmap: 1 359 + m_PreserveUVs: 0 360 + m_IgnoreNormalsForChartDetection: 0 361 + m_ImportantGI: 0 362 + m_StitchLightmapSeams: 0 363 + m_SelectedEditorRenderState: 0 364 + m_MinimumChartSize: 4 365 + m_AutoUVMaxDistance: 0.5 366 + m_AutoUVMaxAngle: 89 367 + m_LightmapParameters: {fileID: 0} 368 + m_SortingLayerID: 0 369 + m_SortingLayer: 0 370 + m_SortingOrder: 0 371 + m_Sprite: {fileID: 10907, guid: 0000000000000000f000000000000000, type: 0} 372 + m_Color: {r: 1, g: 1, b: 1, a: 1} 373 + m_FlipX: 0 374 + m_FlipY: 0 375 + m_DrawMode: 0 376 + m_Size: {x: 0.16, y: 0.16} 377 + m_AdaptiveModeThreshold: 0.5 378 + m_SpriteTileMode: 0 379 + m_WasSpriteAssigned: 1 380 + m_MaskInteraction: 0 381 + --- !u!61 &1882949160 382 + BoxCollider2D: 383 + m_ObjectHideFlags: 0 384 + m_PrefabParentObject: {fileID: 0} 385 + m_PrefabInternal: {fileID: 0} 386 + m_GameObject: {fileID: 1882949158} 387 + m_Enabled: 1 388 + m_Density: 1 389 + m_Material: {fileID: 0} 390 + m_IsTrigger: 0 391 + m_UsedByEffector: 0 392 + m_UsedByComposite: 0 393 + m_Offset: {x: 0, y: 0} 394 + m_SpriteTilingProperty: 395 + border: {x: 0.049999997, y: 0.049999997, z: 0.049999997, w: 0.049999997} 396 + pivot: {x: 0.5, y: 0.5} 397 + oldSize: {x: 0.16, y: 0.16} 398 + newSize: {x: 0.16, y: 0.16} 399 + adaptiveTilingThreshold: 0.5 400 + drawMode: 0 401 + adaptiveTiling: 0 402 + m_AutoTiling: 0 403 + serializedVersion: 2 404 + m_Size: {x: 0.15, y: 0.15} 405 + m_EdgeRadius: 0 406 + --- !u!4 &1882949161 407 + Transform: 408 + m_ObjectHideFlags: 0 409 + m_PrefabParentObject: {fileID: 0} 410 + m_PrefabInternal: {fileID: 0} 411 + m_GameObject: {fileID: 1882949158} 412 + m_LocalRotation: {x: 0, y: 0, z: 0.08715578, w: 0.9961947} 413 + m_LocalPosition: {x: 1.89, y: -13.2, z: 23.99378} 414 + m_LocalScale: {x: 335.9406, y: 20.803476, z: 1} 415 + m_Children: [] 416 + m_Father: {fileID: 0} 417 + m_RootOrder: 2 418 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 10} 419 + --- !u!114 &1882949162 420 + MonoBehaviour: 421 + m_ObjectHideFlags: 0 422 + m_PrefabParentObject: {fileID: 0} 423 + m_PrefabInternal: {fileID: 0} 424 + m_GameObject: {fileID: 1882949158} 425 + m_Enabled: 1 426 + m_EditorHideFlags: 0 427 + m_Script: {fileID: 11500000, guid: 0970af4f8d9661e4fa80861c5bb48775, type: 3} 428 + m_Name: 429 + m_EditorClassIdentifier:
+13 -13
Assets/src/Core/Danmaku.cs
··· 21 21 /// </remarks> 22 22 public struct Danmaku { 23 23 24 - internal readonly int Index; 24 + public readonly int Id; 25 25 public readonly DanmakuPool Pool; 26 26 27 27 internal Danmaku(DanmakuPool pool, int index) { 28 28 Pool = pool; 29 - Index = index; 29 + Id = index; 30 30 } 31 31 32 32 /// <summary> 33 33 /// Gets the number of seconds since the Danmaku was created. 34 34 /// </summary> 35 - public float Time => Pool.Times[Index]; 35 + public float Time => Pool.Times[Id]; 36 36 37 37 /// <summary> 38 38 /// Gets or sets the world position of the Danmaku. 39 39 /// </summary> 40 40 public Vector2 Position { 41 - get { return Pool.Positions[Index]; } 42 - set { Pool.Positions[Index] = value; } 41 + get { return Pool.Positions[Id]; } 42 + set { Pool.Positions[Id] = value; } 43 43 } 44 44 45 45 /// <summary> ··· 51 51 /// the Danmaku is moving in. 52 52 /// </remarks> 53 53 public float Rotation { 54 - get { return Pool.Rotations[Index]; } 55 - set { Pool.Rotations[Index] = value; } 54 + get { return Pool.Rotations[Id]; } 55 + set { Pool.Rotations[Id] = value; } 56 56 } 57 57 58 58 /// <summary> ··· 63 63 /// Can be negative. 64 64 /// </remarks> 65 65 public float Speed { 66 - get { return Pool.Speeds[Index]; } 67 - set { Pool.Speeds[Index] = value; } 66 + get { return Pool.Speeds[Id]; } 67 + set { Pool.Speeds[Id] = value; } 68 68 } 69 69 70 70 /// <summary> ··· 74 74 /// Units are in radians per second. Can be negative. 75 75 /// </remarks> 76 76 public float AngularSpeed { 77 - get { return Pool.AngularSpeeds[Index]; } 78 - set { Pool.AngularSpeeds[Index] = value; } 77 + get { return Pool.AngularSpeeds[Id]; } 78 + set { Pool.AngularSpeeds[Id] = value; } 79 79 } 80 80 81 81 /// <summary> 82 82 /// Gets or sets the Danmaku's rendering color. 83 83 /// </summary> 84 84 public Color Color { 85 - get { return Pool.Colors[Index]; } 86 - set { Pool.Colors[Index] = value; } 85 + get { return Pool.Colors[Id]; } 86 + set { Pool.Colors[Id] = value; } 87 87 } 88 88 89 89 /// <summary>
+77
Assets/src/Core/DanmakuCollider.cs
··· 1 + using System.Collections; 2 + using System.Collections.Generic; 3 + using UnityEngine; 4 + using UnityEngine.Assertions; 5 + 6 + namespace DanmakU { 7 + 8 + public class DanmakuCollider : MonoBehaviour { 9 + 10 + static readonly List<DanmakuCollider> Colliders; 11 + 12 + static DanmakuCollider() { 13 + Colliders = new List<DanmakuCollider>(); 14 + } 15 + 16 + public static int ColliderCount => Colliders.Count; 17 + 18 + Collider2D[] colliders; 19 + Bounds totalBounds; 20 + int layerMask; 21 + 22 + /// <summary> 23 + /// Awake is called when the script instance is being loaded. 24 + /// </summary> 25 + void Awake() { 26 + colliders = GetComponentsInChildren<Collider2D>(); 27 + totalBounds = BuildBounds(); 28 + } 29 + 30 + /// <summary> 31 + /// This function is called when the object becomes enabled and active. 32 + /// </summary> 33 + void OnEnable() => Colliders.Add(this); 34 + 35 + /// <summary> 36 + /// This function is called when the behaviour becomes disabled or inactive. 37 + /// </summary> 38 + void OnDisable() => Colliders.Remove(this); 39 + 40 + /// <summary> 41 + /// This function is called every fixed framerate frame, if the MonoBehaviour is enabled. 42 + /// </summary> 43 + void FixedUpdate() { 44 + totalBounds = BuildBounds(); 45 + layerMask = 1 << gameObject.layer; 46 + } 47 + 48 + internal static int TestCollisions(Bounds bounds) { 49 + int collisions = 0; 50 + foreach (var collider in Colliders) { 51 + if (!collider.totalBounds.Intersects(bounds)) continue; 52 + collisions |= collider.layerMask; 53 + } 54 + return collisions; 55 + } 56 + 57 + public Bounds BuildBounds() { 58 + Bounds? bounds = null; 59 + foreach (var collider in colliders) { 60 + if (collider != null && collider.enabled && collider.gameObject.activeInHierarchy) { 61 + if (bounds == null) { 62 + bounds = collider.bounds; 63 + } else { 64 + bounds.Value.Encapsulate(collider.bounds); 65 + } 66 + } 67 + } 68 + var fullBounds = bounds ?? new Bounds(transform.position, Vector3.zero); 69 + var extents = fullBounds.extents; 70 + extents.z = float.PositiveInfinity; 71 + fullBounds.extents = extents; 72 + return fullBounds; 73 + } 74 + 75 + } 76 + 77 + }
+11
Assets/src/Core/DanmakuCollider.cs.meta
··· 1 + fileFormatVersion: 2 2 + guid: 0970af4f8d9661e4fa80861c5bb48775 3 + MonoImporter: 4 + externalObjects: {} 5 + serializedVersion: 2 6 + defaultReferences: [] 7 + executionOrder: 0 8 + icon: {instanceID: 0} 9 + userData: 10 + assetBundleName: 11 + assetBundleVariant:
+22 -3
Assets/src/Core/DanmakuPool.cs
··· 14 14 15 15 public int ActiveCount { get; private set; } 16 16 17 + public float ColliderRadius; 18 + 17 19 internal NativeArray<float> Times; 18 20 19 21 public NativeArray<Vector2> Positions; ··· 24 26 25 27 public NativeArray<Vector4> Colors; 26 28 27 - public NativeArray<Matrix4x4> Transforms; 29 + internal NativeArray<Matrix4x4> Transforms; 30 + internal NativeArray<Vector2> OldPositions; 31 + internal NativeArray<int> CollisionMasks; 28 32 29 33 readonly Stack<int> Deactivated; 30 34 ··· 43 47 Colors = new NativeArray<Vector4>(poolSize, Allocator.Persistent, NativeArrayOptions.UninitializedMemory); 44 48 45 49 Transforms = new NativeArray<Matrix4x4>(poolSize, Allocator.Persistent, NativeArrayOptions.UninitializedMemory); 50 + 51 + OldPositions = new NativeArray<Vector2>(poolSize, Allocator.Persistent, NativeArrayOptions.UninitializedMemory); 52 + CollisionMasks = new NativeArray<int>(poolSize, Allocator.Persistent, NativeArrayOptions.UninitializedMemory); 46 53 } 47 54 48 55 public JobHandle Update(JobHandle dependency = default(JobHandle)) { ··· 58 65 59 66 if (ActiveCount <= 0) return dependency; 60 67 61 - return new MoveDanmaku { 68 + OldPositions.CopyFrom(Positions); 69 + var updateHandle = new MoveDanmaku { 62 70 DeltaTime = Time.deltaTime, 63 71 64 72 Times = Times, ··· 71 79 72 80 Transforms = Transforms 73 81 }.Schedule(ActiveCount, kBatchSize, dependency); 82 + if (DanmakuCollider.ColliderCount > 0) { 83 + updateHandle = new CollideDanamku { 84 + Radius = ColliderRadius, 85 + Positions = Positions, 86 + Collisions = CollisionMasks 87 + }.Schedule(ActiveCount, kBatchSize, updateHandle); 88 + } 89 + return updateHandle; 74 90 } 75 91 76 92 /// <summary> ··· 116 132 Colors.Dispose(); 117 133 118 134 Transforms.Dispose(); 135 + 136 + OldPositions.Dispose(); 137 + CollisionMasks.Dispose(); 119 138 } 120 139 121 140 public Enumerator GetEnumerator() => new Enumerator(this, 0, ActiveCount); 122 141 IEnumerator<Danmaku> IEnumerable<Danmaku>.GetEnumerator() => GetEnumerator(); 123 142 IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); 124 143 125 - internal void Destroy(Danmaku deactivate) => Deactivated.Push(deactivate.Index); 144 + internal void Destroy(Danmaku deactivate) => Deactivated.Push(deactivate.Id); 126 145 127 146 void Swap<T>(ref NativeArray<T> array, int a, int b) where T : struct { 128 147 T temp = array[a];
+23
Assets/src/Core/Jobs/CollideDanamku.cs
··· 1 + using System.Collections; 2 + using System.Collections.Generic; 3 + using UnityEngine; 4 + using Unity.Jobs; 5 + using Unity.Collections; 6 + 7 + namespace DanmakU { 8 + 9 + internal struct CollideDanamku : IJobParallelFor { 10 + 11 + public float Radius; 12 + 13 + [ReadOnly] public NativeArray<Vector2> Positions; 14 + [WriteOnly] public NativeArray<int> Collisions; 15 + 16 + public void Execute(int index) { 17 + var danmakuBounds = new Bounds(Positions[index], new Vector2(Radius, Radius)); 18 + Collisions[index] = DanmakuCollider.TestCollisions(danmakuBounds); 19 + } 20 + 21 + } 22 + 23 + }
+11
Assets/src/Core/Jobs/CollideDanamku.cs.meta
··· 1 + fileFormatVersion: 2 2 + guid: 197d036963b762647b81186b9a76a1bc 3 + MonoImporter: 4 + externalObjects: {} 5 + serializedVersion: 2 6 + defaultReferences: [] 7 + executionOrder: 0 8 + icon: {instanceID: 0} 9 + userData: 10 + assetBundleName: 11 + assetBundleVariant: