Newer
Older
DungeonShooting / src / weapon / gun / Gun.cs
  1. using Godot;
  2. using System;
  3.  
  4. /// <summary>
  5. /// 枪的基类
  6. /// </summary>
  7. public abstract class Gun : Node2D
  8. {
  9. /// <summary>
  10. /// 开火回调事件
  11. /// </summary>
  12. public event Action<Gun> FireEvent;
  13.  
  14. /// <summary>
  15. /// 属性数据
  16. /// </summary>
  17. public GunAttribute Attribute
  18. {
  19. get
  20. {
  21. if (_attribute == null)
  22. {
  23. throw new Exception("请先调用Init来初始化枪的属性");
  24. }
  25. return _attribute;
  26. }
  27. private set => _attribute = value;
  28. }
  29. private GunAttribute _attribute;
  30.  
  31. /// <summary>
  32. /// 枪的图片
  33. /// </summary>
  34. public Sprite GunSprite { get; private set; }
  35.  
  36. /// <summary>
  37. /// 动画播放器
  38. /// </summary>
  39. /// <value></value>
  40. public AnimationPlayer AnimationPlayer { get; private set; }
  41.  
  42. /// <summary>
  43. /// 枪攻击的目标阵营
  44. /// </summary>
  45. public CampEnum TargetCamp { get; set; }
  46.  
  47. /// <summary>
  48. /// 该武器的拥有者
  49. /// </summary>
  50. public Role Master { get; private set; }
  51.  
  52. /// <summary>
  53. /// 枪管的开火点
  54. /// </summary>
  55. public Position2D FirePoint { get; private set; }
  56. /// <summary>
  57. /// 枪管的原点
  58. /// </summary>
  59. public Position2D OriginPoint { get; private set; }
  60. /// <summary>
  61. /// 弹壳抛出的点
  62. /// </summary>
  63. public Position2D ShellPoint { get; private set; }
  64. /// <summary>
  65. /// 枪的当前散射半径
  66. /// </summary>
  67. public float CurrScatteringRange { get; private set; } = 0;
  68.  
  69. //是否按下
  70. private bool triggerFlag = false;
  71. //扳机计时器
  72. private float triggerTimer = 0;
  73. //开火前延时时间
  74. private float delayedTime = 0;
  75. //开火间隙时间
  76. private float fireInterval = 0;
  77. //开火枪口角度
  78. private float fireAngle = 0;
  79. //攻击冷却计时
  80. private float attackTimer = 0;
  81. //攻击状态
  82. private bool attackFlag = false;
  83. //按下的时间
  84. private float downTimer = 0;
  85. //松开的时间
  86. private float upTimer = 0;
  87. //连发次数
  88. private float continuousCount = 0;
  89. private bool continuousShootFlag = false;
  90.  
  91. //状态 0 在地上, 1 被拾起
  92. private int _state = 0;
  93.  
  94. public override void _Process(float delta)
  95. {
  96. if (Master == null) //这把武器被扔在地上
  97. {
  98.  
  99. }
  100. else if (Master.Holster.ActiveGun != this) //当前武器没有被使用
  101. {
  102. triggerTimer = triggerTimer > 0 ? triggerTimer - delta : 0;
  103. triggerFlag = false;
  104. attackFlag = false;
  105. attackTimer = attackTimer > 0 ? attackTimer - delta : 0;
  106. continuousCount = 0;
  107. delayedTime = 0;
  108. }
  109. else //正在使用中
  110. {
  111. if (triggerFlag)
  112. {
  113. if (upTimer > 0) //第一帧按下扳机
  114. {
  115. upTimer = 0;
  116. DownTrigger();
  117. }
  118. downTimer += delta;
  119. }
  120. else
  121. {
  122. if (downTimer > 0) //第一帧松开扳机
  123. {
  124. downTimer = 0;
  125. UpTriggern();
  126. }
  127. upTimer += delta;
  128. }
  129.  
  130. // 攻击的计时器
  131. if (attackTimer > 0)
  132. {
  133. attackTimer -= delta;
  134. if (attackTimer < 0)
  135. {
  136. delayedTime += attackTimer;
  137. attackTimer = 0;
  138. }
  139. }
  140. else if (delayedTime > 0) //攻击延时
  141. {
  142. delayedTime -= delta;
  143. if (attackTimer < 0)
  144. {
  145. delayedTime = 0;
  146. }
  147. }
  148.  
  149. //连发判断
  150. if (continuousCount > 0 && delayedTime <= 0 && attackTimer <= 0)
  151. {
  152. TriggernFire();
  153. }
  154.  
  155. if (!attackFlag && attackTimer <= 0)
  156. {
  157. CurrScatteringRange = Mathf.Max(CurrScatteringRange - Attribute.ScatteringRangeBackSpeed * delta, Attribute.StartScatteringRange);
  158. }
  159. triggerTimer = triggerTimer > 0 ? triggerTimer - delta : 0;
  160. triggerFlag = false;
  161. attackFlag = false;
  162.  
  163. //枪身回归
  164. Position = Position.MoveToward(Vector2.Zero, 35 * delta);
  165. if (fireInterval == 0)
  166. {
  167. RotationDegrees = 0;
  168. }
  169. else
  170. {
  171. RotationDegrees = Mathf.Lerp(0, fireAngle, attackTimer / fireInterval);
  172. }
  173. }
  174. }
  175.  
  176. public void Init(GunAttribute attribute)
  177. {
  178. if (_attribute != null)
  179. {
  180. throw new Exception("当前武器已经初始化过了!");
  181. }
  182.  
  183. GunSprite = GetNode<Sprite>("GunSprite");
  184. FirePoint = GetNode<Position2D>("FirePoint");
  185. OriginPoint = GetNode<Position2D>("OriginPoint");
  186. ShellPoint = GetNode<Position2D>("ShellPoint");
  187. AnimationPlayer = GetNode<AnimationPlayer>("AnimationPlayer");
  188.  
  189. Attribute = attribute;
  190. //更新图片
  191. GunSprite.Texture = attribute.Sprite;
  192. GunSprite.Position = Attribute.CenterPosition;
  193. //开火位置
  194. FirePoint.Position = new Vector2(attribute.FirePosition.x, -attribute.FirePosition.y);
  195. OriginPoint.Position = new Vector2(0, -attribute.FirePosition.y);
  196.  
  197. Init();
  198. }
  199.  
  200. /// <summary>
  201. /// 扳机函数, 调用即视为扣动扳机
  202. /// </summary>
  203. public void Trigger()
  204. {
  205. //是否第一帧按下
  206. var justDown = downTimer == 0;
  207. //是否能发射
  208. var flag = false;
  209. if (continuousCount <= 0) //不能处于连发状态下
  210. {
  211. if (Attribute.ContinuousShoot) //自动射击
  212. {
  213. if (triggerTimer > 0)
  214. {
  215. if (continuousShootFlag)
  216. {
  217. flag = true;
  218. }
  219. }
  220. else
  221. {
  222. flag = true;
  223. if (delayedTime <= 0 && attackTimer <= 0)
  224. {
  225. continuousShootFlag = true;
  226. }
  227. }
  228. }
  229. else //半自动
  230. {
  231. if (justDown && triggerTimer <= 0)
  232. {
  233. flag = true;
  234. }
  235. }
  236. }
  237.  
  238. if (flag)
  239. {
  240. if (justDown)
  241. {
  242. //开火前延时
  243. delayedTime = Attribute.DelayedTime;
  244. //扳机按下间隔
  245. triggerTimer = Attribute.TriggerInterval;
  246. //连发数量
  247. if (!Attribute.ContinuousShoot)
  248. {
  249. continuousCount = MathUtils.RandRangeInt(Attribute.MinContinuousCount, Attribute.MaxContinuousCount);
  250. }
  251. }
  252. if (delayedTime <= 0 && attackTimer <= 0)
  253. {
  254. TriggernFire();
  255. }
  256. attackFlag = true;
  257. }
  258. triggerFlag = true;
  259. }
  260.  
  261. /// <summary>
  262. /// 刚按下扳机
  263. /// </summary>
  264. private void DownTrigger()
  265. {
  266.  
  267. }
  268.  
  269. /// <summary>
  270. /// 刚松开扳机
  271. /// </summary>
  272. private void UpTriggern()
  273. {
  274. continuousShootFlag = false;
  275. if (delayedTime > 0)
  276. {
  277. continuousCount = 0;
  278. }
  279. }
  280.  
  281. /// <summary>
  282. /// 触发开火
  283. /// </summary>
  284. private void TriggernFire()
  285. {
  286. continuousCount = continuousCount > 0 ? continuousCount - 1 : 0;
  287. fireInterval = 60 / Attribute.StartFiringSpeed;
  288. attackTimer += fireInterval;
  289.  
  290. //触发开火函数
  291. Fire();
  292.  
  293. //开火发射的子弹数量
  294. var bulletCount = MathUtils.RandRangeInt(Attribute.MaxFireBulletCount, Attribute.MinFireBulletCount);
  295. //枪口角度
  296. var angle = new Vector2(GameConfig.ScatteringDistance, CurrScatteringRange).Angle();
  297.  
  298. //创建子弹
  299. for (int i = 0; i < bulletCount; i++)
  300. {
  301. //先算枪口方向
  302. Rotation = (float)GD.RandRange(-angle, angle);
  303. //发射子弹
  304. ShootBullet();
  305. }
  306.  
  307. //当前的散射半径
  308. CurrScatteringRange = Mathf.Min(CurrScatteringRange + Attribute.ScatteringRangeAddValue, Attribute.FinalScatteringRange);
  309. //枪的旋转角度
  310. RotationDegrees -= Attribute.UpliftAngle;
  311. fireAngle = RotationDegrees;
  312. //枪身位置
  313. Position = new Vector2(Mathf.Max(-Attribute.MaxBacklash, Position.x - MathUtils.RandRange(Attribute.MinBacklash, Attribute.MaxBacklash)), Position.y);
  314.  
  315. if (FireEvent != null)
  316. {
  317. FireEvent(this);
  318. }
  319. }
  320.  
  321. /// <summary>
  322. /// 初始化时调用
  323. /// </summary>
  324. protected abstract void Init();
  325.  
  326. /// <summary>
  327. /// 单次开火时调用的函数
  328. /// </summary>
  329. protected abstract void Fire();
  330.  
  331. /// <summary>
  332. /// 发射子弹时调用的函数, 每发射一枚子弹调用一次,
  333. /// 如果做霰弹枪效果, 一次开火发射5枚子弹, 则该函数调用5次
  334. /// </summary>
  335. protected abstract void ShootBullet();
  336.  
  337. /// <summary>
  338. /// 当武器被拾起时调用
  339. /// </summary>
  340. /// <param name="master">拾起该武器的角色</param>
  341. protected abstract void OnPickUp(Role master);
  342.  
  343. /// <summary>
  344. /// 当武器被扔掉时调用
  345. /// </summary>
  346. protected abstract void OnThrowOut();
  347.  
  348. /// <summary>
  349. /// 当武器被激活时调用, 也就是使用当武器是调用
  350. /// </summary>
  351. protected abstract void OnActive();
  352.  
  353. /// <summary>
  354. /// 当武器被收起时调用
  355. /// </summary>
  356. protected abstract void OnConceal();
  357.  
  358. public void _PickUpGun(Role master)
  359. {
  360. Master = master;
  361. _state = 1;
  362. //握把位置
  363. GunSprite.Position = Attribute.HoldPosition;
  364. AnimationPlayer.Play("RESET");
  365. ZIndex = 0;
  366. OnPickUp(master);
  367. }
  368.  
  369. public void _ThrowOutGun()
  370. {
  371. Master = null;
  372. _state = 0;
  373. GunSprite.Position = Attribute.CenterPosition;
  374. AnimationPlayer.Play("Floodlight");
  375. OnThrowOut();
  376. }
  377.  
  378. public void _Active()
  379. {
  380. OnActive();
  381. }
  382.  
  383. public void _Conceal()
  384. {
  385. OnConceal();
  386. }
  387.  
  388. /// <summary>
  389. /// 实例化并返回子弹对象
  390. /// </summary>
  391. /// <param name="bulletPack">子弹的预制体</param>
  392. protected T CreateBullet<T>(PackedScene bulletPack, Vector2 globalPostion, float globalRotation, Node parent = null) where T : Node2D, IBullet
  393. {
  394. return (T)CreateBullet(bulletPack, globalPostion, globalRotation, parent);
  395. }
  396.  
  397.  
  398. protected IBullet CreateBullet(PackedScene bulletPack, Vector2 globalPostion, float globalRotation, Node parent = null)
  399. {
  400. // 实例化子弹
  401. Node2D bullet = bulletPack.Instance<Node2D>();
  402. // 设置坐标
  403. bullet.GlobalPosition = globalPostion;
  404. // 旋转角度
  405. bullet.GlobalRotation = globalRotation;
  406. if (parent == null)
  407. {
  408. RoomManager.Current.ItemRoot.AddChild(bullet);
  409. }
  410. else
  411. {
  412. parent.AddChild(bullet);
  413. }
  414. // 调用初始化
  415. IBullet result = (IBullet)bullet;
  416. result.Init(TargetCamp, this, null);
  417. return result;
  418. }
  419. }