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