Newer
Older
DungeonShooting / DungeonShooting_Godot / src / framework / map / mark / ActivityMark.cs
  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 static Font _drawFont;
  84.  
  85. //已经计算好要生成的物体
  86. private Dictionary<string, ActivityExpressionData> _currentExpression = new Dictionary<string, ActivityExpressionData>();
  87.  
  88. //存储所有 ActivityMark 和子类中被 [ActivityExpression] 标记的字段名称
  89. private static Dictionary<Type, List<string>> _activityExpressionMap = new Dictionary<Type, List<string>>();
  90.  
  91. /// <summary>
  92. /// 对生成的物体执行后续操作
  93. /// </summary>
  94. public virtual void Doing(ActivityObjectResult<ActivityObject> result, RoomInfo roomInfo)
  95. {
  96. }
  97.  
  98. public ActivityMark()
  99. {
  100. //扫描所有 ActivityExpression
  101. var type = GetType();
  102. if (!_activityExpressionMap.ContainsKey(type))
  103. {
  104. // 获取类型信息
  105. var fieldInfos = new List<string>();
  106. var tempList = type.GetFields(BindingFlags.Instance | BindingFlags.Public);
  107. foreach (var s in tempList)
  108. {
  109. if (s.GetCustomAttribute<ActivityExpression>() != null)
  110. {
  111. fieldInfos.Add(s.Name);
  112. }
  113. }
  114.  
  115. _activityExpressionMap.Add(type, fieldInfos);
  116. }
  117. }
  118. public override void _Process(double delta)
  119. {
  120. #if TOOLS
  121. if (Engine.IsEditorHint())
  122. {
  123. QueueRedraw();
  124. return;
  125. }
  126. #endif
  127. if (_isOver)
  128. {
  129. _overTimer += (float)delta;
  130. if (_overTimer >= 1)
  131. {
  132. SetActive(false);
  133. }
  134. }
  135. else
  136. {
  137. if (DelayTime > 0)
  138. {
  139. _timer += (float)delta;
  140. if (_timer >= DelayTime)
  141. {
  142. Doing(_tempRoom);
  143. _tempRoom = null;
  144. _isOver = true;
  145. }
  146. }
  147. }
  148. }
  149.  
  150. /// <summary>
  151. /// 标记准备好了
  152. /// </summary>
  153. public void BeReady(RoomInfo roomInfo)
  154. {
  155. if (_currentExpression == null || Type == ActivityIdPrefix.ActivityPrefixType.Player)
  156. {
  157. return;
  158. }
  159. _isOver = false;
  160. _overTimer = 0;
  161. SetActive(true);
  162. if (DelayTime <= 0)
  163. {
  164. Doing(roomInfo);
  165. _isOver = true;
  166. }
  167. else
  168. {
  169. _timer = 0;
  170. _tempRoom = roomInfo;
  171. }
  172. }
  173.  
  174. /// <summary>
  175. /// 是否已经结束
  176. /// </summary>
  177. public bool IsOver()
  178. {
  179. return _isOver && _overTimer >= 1;
  180. }
  181.  
  182. private void Doing(RoomInfo roomInfo)
  183. {
  184. var result = CreateActivityObjectFromExpression<ActivityObject>(Type, nameof(ItemExpression));
  185.  
  186. if (result == null || result.ActivityObject == null)
  187. {
  188. return;
  189. }
  190. result.ActivityObject.VerticalSpeed = VerticalSpeed;
  191. result.ActivityObject.Altitude = Altitude;
  192. var pos = Position;
  193. if (BirthRect != Vector2I.Zero)
  194. {
  195. result.ActivityObject.Position = new Vector2(
  196. Utils.RandomRangeInt((int)pos.X - BirthRect.X / 2, (int)pos.X + BirthRect.X / 2),
  197. Utils.RandomRangeInt((int)pos.Y - BirthRect.Y / 2, (int)pos.Y + BirthRect.Y / 2)
  198. );
  199. }
  200. else
  201. {
  202. result.ActivityObject.Position = pos;
  203. }
  204.  
  205. result.ActivityObject.StartCoroutine(OnActivityObjectBirth(result.ActivityObject));
  206. result.ActivityObject.PutDown(Layer);
  207. var effect1 = ResourceManager.LoadAndInstantiate<Effect1>(ResourcePath.prefab_effect_Effect1_tscn);
  208. effect1.Position = result.ActivityObject.Position + new Vector2(0, -Altitude);
  209. effect1.AddToActivityRoot(RoomLayerEnum.NormalLayer);
  210. Doing(result, roomInfo);
  211. }
  212.  
  213. /// <summary>
  214. /// 生成 ActivityObject 时调用, 用于出生时的动画效果
  215. /// </summary>
  216. private IEnumerator OnActivityObjectBirth(ActivityObject instance)
  217. {
  218. var a = 1.0f;
  219. instance.SetBlendColor(Colors.White);
  220. //禁用自定义行为
  221. instance.EnableCustomBehavior = false;
  222. //禁用下坠
  223. instance.EnableVerticalMotion = false;
  224.  
  225. for (var i = 0; i < 10; i++)
  226. {
  227. instance.SetBlendSchedule(a);
  228. yield return 0;
  229. }
  230. while (a > 0)
  231. {
  232. instance.SetBlendSchedule(a);
  233. a -= 0.05f;
  234. yield return 0;
  235. }
  236. //启用自定义行为
  237. instance.EnableCustomBehavior = true;
  238. //启用下坠
  239. instance.EnableVerticalMotion = true;
  240. }
  241.  
  242. #if TOOLS
  243. public override void _Draw()
  244. {
  245. if (Engine.IsEditorHint() || GameApplication.Instance.Debug)
  246. {
  247. var drawColor = DrawColor;
  248.  
  249. //如果在编辑器中选中了该节点, 则绘更改绘制颜色的透明度
  250. var selectedNodes = Plugin.Plugin.Instance?.GetEditorInterface()?.GetSelection()?.GetSelectedNodes();
  251. if (selectedNodes != null && selectedNodes.Contains(this))
  252. {
  253. drawColor.A = 1f;
  254. }
  255. else
  256. {
  257. drawColor.A = 0.5f;
  258. }
  259. DrawLine(new Vector2(-2, -2), new Vector2(2, 2), drawColor, 1f);
  260. DrawLine(new Vector2(-2, 2), new Vector2(2, -2), drawColor, 1f);
  261.  
  262. if (BirthRect != Vector2.Zero)
  263. {
  264. DrawRect(new Rect2(-BirthRect / 2, BirthRect), drawColor, false, 0.5f);
  265. }
  266.  
  267. if (_drawFont == null)
  268. {
  269. _drawFont = ResourceManager.Load<Font>(ResourcePath.Silver_ttf);
  270. }
  271. DrawString(_drawFont, new Vector2(-14, 12), WaveNumber.ToString(), HorizontalAlignment.Center, 28, 14);
  272. }
  273. }
  274. #endif
  275.  
  276. /// <summary>
  277. /// 设置当前节点是否是活动状态
  278. /// </summary>
  279. private void SetActive(bool flag)
  280. {
  281. // SetProcess(flag);
  282. // SetPhysicsProcess(flag);
  283. // SetProcessInput(flag);
  284. // Visible = flag;
  285. var parent = GetParent();
  286. if (flag)
  287. {
  288. if (parent == null)
  289. {
  290. TileRoot.AddChild(this);
  291. }
  292. else if (parent != TileRoot)
  293. {
  294. parent.RemoveChild(this);
  295. TileRoot.AddChild(this);
  296. }
  297. Owner = TileRoot;
  298. }
  299. else
  300. {
  301. if (parent != null)
  302. {
  303. parent.RemoveChild(this);
  304. Owner = null;
  305. }
  306. }
  307. }
  308.  
  309. //-----------------------------------------------------------------------------------------------------
  310.  
  311. /// <summary>
  312. /// 执行预处理操作
  313. /// </summary>
  314. public void Pretreatment()
  315. {
  316. if (_activityExpressionMap.TryGetValue(GetType(), out var list))
  317. {
  318. foreach (var field in list)
  319. {
  320. Pretreatment(field);
  321. }
  322. }
  323. }
  324.  
  325. private void Pretreatment(string field)
  326. {
  327. var expressionStr = GetType().GetField(field)?.GetValue(this) as string;
  328. if (string.IsNullOrEmpty(expressionStr))
  329. {
  330. _currentExpression.Add(field, new ActivityExpressionData(""));
  331. return;
  332. }
  333. var activityExpression = Parse(expressionStr);
  334. if (activityExpression.Count > 0)
  335. {
  336. //权重列表
  337. var list = new List<int>();
  338. for (var i = 0; i < activityExpression.Count; i++)
  339. {
  340. var item = activityExpression[i];
  341. if (item.Args.TryGetValue("weight", out var weight)) //获取自定义权重值
  342. {
  343. list.Add(int.Parse(weight));
  344. }
  345. else //默认权重100
  346. {
  347. item.Args.Add("weight", "100");
  348. list.Add(100);
  349. }
  350. }
  351. //根据权重随机值
  352. var index = Utils.RandomWeight(list);
  353. _currentExpression.Add(field, activityExpression[index]);
  354. }
  355. else
  356. {
  357. _currentExpression.Add(field, new ActivityExpressionData(""));
  358. }
  359. }
  360. private List<ActivityExpressionData> Parse(string str)
  361. {
  362. var list = new List<ActivityExpressionData>();
  363. var exps = str.Split(';');
  364. for (var i = 0; i < exps.Length; i++)
  365. {
  366. var exp = exps[i];
  367. //去除空格
  368. exp = Regex.Replace(exp, "\\s", "");
  369. if (string.IsNullOrEmpty(exp))
  370. {
  371. continue;
  372. }
  373. //验证语法
  374. if (Regex.IsMatch(exp, "^\\w+(\\((\\w+:\\w+)*(,\\w+:\\w+)*\\))?$"))
  375. {
  376. if (!exp.Contains('(')) //没有参数
  377. {
  378. list.Add(new ActivityExpressionData(exp));
  379. }
  380. else
  381. {
  382. var name = Regex.Match(exp, "^\\w+").Value;
  383. var activityExpression = new ActivityExpressionData(name);
  384. var paramsResult = Regex.Matches(exp, "\\w+:\\w+");
  385. if (paramsResult.Count > 0)
  386. {
  387. foreach (Match result in paramsResult)
  388. {
  389. var valSplit = result.Value.Split(':');
  390. activityExpression.Args.Add(valSplit[0], valSplit[1]);
  391. }
  392. }
  393. list.Add(activityExpression);
  394. }
  395. }
  396. else //语法异常
  397. {
  398. throw new Exception("表达式语法错误: " + exp);
  399. }
  400. }
  401.  
  402. return list;
  403. }
  404. }