···5566namespace DanmakU {
7788+[CanEditMultipleObjects]
89[CustomPropertyDrawer(typeof(Range))]
99-public class RangeDrawer : PropertyDrawer {
1010+internal class RangeDrawer : PropertyDrawer {
10111112 const float buttonSize = 30f;
12131314 Dictionary<string, bool> _propertyType;
14151516 public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) {
1616- var fieldPosition = position;
1717- var buttonPosition = position;
1818- fieldPosition.width -= buttonSize;
1919- buttonPosition.x += fieldPosition.width;
2020- buttonPosition.width = buttonSize;
2121-2217 var min = property.FindPropertyRelative("_min");
2318 var max = property.FindPropertyRelative("_max");
24192525- if (_propertyType == null)
2626- _propertyType = new Dictionary<string, bool>();
2020+ _propertyType = _propertyType ?? (_propertyType = new Dictionary<string, bool>());
27212822 bool isRange;
2923 if (!_propertyType.TryGetValue(property.propertyPath, out isRange)) {
···3125 _propertyType.Add(property.propertyPath, isRange);
3226 }
33272828+ _propertyType[property.propertyPath] = DrawRangeEditor(position, property, label, isRange);
2929+ }
3030+3131+ static bool DrawRangeEditor(Rect position, SerializedProperty property, GUIContent label, bool isRange) {
3232+ var fieldPosition = position;
3333+ var buttonPosition = position;
3434+ fieldPosition.width -= buttonSize;
3535+ buttonPosition.x += fieldPosition.width;
3636+ buttonPosition.width = buttonSize;
3737+3838+ var min = property.FindPropertyRelative("_min");
3939+ var max = property.FindPropertyRelative("_max");
4040+4141+ EditorGUI.showMixedValue = property.hasMultipleDifferentValues;
3442 EditorGUI.BeginProperty(position, label, property);
3543 if (isRange) {
3636- var values = new[] { min.floatValue, max.floatValue };
3737- EditorGUI.MultiFloatField(fieldPosition, label,
3838- new[] { new GUIContent("-"), new GUIContent("+")},
3939- values);
4040- min.floatValue = values[0];
4141- max.floatValue = values[1];
4444+ MultiFloatField(fieldPosition, label,
4545+ new[] { new GUIContent("-"), new GUIContent("+")},
4646+ new[] { min, max });
4247 } else {
4343- var value = EditorGUI.FloatField(fieldPosition, label ,min.floatValue);
4848+ var multiEditing = min.hasMultipleDifferentValues || max.hasMultipleDifferentValues;
4949+ EditorGUI.showMixedValue = multiEditing;
5050+ var value = EditorGUI.FloatField(fieldPosition, label ,min.floatValue);
5151+ if (!min.hasMultipleDifferentValues) {
4452 min.floatValue = value;
4553 max.floatValue = value;
5454+ }
4655 }
5656+ EditorGUI.showMixedValue = false;
4757 if (GUI.Button(buttonPosition, isRange ? "\u2194" : "\u2022")) {
4858 isRange = !isRange;
4959 if (!isRange) {
···5161 min.floatValue = average;
5262 max.floatValue = average;
5363 }
5454- _propertyType[property.propertyPath] = isRange;
5564 }
5665 EditorGUI.EndProperty();
6666+ return isRange;
6767+ }
6868+6969+ static void MultiFloatField(Rect position, GUIContent label, GUIContent[] subLabels, SerializedProperty[] properties) {
7070+ int controlId = GUIUtility.GetControlID("foldout".GetHashCode(), FocusType.Passive, position);
7171+ position = MultiFieldPrefixLabel(position, controlId, label, subLabels.Length);
7272+ position.height = 16f;
7373+ MultiFloatField(position, subLabels, properties);
7474+ }
7575+7676+ static void MultiFloatField(Rect position, GUIContent[] subLabels, SerializedProperty[] properties) {
7777+ int length = properties.Length;
7878+ float num = (position.width - (float) (length - 1) * 2f) / (float) length;
7979+ Rect position1 = new Rect(position);
8080+ position1.width = num;
8181+ float labelWidth1 = EditorGUIUtility.labelWidth;
8282+ int indentLevel = EditorGUI.indentLevel;
8383+ EditorGUIUtility.labelWidth = 13f;
8484+ EditorGUI.indentLevel = 0;
8585+ for (int index = 0; index < properties.Length; ++index) {
8686+ EditorGUI.PropertyField(position1, properties[index], subLabels[index], false);
8787+ position1.x += num + 2f;
8888+ }
8989+ EditorGUIUtility.labelWidth = labelWidth1;
9090+ EditorGUI.indentLevel = indentLevel;
9191+ }
9292+9393+ static bool LabelHasContent(GUIContent label) {
9494+ if (label == null || label.text != string.Empty)
9595+ return true;
9696+ return label.image != null;
9797+ }
9898+9999+ static Rect MultiFieldPrefixLabel(Rect totalPosition, int id, GUIContent label, int columns) {
100100+ if (!LabelHasContent(label))
101101+ return EditorGUI.IndentedRect(totalPosition);
102102+ var indent = EditorGUI.indentLevel * 15f;
103103+ if (EditorGUIUtility.wideMode) {
104104+ Rect labelPosition = new Rect(totalPosition.x + indent, totalPosition.y, EditorGUIUtility.labelWidth - indent, 16f);
105105+ Rect rect = totalPosition;
106106+ rect.xMin += EditorGUIUtility.labelWidth;
107107+ if (columns > 1) {
108108+ --labelPosition.width;
109109+ --rect.xMin;
110110+ }
111111+ if (columns == 2) {
112112+ float num = (float) (((double) rect.width - 4.0) / 3.0);
113113+ rect.xMax -= num + 2f;
114114+ }
115115+ EditorGUI.HandlePrefixLabel(totalPosition, labelPosition, label, id);
116116+ return rect;
117117+ }
118118+ Rect labelPosition1 = new Rect(totalPosition.x + indent, totalPosition.y, totalPosition.width - indent, 16f);
119119+ Rect rect1 = totalPosition;
120120+ rect1.xMin += indent + 15f;
121121+ rect1.yMin += 16f;
122122+ EditorGUI.HandlePrefixLabel(totalPosition, labelPosition1, label, id);
123123+ return rect1;
57124 }
5812559126}
+1-2
Assets/DanmakU/Runtime/Core/DanmakuPool.cs
···163163 var count = ActiveCount;
164164 if (count <= 0) return dependency;
165165 new NativeSlice<Vector2>(OldPositions, 0, count).CopyFrom(new NativeSlice<Vector2>(Positions, 0, count));
166166- var rotate = new RotateDanmaku(this).Schedule(count, kBatchSize, dependency);
167167- var move = new MoveDanmaku(this).Schedule(count, kBatchSize, rotate);
166166+ var move = new MoveDanmaku(this).Schedule(count, kBatchSize, dependency);
168167 var boundsCheck = new BoundsCheckDanmaku(this).Schedule(count, kBatchSize, move);
169168 var transforms = new ComputeDanmakuTranforms(this).Schedule(count, kBatchSize, move);
170169 dependency = JobHandle.CombineDependencies(boundsCheck, transforms);
···11+using System.Collections;
22+using System.Collections.Generic;
33+using DanmakU.Fireables;
44+using UnityEngine;
55+66+namespace DanmakU {
77+88+[AddComponentMenu("DanmakU/Danmaku Emitter")]
99+public class DanmakuEmitter : DanmakuBehaviour {
1010+1111+ public DanmakuPrefab DanmakuType;
1212+1313+ public Range Speed = 5f;
1414+ public Range AngularSpeed;
1515+ public Color Color = Color.white;
1616+ public Range FireRate = 5;
1717+ public float FrameRate;
1818+ public Arc Arc;
1919+ public Line Line;
2020+2121+ float timer;
2222+ DanmakuConfig config;
2323+ IFireable fireable;
2424+2525+ /// <summary>
2626+ /// Start is called on the frame when a script is enabled just before
2727+ /// any of the Update methods is called the first time.
2828+ /// </summary>
2929+ void Start() {
3030+ if (DanmakuType == null) {
3131+ Debug.LogWarning($"Emitter doesn't have a valid DanmakuPrefab", this);
3232+ return;
3333+ }
3434+ var set = CreateSet(DanmakuType);
3535+ set.AddModifiers(GetComponents<IDanmakuModifier>());
3636+ fireable = Arc.Of(Line).Of(set);
3737+ }
3838+3939+ /// <summary>
4040+ /// Update is called every frame, if the MonoBehaviour is enabled.
4141+ /// </summary>
4242+ void Update() {
4343+ if (fireable == null) return;
4444+ var deltaTime = Time.deltaTime;
4545+ if (FrameRate > 0) {
4646+ deltaTime = 1f / FrameRate;
4747+ }
4848+ timer -= deltaTime;
4949+ if (timer < 0) {
5050+ config = new DanmakuConfig {
5151+ Position = transform.position,
5252+ Rotation = transform.rotation.eulerAngles.z * Mathf.Deg2Rad,
5353+ Speed = Speed,
5454+ AngularSpeed = AngularSpeed,
5555+ Color = Color
5656+ };
5757+ fireable.Fire(config);
5858+ timer = 1f / FireRate.GetValue();
5959+ }
6060+ }
6161+6262+}
6363+6464+}
···1010public struct DanmakuConfig {
11111212 public Vector2 Position;
1313- public Range Rotation;
1313+ [Radians] public Range Rotation;
1414 public Range Speed;
1515- public Range AngularSpeed;
1515+ [Radians] public Range AngularSpeed;
1616 public Color Color;
17171818 /// <summary>
···3737[Serializable]
3838public struct DanmakuState {
3939 public Vector2 Position;
4040- public float Rotation;
4040+ [Radians] public float Rotation;
4141 public float Speed;
4242- public float AngularSpeed;
4242+ [Radians] public float AngularSpeed;
4343 public Color Color;
4444}
4545
+11-6
Assets/DanmakU/Runtime/Fireables/Shapes/Arc.cs
···77[Serializable]
88public class Arc : Fireable {
991010- public Range Count;
1111- public Range ArcLength;
1010+ public Range Count = 1;
1111+ [Radians] public Range ArcLength;
1212 public Range Radius;
13131414 public Arc(Range count, Range arcLength, Range radius) {
···2020 public override void Fire(DanmakuConfig state) {
2121 float radius = Radius.GetValue();
2222 int count = Mathf.RoundToInt(Count.GetValue());
2323+ if (count == 0) return;
2424+ if (count == 1) {
2525+ Subfire(state);
2626+ return;
2727+ }
2328 float arcLength = ArcLength.GetValue();
2429 var rotation = state.Rotation.GetValue();
2530 var start = rotation - arcLength / 2;
2626- var currentState = state;
2731 for (int i = 0; i < count; i++) {
2828- var angle = start + i * (arcLength / count);
2929- state.Position = state.Position + (radius * RotationUtiliity.ToUnitVector(angle));
3030- state.Rotation = angle;
3232+ var angle = start + i * (arcLength / (count - 1));
3333+ var currentState = state;
3434+ currentState.Position = state.Position + (radius * RotationUtiliity.ToUnitVector(angle));
3535+ currentState.Rotation = angle;
3136 Subfire(currentState);
3237 }
3338 }
+1-1
Assets/DanmakU/Runtime/Fireables/Shapes/Circle.cs
···88[Serializable]
99public class Circle : Fireable {
10101111- public Range Count;
1111+ public Range Count = 1;
1212 public Range Radius;
13131414 public Circle(Range count, Range radius) {
+23
Assets/DanmakU/Runtime/Fireables/Shapes/Line.cs
···11+using System;
22+using UnityEngine;
33+44+namespace DanmakU.Fireables {
55+66+[Serializable]
77+public class Line : Fireable {
88+99+ public Range Count = 1;
1010+ public Range DeltaSpeed;
1111+1212+ public override void Fire(DanmakuConfig config) {
1313+ var count = Mathf.RoundToInt(Count.GetValue());
1414+ var deltaSpeed = DeltaSpeed.GetValue();
1515+ for (var i = 0; i < count; i++) {
1616+ config.Speed += deltaSpeed;
1717+ Subfire(config);
1818+ }
1919+ }
2020+2121+}
2222+2323+}
+1-1
Assets/DanmakU/Runtime/Fireables/Shapes/Ring.cs
···88[Serializable]
99public class Ring : Fireable {
10101111- public Range Count;
1111+ public Range Count = 1;
1212 public Range Radius;
13131414 public Ring(Range count, Range radius) {