Newer
Older
DungeonShooting / src / weapon / gun / Gun.cs
@小李xl 小李xl on 15 Jun 2022 9 KB 给枪套添加切换武器接口
  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. public CampEnum TargetCamp { get; set; }
  40.  
  41. /// <summary>
  42. /// 该武器的拥有者
  43. /// </summary>
  44. public Node2D Master { get; }
  45.  
  46. /// <summary>
  47. /// 枪管的开火点
  48. /// </summary>
  49. public Position2D FirePoint { get; private set; }
  50. /// <summary>
  51. /// 枪管的原点
  52. /// </summary>
  53. public Position2D OriginPoint { get; private set; }
  54. /// <summary>
  55. /// 弹壳抛出的点
  56. /// </summary>
  57. public Position2D ShellPoint { get; private set; }
  58. /// <summary>
  59. /// 枪的当前散射半径
  60. /// </summary>
  61. public float CurrScatteringRange { get; private set; } = 0;
  62.  
  63.  
  64. //是否按下
  65. private bool triggerFlag = false;
  66. //扳机计时器
  67. private float triggerTimer = 0;
  68. //开火前延时时间
  69. private float delayedTime = 0;
  70. //开火间隙时间
  71. private float fireInterval = 0;
  72. //开火枪口角度
  73. private float fireAngle = 0;
  74. //攻击冷却计时
  75. private float attackTimer = 0;
  76. //攻击状态
  77. private bool attackFlag = false;
  78. //按下的时间
  79. private float downTimer = 0;
  80. //松开的时间
  81. private float upTimer = 0;
  82. //连发次数
  83. private float continuousCount = 0;
  84. private bool continuousShootFlag = false;
  85.  
  86. public override void _Process(float delta)
  87. {
  88. if (triggerFlag)
  89. {
  90. if (upTimer > 0) //第一帧按下扳机
  91. {
  92. upTimer = 0;
  93. DownTrigger();
  94. }
  95. downTimer += delta;
  96. }
  97. else
  98. {
  99. if (downTimer > 0) //第一帧松开扳机
  100. {
  101. downTimer = 0;
  102. UpTriggern();
  103. }
  104. upTimer += delta;
  105. }
  106.  
  107. // 攻击的计时器
  108. if (attackTimer > 0)
  109. {
  110. attackTimer -= delta;
  111. if (attackTimer < 0)
  112. {
  113. delayedTime += attackTimer;
  114. attackTimer = 0;
  115. }
  116. }
  117. else if (delayedTime > 0) //攻击延时
  118. {
  119. delayedTime -= delta;
  120. if (attackTimer < 0)
  121. {
  122. delayedTime = 0;
  123. }
  124. }
  125.  
  126. //连发判断
  127. if (continuousCount > 0 && delayedTime <= 0 && attackTimer <= 0)
  128. {
  129. TriggernFire();
  130. }
  131.  
  132. if (!attackFlag && attackTimer <= 0)
  133. {
  134. CurrScatteringRange = Mathf.Max(CurrScatteringRange - Attribute.ScatteringRangeBackSpeed * delta, Attribute.StartScatteringRange);
  135. }
  136. triggerTimer = triggerTimer > 0 ? triggerTimer - delta : 0;
  137. triggerFlag = false;
  138. attackFlag = false;
  139.  
  140. //枪身回归
  141. Position = Position.MoveToward(Vector2.Zero, 35 * delta);
  142. if (fireInterval == 0)
  143. {
  144. RotationDegrees = 0;
  145. }
  146. else
  147. {
  148. RotationDegrees = Mathf.Lerp(0, fireAngle, attackTimer / fireInterval);
  149. }
  150. }
  151.  
  152. public void Init(GunAttribute attribute)
  153. {
  154. if (_attribute != null)
  155. {
  156. throw new Exception("当前武器已经初始化过了!");
  157. }
  158.  
  159. GunSprite = GetNode<Sprite>("GunSprite");
  160. FirePoint = GetNode<Position2D>("FirePoint");
  161. OriginPoint = GetNode<Position2D>("OriginPoint");
  162. ShellPoint = GetNode<Position2D>("ShellPoint");
  163.  
  164. Attribute = attribute;
  165. //更新图片
  166. GunSprite.Texture = attribute.Sprite;
  167. //开火位置
  168. FirePoint.Position = new Vector2(attribute.FirePosition.x, -attribute.FirePosition.y);
  169. OriginPoint.Position = new Vector2(0, -attribute.FirePosition.y);
  170. //握把位置
  171. GunSprite.Position = attribute.HoldPosition;
  172.  
  173. Init();
  174. }
  175.  
  176. /// <summary>
  177. /// 扳机函数, 调用即视为扣动扳机
  178. /// </summary>
  179. public void Trigger()
  180. {
  181. //是否第一帧按下
  182. var justDown = downTimer == 0;
  183. //是否能发射
  184. var flag = false;
  185. if (continuousCount <= 0) //不能处于连发状态下
  186. {
  187. if (Attribute.ContinuousShoot) //自动射击
  188. {
  189. if (triggerTimer > 0)
  190. {
  191. if (continuousShootFlag)
  192. {
  193. flag = true;
  194. }
  195. }
  196. else
  197. {
  198. flag = true;
  199. if (delayedTime <= 0 && attackTimer <= 0)
  200. {
  201. continuousShootFlag = true;
  202. }
  203. }
  204. }
  205. else //半自动
  206. {
  207. if (justDown && triggerTimer <= 0)
  208. {
  209. flag = true;
  210. }
  211. }
  212. }
  213.  
  214. if (flag)
  215. {
  216. if (justDown)
  217. {
  218. //开火前延时
  219. delayedTime = Attribute.DelayedTime;
  220. //扳机按下间隔
  221. triggerTimer = Attribute.TriggerInterval;
  222. //连发数量
  223. if (!Attribute.ContinuousShoot)
  224. {
  225. continuousCount = MathUtils.RandRangeInt(Attribute.MinContinuousCount, Attribute.MaxContinuousCount);
  226. }
  227. }
  228. if (delayedTime <= 0 && attackTimer <= 0)
  229. {
  230. TriggernFire();
  231. }
  232. attackFlag = true;
  233. }
  234. triggerFlag = true;
  235. }
  236.  
  237. /// <summary>
  238. /// 刚按下扳机
  239. /// </summary>
  240. private void DownTrigger()
  241. {
  242.  
  243. }
  244.  
  245. /// <summary>
  246. /// 刚松开扳机
  247. /// </summary>
  248. private void UpTriggern()
  249. {
  250. continuousShootFlag = false;
  251. if (delayedTime > 0)
  252. {
  253. continuousCount = 0;
  254. }
  255. }
  256.  
  257. /// <summary>
  258. /// 触发开火
  259. /// </summary>
  260. private void TriggernFire()
  261. {
  262. continuousCount = continuousCount > 0 ? continuousCount - 1 : 0;
  263. fireInterval = 60 / Attribute.StartFiringSpeed;
  264. attackTimer += fireInterval;
  265.  
  266. //触发开火函数
  267. Fire();
  268.  
  269. //开火发射的子弹数量
  270. var bulletCount = MathUtils.RandRangeInt(Attribute.MaxFireBulletCount, Attribute.MinFireBulletCount);
  271. //枪口角度
  272. var angle = new Vector2(GameConfig.ScatteringDistance, CurrScatteringRange).Angle();
  273.  
  274. //创建子弹
  275. for (int i = 0; i < bulletCount; i++)
  276. {
  277. //先算枪口方向
  278. Rotation = (float)GD.RandRange(-angle, angle);
  279. //发射子弹
  280. ShootBullet();
  281. }
  282.  
  283. //当前的散射半径
  284. CurrScatteringRange = Mathf.Min(CurrScatteringRange + Attribute.ScatteringRangeAddValue, Attribute.FinalScatteringRange);
  285. //枪的旋转角度
  286. RotationDegrees -= Attribute.UpliftAngle;
  287. fireAngle = RotationDegrees;
  288. //枪身位置
  289. Position = new Vector2(Mathf.Max(-Attribute.MaxBacklash, Position.x - MathUtils.RandRange(Attribute.MinBacklash, Attribute.MaxBacklash)), Position.y);
  290.  
  291. if (FireEvent != null)
  292. {
  293. FireEvent(this);
  294. }
  295. }
  296.  
  297. /// <summary>
  298. /// 初始化时调用
  299. /// </summary>
  300. protected abstract void Init();
  301.  
  302. /// <summary>
  303. /// 单次开火时调用的函数
  304. /// </summary>
  305. protected abstract void Fire();
  306.  
  307. /// <summary>
  308. /// 发射子弹时调用的函数, 每发射一枚子弹调用一次,
  309. /// 如果做霰弹枪效果, 一次开火发射5枚子弹, 则该函数调用5次
  310. /// </summary>
  311. protected abstract void ShootBullet();
  312.  
  313. /// <summary>
  314. /// 当武器被拾起时调用
  315. /// </summary>
  316. /// <param name="master">拾起该武器的角色</param>
  317. protected abstract void OnPickUp(Role master);
  318.  
  319. /// <summary>
  320. /// 当武器被扔掉时调用
  321. /// </summary>
  322. protected abstract void OnThrowOut();
  323.  
  324. /// <summary>
  325. /// 实例化并返回子弹对象
  326. /// </summary>
  327. /// <param name="bulletPack">子弹的预制体</param>
  328. protected T CreateBullet<T>(PackedScene bulletPack, Vector2 globalPostion, float globalRotation, Node parent = null) where T : Node2D, IBullet
  329. {
  330. return (T) CreateBullet(bulletPack, globalPostion, globalRotation, parent);
  331. }
  332.  
  333.  
  334. protected IBullet CreateBullet(PackedScene bulletPack, Vector2 globalPostion, float globalRotation, Node parent = null)
  335. {
  336. // 实例化子弹
  337. Node2D bullet = bulletPack.Instance<Node2D>();
  338. // 设置坐标
  339. bullet.GlobalPosition = globalPostion;
  340. // 旋转角度
  341. bullet.GlobalRotation = globalRotation;
  342. if (parent == null)
  343. {
  344. RoomManager.Current.ItemRoot.AddChild(bullet);
  345. }
  346. else
  347. {
  348. parent.AddChild(bullet);
  349. }
  350. // 调用初始化
  351. IBullet result = (IBullet)bullet;
  352. result.Init(TargetCamp, this, null);
  353. return result;
  354. }
  355. }