explosion.ts 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. /**
  2. * 爆破动画
  3. */
  4. import { generateSimilarColors } from "../base/utils";
  5. /**
  6. * 爆破微粒
  7. */
  8. class Particle {
  9. ctx: CanvasRenderingContext2D;
  10. x: number;
  11. y: number;
  12. r: number;
  13. dx: number;
  14. dy: number;
  15. color: string;
  16. a: number;
  17. /**
  18. *
  19. * @param ctx
  20. * @param x 初始坐标x
  21. * @param y 初始坐标y
  22. * @param r 颗粒大小半径
  23. * @param dx 每帧移动x坐标距离
  24. * @param dy 每帧移动y坐标距离
  25. * @param color 颜色
  26. */
  27. constructor(ctx: CanvasRenderingContext2D, x: number, y: number, r: number, dx: number, dy: number, color: string) {
  28. this.x = x;
  29. this.y = y;
  30. this.r = r;
  31. this.dx = dx;
  32. this.dy = dy;
  33. this.color = color;
  34. this.a = 1;
  35. this.ctx = ctx;
  36. }
  37. draw() {
  38. let ctx = this.ctx;
  39. ctx.save();
  40. ctx.globalAlpha = this.a;
  41. ctx.fillStyle = this.color;
  42. ctx.beginPath();
  43. ctx.arc(this.x, this.y, this.r, 0, Math.PI * 2, false);
  44. ctx.fill();
  45. ctx.restore();
  46. }
  47. update() {
  48. this.draw();
  49. this.a -= 1 / 120;
  50. this.x += this.dx;
  51. this.y += this.dy;
  52. }
  53. }
  54. export default class Explosion {
  55. canvas: HTMLCanvasElement;
  56. ctx: CanvasRenderingContext2D;
  57. onend: Function;
  58. particles: Particle[] = [];
  59. constructor(canvas: HTMLCanvasElement, color: string, particleNum: number, onend: Function) {
  60. this.canvas = canvas;
  61. this.canvas.width = Math.floor(this.canvas.offsetWidth * window.devicePixelRatio);
  62. this.canvas.height = Math.floor(this.canvas.offsetHeight * window.devicePixelRatio);
  63. this.ctx = this.canvas.getContext("2d")!;
  64. this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
  65. this.initParticles(color, particleNum);
  66. this.onend = onend;
  67. }
  68. /**
  69. * 用requestAnimationFrame试试==>果然效果好多了,而且在低端机上效果明显
  70. */
  71. explode() {
  72. this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
  73. this.particles.forEach((particle, i) => {
  74. if (particle.a <= 0) {
  75. this.particles.splice(i, 1);
  76. } else {
  77. particle.update();
  78. }
  79. })
  80. if (this.particles.length == 0) {
  81. this.onend && this.onend();
  82. return;
  83. }
  84. requestAnimationFrame(this.explode.bind(this));
  85. }
  86. private initParticles(color: string, particleNum: number) {
  87. let colors = generateSimilarColors(color, particleNum);
  88. for (let i = 0; i < particleNum; i++) {
  89. let x = this.canvas.width / 2 + (Math.random() - 0.5) * (Math.random() * 10);
  90. let y = this.canvas.height / 2 + (Math.random() - 0.5) * (Math.random() * 10);
  91. let r = (Math.floor(Math.random() * 4) + 1) * window.devicePixelRatio;
  92. let dx = (Math.random() - 0.5) * (Math.random() * 8) * window.devicePixelRatio;
  93. let dy = (Math.random() - 0.5) * (Math.random() * 6) * window.devicePixelRatio;
  94. let c = colors[i];
  95. let particle = new Particle(this.ctx, x, y, r, dx, dy, c);
  96. this.particles.push(particle);
  97. }
  98. }
  99. }