给蓝色的大鱼身体加点反馈,当吃了蓝色果实,启动双倍模式的时候,大鱼的身体变成蓝色。

    这里新建一个私有的存放蓝色身体的序列数组,私有变量不会被继承。

    1. private _pBigBody: Array<HTMLImageElement> = []; // 只属于鱼妈妈的特殊颜色身体
    1. import { ctx_one, cvs_height, cvs_width, mouse_x, mouse_y, fish_mother, score } from "./init";
    2. import { deltaTime } from "./game-loop";
    3. import utils from "./utils";
    4. // 鱼妈妈
    5. class FishMother{
    6. x: number = cvs_width / 2; // 坐标轴 x
    7. y: number = cvs_height / 2 ; // 坐标轴 y
    8. bigEye : Array<HTMLImageElement> = []; // 眼睛
    9. bigBody : Array<HTMLImageElement> = []; // 身体
    10. private _pBigBody: Array<HTMLImageElement> = []; // 只属于鱼妈妈的特殊颜色身体
    11. BigTail : Array<HTMLImageElement> = []; // 尾巴
    12. angle: number = 0; // 鱼的角度
    13. EyeIndex = 0; // 需要渲染哪个眼睛的索引值
    14. BodyIndex = 0;
    15. TailIndex = 0;
    16. EyeTimer = 0; // 计算眼睛时间
    17. BodyTimer = 0;
    18. TailTimer = 0;
    19. EyeInterval = 300; // 通过这个变量动态的设置眨眼睛的间隔
    20. BodyInterval = 300;
    21. TailInterval = 50;
    22. constructor(){
    23. for (let i = 0; i < 2; ++i) {
    24. this.bigEye[i] = new Image();
    25. this.bigEye[i].src = `assets/img/bigEye${i}.png`;
    26. }
    27. for (let i = 0; i < 8; ++i) {
    28. this._pBigBody[i] = new Image();
    29. this._pBigBody[i].src = `assets/img/bigSwimBlue${i}.png`;
    30. }
    31. for (let i = 0; i < 8; ++i) {
    32. this.bigBody[i] = new Image();
    33. this.bigBody[i].src = `assets/img/bigSwim${i}.png`;
    34. }
    35. for (let i = 0; i < 8; ++i) {
    36. this.BigTail[i] = new Image();
    37. this.BigTail[i].src = `assets/img/bigTail${i}.png`;
    38. }
    39. }
    40. checkImageIndex(){
    41. this.EyeTimer += deltaTime;
    42. this.TailTimer += deltaTime;
    43. this.BodyTimer += deltaTime;
    44. // 当计时器大于某个值的时候才进行修改
    45. if(this.EyeTimer > this.EyeInterval) {
    46. this.EyeIndex = (this.EyeIndex + 1) % 2;
    47. // 重置一下定时器
    48. this.EyeTimer %= this.EyeInterval;
    49. // 判断是眨眼的哪个过程
    50. if(this.EyeIndex === 0) {
    51. this.EyeInterval = Math.random() * 1500 + 2000 // 设置下一次眨眼的间隔长一点
    52. }else{
    53. // 先闭眼后睁眼,这个过程应该非常短
    54. this.EyeInterval = 300;
    55. }
    56. }
    57. if(this.TailTimer > this.TailInterval) {
    58. this.TailIndex = (this.TailIndex + 1) % 8;
    59. this.TailTimer %= this.TailInterval
    60. }
    61. if(this.BodyTimer > this.BodyInterval) {
    62. this.BodyIndex = this.BodyIndex + 1;
    63. this.BodyTimer %= this.BodyInterval
    64. if(this.BodyIndex > 7) {
    65. this.BodyIndex = 7
    66. }
    67. }
    68. }
    69. checkMove(){
    70. this.x = utils.lerpDistance(mouse_x, this.x , .95)
    71. this.y = utils.lerpDistance(mouse_y, this.y , .95)
    72. let instance_X = mouse_x - this.x; // 边 a
    73. let instance_Y = mouse_y - this.y; // 边 b
    74. let ag = Math.atan2(instance_Y, instance_X) + Math.PI // [-PI, PI]
    75. this.angle = utils.lerpAngle(ag, this.angle, .9)
    76. }
    77. draw(){
    78. this.checkMove()
    79. this.checkImageIndex()
    80. ctx_one.save();
    81. ctx_one.translate(this.x, this.y); // 定义相对定位的坐标中心点
    82. ctx_one.rotate(this.angle);
    83. ctx_one.scale(.8, .8);
    84. ctx_one.drawImage(this.BigTail[this.TailIndex], -this.BigTail[this.TailIndex].width / 2 + 30, -this.BigTail[this.TailIndex].height / 2); // 这里的尾巴,往右移动30像素,让它在身体的后面。
    85. if(score.doubleMode === 2) {
    86. ctx_one.drawImage(this._pBigBody[this.BodyIndex], -this._pBigBody[this.BodyIndex].width / 2, -this._pBigBody[this.BodyIndex].height / 2);
    87. }else{
    88. ctx_one.drawImage(this.bigBody[this.BodyIndex], -this.bigBody[this.BodyIndex].width / 2, -this.bigBody[this.BodyIndex].height / 2);
    89. }
    90. ctx_one.drawImage(this.bigEye[this.EyeIndex], -this.bigEye[this.EyeIndex].width / 2, -this.bigEye[this.EyeIndex].height / 2); // 居中,所以向左移动宽度的一半,向上移动宽度的一半
    91. ctx_one.restore();
    92. }
    93. }
    94. // 鱼宝宝
    95. class FishBaby extends FishMother {
    96. x: number = cvs_width / 2 + 50; // 坐标轴 x
    97. y: number = cvs_height / 2 + 50; // 坐标轴 y
    98. constructor() {
    99. super()
    100. for (let i = 0; i < 2; ++i) {
    101. this.bigEye[i] = new Image();
    102. this.bigEye[i].src = `assets/img/babyEye${i}.png`;
    103. }
    104. for (let i = 0; i < 20; ++i) {
    105. this.bigBody[i] = new Image();
    106. this.bigBody[i].src = `assets/img/babyFade${i}.png`;
    107. }
    108. for (let i = 0; i < 8; ++i) {
    109. this.BigTail[i] = new Image();
    110. this.BigTail[i].src = `assets/img/babyTail${i}.png`;
    111. }
    112. }
    113. checkImageIndex(){
    114. this.EyeTimer += deltaTime;
    115. this.TailTimer += deltaTime;
    116. this.BodyTimer += deltaTime;
    117. // 当计时器大于某个值的时候才进行修改
    118. if(this.EyeTimer > this.EyeInterval) {
    119. this.EyeIndex = (this.EyeIndex + 1) % 2;
    120. // 重置一下定时器
    121. this.EyeTimer %= this.EyeInterval;
    122. // 判断是眨眼的哪个过程
    123. if(this.EyeIndex === 0) {
    124. this.EyeInterval = Math.random() * 1500 + 2000 // 设置下一次眨眼的间隔长一点
    125. }else{
    126. // 先闭眼后睁眼,这个过程应该非常短
    127. this.EyeInterval = 300;
    128. }
    129. }
    130. if(this.TailTimer > this.TailInterval) {
    131. this.TailIndex = (this.TailIndex + 1) % 8;
    132. this.TailTimer %= this.TailInterval
    133. }
    134. if(this.BodyTimer > this.BodyInterval) {
    135. this.BodyIndex = this.BodyIndex + 1;
    136. this.BodyTimer %= this.BodyInterval
    137. if(this.BodyIndex > 19) {
    138. this.BodyIndex = 19
    139. console.log('game over');
    140. }
    141. }
    142. }
    143. // 重置身体的图片,也就是得到能量满血复活
    144. recover(){
    145. this.BodyIndex = 0;
    146. }
    147. checkMove(){
    148. this.x = utils.lerpDistance(fish_mother.x, this.x , .98)
    149. this.y = utils.lerpDistance(fish_mother.y, this.y , .98)
    150. let instance_X = fish_mother.x - this.x; // 边 a
    151. let instance_Y = fish_mother.y - this.y; // 边 b
    152. let ag = Math.atan2(instance_Y, instance_X) + Math.PI // [-PI, PI]
    153. this.angle = utils.lerpAngle(ag, this.angle, .7)
    154. }
    155. draw(){
    156. this.checkMove()
    157. this.checkImageIndex()
    158. ctx_one.save();
    159. ctx_one.translate(this.x, this.y); // 定义相对定位的坐标中心点
    160. ctx_one.rotate(this.angle);
    161. ctx_one.scale(.8, .8);
    162. ctx_one.drawImage(this.BigTail[this.TailIndex], -this.BigTail[this.TailIndex].width / 2 + 24, -this.BigTail[this.TailIndex].height / 2); // 这里的尾巴,往右移动30像素,让它在身体的后面。
    163. ctx_one.drawImage(this.bigBody[this.BodyIndex], -this.bigBody[this.BodyIndex].width / 2, -this.bigBody[this.BodyIndex].height / 2);
    164. ctx_one.drawImage(this.bigEye[this.EyeIndex], -this.bigEye[this.EyeIndex].width / 2, -this.bigEye[this.EyeIndex].height / 2); // 居中,所以向左移动宽度的一半,向上移动宽度的一半
    165. ctx_one.restore();
    166. }
    167. }
    168. export {
    169. FishMother,
    170. FishBaby
    171. }

    此时我们在喂给小鱼之后还需要重置大鱼图片序列的索引为0,以及身体的定时器改大一点。

    1. // 把能力给小鱼,果实数清零,计算分数一次
    2. score.reset()
    3. // 把大鱼的 bodyindex 恢复成 0
    4. fish_mother.BodyIndex = 0;
    1. BodyInterval = 1000;

    此时我们发现小鱼的身体变化又太慢了,所以我们重新定义一个覆盖父类的

    1. // 鱼宝宝
    2. class FishBaby extends FishMother {
    3. x: number = cvs_width / 2 + 50; // 坐标轴 x
    4. y: number = cvs_height / 2 + 50; // 坐标轴 y
    5. BodyInterval = 300;
    6. constructor() {