Newer
Older
DungeonShooting / DungeonShooting_Godot / src / framework / map / mark / ActivityMark.cs
@lijincheng lijincheng on 5 Jun 2023 11 KB 自动补全缺失属性
  1.  
  2. using System;
  3. using System.Collections;
  4. using System.Collections.Generic;
  5. using System.Reflection;
  6. using System.Text.RegularExpressions;
  7. using Godot;
  8.  
  9. /// <summary>
  10. /// 物体生成标记
  11. /// </summary>
  12. [Tool]
  13. public partial class ActivityMark : Node2D
  14. {
  15. /// <summary>
  16. /// 物体类型
  17. /// </summary>
  18. [Export]
  19. public ActivityIdPrefix.ActivityPrefixType Type = ActivityIdPrefix.ActivityPrefixType.NonePrefix;
  20.  
  21. /// <summary>
  22. /// 创建物体的表达式, 该表达式计算出的id会自动加上 Type 前缀
  23. /// 例如: 0001(w:100,ca:15,ra:30);0002(w:120,ca:10,ra:20)
  24. /// </summary>
  25. [Export(PropertyHint.Expression), ActivityExpression]
  26. public string ItemExpression;
  27.  
  28. /// <summary>
  29. /// 所在层级
  30. /// </summary>
  31. [Export]
  32. public RoomLayerEnum Layer = RoomLayerEnum.NormalLayer;
  33.  
  34. /// <summary>
  35. /// 该标记在第几波调用 BeReady,
  36. /// 一个房间内所以敌人清完即可进入下一波
  37. /// </summary>
  38. [Export]
  39. public int WaveNumber = 1;
  40.  
  41. /// <summary>
  42. /// 延时执行时间,单位:秒
  43. /// </summary>
  44. [Export]
  45. public float DelayTime = 0;
  46.  
  47. /// <summary>
  48. /// 物体会在该矩形区域内随机位置生成
  49. /// </summary>
  50. [Export]
  51. public Vector2I BirthRect = Vector2I.Zero;
  52. /// <summary>
  53. /// 绘制的颜色
  54. /// </summary>
  55. [Export]
  56. public Color DrawColor = new Color(1, 1, 1, 1);
  57.  
  58. /// <summary>
  59. /// 物体初始海拔高度
  60. /// </summary>
  61. [ExportGroup("Vertical")]
  62. [Export(PropertyHint.Range, "0, 128")]
  63. public int Altitude = 8;
  64.  
  65. /// <summary>
  66. /// 物体初始纵轴速度
  67. /// </summary>
  68. [Export(PropertyHint.Range, "-1000,1000,0.1")]
  69. public float VerticalSpeed = 0;
  70.  
  71. /// <summary>
  72. /// 当前标记所在Tile节点
  73. /// </summary>
  74. public TileMap TileRoot;
  75.  
  76. //是否已经结束
  77. private bool _isOver = true;
  78. private float _overTimer = 1;
  79. private float _timer = 0;
  80. private RoomInfo _tempRoom;
  81.  
  82. //已经计算好要生成的物体
  83. private Dictionary<string, ActivityExpressionData> _currentExpression = new Dictionary<string, ActivityExpressionData>();
  84.  
  85. //存储所有 ActivityMark 和子类中被 [ActivityExpression] 标记的字段名称
  86. private static Dictionary<Type, List<string>> _activityExpressionMap = new Dictionary<Type, List<string>>();
  87.  
  88. /// <summary>
  89. /// 对生成的物体执行后续操作
  90. /// </summary>
  91. public virtual void Doing(ActivityObjectResult<ActivityObject> result, RoomInfo roomInfo)
  92. {
  93. }
  94.  
  95. public ActivityMark()
  96. {
  97. //扫描所有 ActivityExpression
  98. var type = GetType();
  99. if (!_activityExpressionMap.ContainsKey(type))
  100. {
  101. // 获取类型信息
  102. var fieldInfos = new List<string>();
  103. var tempList = type.GetFields(BindingFlags.Instance | BindingFlags.Public);
  104. foreach (var s in tempList)
  105. {
  106. if (s.GetCustomAttribute<ActivityExpressionAttribute>() != null)
  107. {
  108. fieldInfos.Add(s.Name);
  109. }
  110. }
  111.  
  112. _activityExpressionMap.Add(type, fieldInfos);
  113. }
  114. }
  115. public override void _Process(double delta)
  116. {
  117. #if TOOLS
  118. if (Engine.IsEditorHint())
  119. {
  120. QueueRedraw();
  121. return;
  122. }
  123. #endif
  124. if (_isOver)
  125. {
  126. _overTimer += (float)delta;
  127. if (_overTimer >= 1)
  128. {
  129. SetActive(false);
  130. }
  131. }
  132. else
  133. {
  134. if (DelayTime > 0)
  135. {
  136. _timer += (float)delta;
  137. if (_timer >= DelayTime)
  138. {
  139. Doing(_tempRoom);
  140. _tempRoom = null;
  141. _isOver = true;
  142. }
  143. }
  144. }
  145. }
  146.  
  147. /// <summary>
  148. /// 标记准备好了
  149. /// </summary>
  150. public void BeReady(RoomInfo roomInfo)
  151. {
  152. if (_currentExpression == null || Type == ActivityIdPrefix.ActivityPrefixType.Player)
  153. {
  154. return;
  155. }
  156. _isOver = false;
  157. _overTimer = 0;
  158. SetActive(true);
  159. if (DelayTime <= 0)
  160. {
  161. Doing(roomInfo);
  162. _isOver = true;
  163. }
  164. else
  165. {
  166. _timer = 0;
  167. _tempRoom = roomInfo;
  168. }
  169. }
  170.  
  171. /// <summary>
  172. /// 是否已经结束
  173. /// </summary>
  174. public bool IsOver()
  175. {
  176. return _isOver && _overTimer >= 1;
  177. }
  178.  
  179. private void Doing(RoomInfo roomInfo)
  180. {
  181. var result = CreateActivityObjectFromExpression<ActivityObject>(Type, nameof(ItemExpression));
  182.  
  183. if (result == null || result.ActivityObject == null)
  184. {
  185. return;
  186. }
  187. result.ActivityObject.VerticalSpeed = VerticalSpeed;
  188. result.ActivityObject.Altitude = Altitude;
  189. var pos = Position;
  190. if (BirthRect != Vector2I.Zero)
  191. {
  192. result.ActivityObject.Position = new Vector2(
  193. Utils.RandomRangeInt((int)pos.X - BirthRect.X / 2, (int)pos.X + BirthRect.X / 2),
  194. Utils.RandomRangeInt((int)pos.Y - BirthRect.Y / 2, (int)pos.Y + BirthRect.Y / 2)
  195. );
  196. }
  197. else
  198. {
  199. result.ActivityObject.Position = pos;
  200. }
  201.  
  202. result.ActivityObject.StartCoroutine(OnActivityObjectBirth(result.ActivityObject));
  203. result.ActivityObject.PutDown(Layer);
  204. var effect1 = ResourceManager.LoadAndInstantiate<Effect1>(ResourcePath.prefab_effect_Effect1_tscn);
  205. effect1.Position = result.ActivityObject.Position + new Vector2(0, -Altitude);
  206. effect1.AddToActivityRoot(RoomLayerEnum.NormalLayer);
  207. Doing(result, roomInfo);
  208. }
  209.  
  210. /// <summary>
  211. /// 生成 ActivityObject 时调用, 用于出生时的动画效果
  212. /// </summary>
  213. private IEnumerator OnActivityObjectBirth(ActivityObject instance)
  214. {
  215. var a = 1.0f;
  216. instance.SetBlendColor(Colors.White);
  217. //禁用自定义行为
  218. instance.EnableCustomBehavior = false;
  219. //禁用下坠
  220. instance.EnableVerticalMotion = false;
  221.  
  222. for (var i = 0; i < 10; i++)
  223. {
  224. instance.SetBlendSchedule(a);
  225. yield return 0;
  226. }
  227. while (a > 0)
  228. {
  229. instance.SetBlendSchedule(a);
  230. a -= 0.05f;
  231. yield return 0;
  232. }
  233. //启用自定义行为
  234. instance.EnableCustomBehavior = true;
  235. //启用下坠
  236. instance.EnableVerticalMotion = true;
  237. }
  238.  
  239. #if TOOLS
  240. public override void _Draw()
  241. {
  242. if (Engine.IsEditorHint() || GameApplication.Instance.Debug)
  243. {
  244. var drawColor = DrawColor;
  245.  
  246. //如果在编辑器中选中了该节点, 则绘更改绘制颜色的透明度
  247. var selectedNodes = Plugin.Plugin.Instance?.GetEditorInterface()?.GetSelection()?.GetSelectedNodes();
  248. if (selectedNodes != null && selectedNodes.Contains(this))
  249. {
  250. drawColor.A = 1f;
  251. }
  252. else
  253. {
  254. drawColor.A = 0.5f;
  255. }
  256. DrawLine(new Vector2(-2, -2), new Vector2(2, 2), drawColor, 1f);
  257. DrawLine(new Vector2(-2, 2), new Vector2(2, -2), drawColor, 1f);
  258.  
  259. if (BirthRect != Vector2.Zero)
  260. {
  261. DrawRect(new Rect2(-BirthRect / 2, BirthRect), drawColor, false, 0.5f);
  262. }
  263. DrawString(ResourceManager.DefaultFont12Px, new Vector2(-14, 12), WaveNumber.ToString(), HorizontalAlignment.Center, 28, 12);
  264. }
  265. }
  266. #endif
  267.  
  268. /// <summary>
  269. /// 设置当前节点是否是活动状态
  270. /// </summary>
  271. private void SetActive(bool flag)
  272. {
  273. // SetProcess(flag);
  274. // SetPhysicsProcess(flag);
  275. // SetProcessInput(flag);
  276. // Visible = flag;
  277. var parent = GetParent();
  278. if (flag)
  279. {
  280. if (parent == null)
  281. {
  282. TileRoot.AddChild(this);
  283. }
  284. else if (parent != TileRoot)
  285. {
  286. parent.RemoveChild(this);
  287. TileRoot.AddChild(this);
  288. }
  289. Owner = TileRoot;
  290. }
  291. else
  292. {
  293. if (parent != null)
  294. {
  295. parent.RemoveChild(this);
  296. Owner = null;
  297. }
  298. }
  299. }
  300.  
  301. //-----------------------------------------------------------------------------------------------------
  302.  
  303. /// <summary>
  304. /// 执行预处理操作
  305. /// </summary>
  306. public void Pretreatment()
  307. {
  308. if (_activityExpressionMap.TryGetValue(GetType(), out var list))
  309. {
  310. foreach (var field in list)
  311. {
  312. Pretreatment(field);
  313. }
  314. }
  315. }
  316.  
  317. private void Pretreatment(string field)
  318. {
  319. var expressionStr = GetType().GetField(field)?.GetValue(this) as string;
  320. if (string.IsNullOrEmpty(expressionStr))
  321. {
  322. _currentExpression.Add(field, new ActivityExpressionData(""));
  323. return;
  324. }
  325. var activityExpression = Parse(expressionStr);
  326. if (activityExpression.Count > 0)
  327. {
  328. //权重列表
  329. var list = new List<int>();
  330. for (var i = 0; i < activityExpression.Count; i++)
  331. {
  332. var item = activityExpression[i];
  333. if (item.Args.TryGetValue("weight", out var weight)) //获取自定义权重值
  334. {
  335. list.Add(int.Parse(weight));
  336. }
  337. else //默认权重100
  338. {
  339. item.Args.Add("weight", "100");
  340. list.Add(100);
  341. }
  342. }
  343. //根据权重随机值
  344. var index = Utils.RandomWeight(list);
  345. _currentExpression.Add(field, activityExpression[index]);
  346. }
  347. else
  348. {
  349. _currentExpression.Add(field, new ActivityExpressionData(""));
  350. }
  351. }
  352. private List<ActivityExpressionData> Parse(string str)
  353. {
  354. var list = new List<ActivityExpressionData>();
  355. var exps = str.Split(';');
  356. for (var i = 0; i < exps.Length; i++)
  357. {
  358. var exp = exps[i];
  359. //去除空格
  360. exp = Regex.Replace(exp, "\\s", "");
  361. if (string.IsNullOrEmpty(exp))
  362. {
  363. continue;
  364. }
  365. //验证语法
  366. if (Regex.IsMatch(exp, "^\\w+(\\((\\w+:\\w+)*(,\\w+:\\w+)*\\))?$"))
  367. {
  368. if (!exp.Contains('(')) //没有参数
  369. {
  370. list.Add(new ActivityExpressionData(exp));
  371. }
  372. else
  373. {
  374. var name = Regex.Match(exp, "^\\w+").Value;
  375. var activityExpression = new ActivityExpressionData(name);
  376. var paramsResult = Regex.Matches(exp, "\\w+:\\w+");
  377. if (paramsResult.Count > 0)
  378. {
  379. foreach (Match result in paramsResult)
  380. {
  381. var valSplit = result.Value.Split(':');
  382. activityExpression.Args.Add(valSplit[0], valSplit[1]);
  383. }
  384. }
  385. list.Add(activityExpression);
  386. }
  387. }
  388. else //语法异常
  389. {
  390. throw new Exception("表达式语法错误: " + exp);
  391. }
  392. }
  393.  
  394. return list;
  395. }
  396. }