click beatiful

会在你点击鼠标时生成特效,并且会持续生成流星雨特效,美观又时尚(如果出现bug,请打开开发人员模式)

  1. // ==UserScript==
  2. // @name click beatiful
  3. // @namespace http://tampermonkey.net/
  4. // @version 1.1.3
  5. // @description 会在你点击鼠标时生成特效,并且会持续生成流星雨特效,美观又时尚(如果出现bug,请打开开发人员模式)
  6. // @author BarkFlorr
  7. // @match https://*/*
  8. // @match http://*/*
  9. // @grant none
  10. // ==/UserScript==
  11.  
  12. (function() {
  13. 'use strict';
  14. // 从 localStorage 中读取之前保存的值,如果没有则使用初始值
  15. let sz1 = localStorage.getItem('sz1') || 32;
  16. let sz2 = localStorage.getItem('sz2') || 10;
  17. let sz3 = localStorage.getItem('sz3') || 15;
  18. let sz4 = localStorage.getItem('sz4') || 1;
  19.  
  20. function clickEffect() {
  21. let balls = [];
  22. let longPressed = false;
  23. let longPress;
  24. let multiplier = 0;
  25. let width, height;
  26. let origin;
  27. let normal;
  28. let ctx;
  29. const colours = ["#F73859", "#14FFEC", "#00E0FF", "#FF99FE", "#FAF15D", "#FFF00", "#00FFFF"];
  30. const canvas = document.createElement("canvas");
  31. document.body.appendChild(canvas);
  32. canvas.setAttribute("style", "width: 100%; height: 100%; top: 0; left: 0; z-index: 99999; position: fixed; pointer-events: none;");
  33. const pointer = document.createElement("span");
  34. pointer.classList.add("pointer");
  35. pointer.style.position = 'fixed';
  36. pointer.style.width = '20px';
  37. pointer.style.height = '20px';
  38. pointer.style.backgroundColor = 'rgba(0, 0, 0, 0.5)';
  39. pointer.style.borderRadius = '50%';
  40. pointer.style.pointerEvents = 'none';
  41. document.body.appendChild(pointer);
  42.  
  43. if (canvas.getContext && window.addEventListener) {
  44. ctx = canvas.getContext("2d");
  45. updateSize();
  46. window.addEventListener('resize', updateSize, false);
  47. loop();
  48. addEventListeners();
  49. } else {
  50. console.log("canvas or addEventListener is unsupported!");
  51. showError('canvas或addEventListener不支持');
  52. }
  53.  
  54. function addEventListeners() {
  55. window.addEventListener("mousedown", function(e) {
  56. pushBalls(randBetween(sz2, sz3), e.clientX, e.clientY);
  57. document.body.classList.add("is-pressed");
  58. longPress = setTimeout(function(){
  59. document.body.classList.add("is-longpress");
  60. longPressed = true;
  61. }, 500);
  62. }, false);
  63. window.addEventListener("mouseup", function(e) {
  64. clearInterval(longPress);
  65. if (longPressed == true) {
  66. document.body.classList.remove("is-longpress");
  67. pushBalls(randBetween(50 + Math.ceil(multiplier), 100 + Math.ceil(multiplier)), e.clientX, e.clientY);
  68. longPressed = false;
  69. }
  70. document.body.classList.remove("is-pressed");
  71. }, false);
  72. }
  73.  
  74. function updateSize() {
  75. canvas.width = window.innerWidth * 2;
  76. canvas.height = window.innerHeight * 2;
  77. canvas.style.width = window.innerWidth + 'px';
  78. canvas.style.height = window.innerHeight + 'px';
  79. ctx.scale(2, 2);
  80. width = (canvas.width = window.innerWidth);
  81. height = (canvas.height = window.innerHeight);
  82. origin = {
  83. x: width / 2,
  84. y: height / 2
  85. };
  86. normal = {
  87. x: width / 2,
  88. y: height / 2
  89. };
  90. }
  91.  
  92. class Ball {
  93. constructor(x = origin.x, y = origin.y) {
  94. this.x = x;
  95. this.y = y;
  96. this.angle = Math.random() * 2 * Math.PI;
  97. if (longPressed == true) {
  98. this.multiplier = randBetween(14 + multiplier, 15 + multiplier);
  99. } else {
  100. this.multiplier = randBetween(6, 12);
  101. }
  102. this.vx = ((this.multiplier + Math.random()) * Math.cos(this.angle))*sz4;
  103. this.vy = ((this.multiplier + Math.random()) * Math.sin(this.angle))*sz4;
  104. this.r = randBetween(4, 0);
  105. this.color = colours[Math.floor(Math.random() * colours.length)];
  106. }
  107.  
  108. update() {
  109. this.x += this.vx - normal.x;
  110. this.y += this.vy - normal.y;
  111. normal.x = -2 / window.innerWidth * Math.sin(this.angle);
  112. normal.y = -2 / window.innerHeight * Math.cos(this.angle);
  113. this.vx *= 1;
  114. this.vy *= 1;
  115. }
  116.  
  117. draw() {
  118. ctx.fillStyle = this.color;
  119. ctx.beginPath();
  120. ctx.arc(this.x, this.y, this.r, 0, Math.PI * 2, false);
  121. ctx.fill();
  122. }
  123. }
  124.  
  125. function pushBalls(count = 1, x = origin.x, y = origin.y) {
  126. for (let i = 0; i < count; i++) {
  127. balls.push(new Ball(x, y));
  128. }
  129. }
  130.  
  131. function randBetween(min, max) {
  132. return Math.floor(Math.random() * max) + min;
  133. }
  134.  
  135. function loop() {
  136. ctx.clearRect(0, 0, canvas.width, canvas.height);
  137. for (let i = 0; i < balls.length; i++) {
  138. let b = balls[i];
  139. if (b.r < 0) continue;
  140. b.draw();
  141. b.update();
  142. }
  143. if (longPressed == true) {
  144. multiplier += 0.2;
  145. } else if (!longPressed && multiplier >= 0) {
  146. multiplier -= 0.4;
  147. }
  148. removeBall();
  149. requestAnimationFrame(loop);
  150. }
  151.  
  152. function removeBall() {
  153. for (let i = 0; i < balls.length; i++) {
  154. let b = balls[i];
  155. if (b.x + b.r < 0 || b.x - b.r > width || b.y + b.r < 0 || b.y - b.r > height || b.r < 0) {
  156. balls.splice(i, 1);
  157. }
  158. }
  159. }
  160.  
  161. function pushBallsFromTopLeft() {
  162. let x = randBetween(0, width);
  163. let y = randBetween(0, height);
  164. let xxx = randBetween(0, 2);
  165. if(xxx==0) x=0;
  166. else y=0;
  167. let angle = Math.atan2(height, width);
  168. let ball = new Ball(x, y);
  169. ball.vx = ((ball.multiplier + Math.random()) * Math.cos(angle))*sz4;
  170. ball.vy = ((ball.multiplier + Math.random()) * Math.sin(angle))*sz4;
  171. balls.push(ball);
  172. }
  173.  
  174. let meteorInterval;
  175. function startMeteorEffect() {
  176. meteorInterval = setInterval(() => {
  177. requestAnimationFrame(pushBallsFromTopLeft);
  178. }, sz1);
  179. }
  180.  
  181. startMeteorEffect();
  182.  
  183. function showError(message) {
  184. const errorDiv = document.createElement('div');
  185. errorDiv.style.position = 'fixed';
  186. errorDiv.style.top = '10px';
  187. errorDiv.style.left = '10px';
  188. errorDiv.style.backgroundColor = 'rgba(255, 0, 0, 0.8)';
  189. errorDiv.style.color = 'white';
  190. errorDiv.style.padding = '10px';
  191. errorDiv.style.zIndex = '100000';
  192. errorDiv.textContent = message;
  193. document.body.appendChild(errorDiv);
  194. }
  195.  
  196. // 创建并添加设置按钮
  197. const settingsButton = document.createElement('button');
  198. settingsButton.textContent = 'click beautiful设置';
  199. settingsButton.style.position = 'fixed';
  200. settingsButton.style.top = '10px';
  201. settingsButton.style.left = '10px';
  202. settingsButton.style.zIndex = '100000';
  203. document.body.appendChild(settingsButton);
  204.  
  205. // 为设置按钮添加点击事件
  206. settingsButton.addEventListener('click', function() {
  207. // 使用 prompt 对话框让用户输入新的值
  208. const newSz1 = prompt('请输入流星雨生成间隔(单位:毫秒)', sz1);
  209. const newSz2 = prompt('请输入点击时小球生成的数量下限', sz2);
  210. const newSz3 = prompt('请输入点击时小球生成的数量上限', sz3);
  211. const newSz4 = prompt('请输入小球移动速度', sz4);
  212. if (newSz1!== null) {
  213. sz1 = parseFloat(newSz1);
  214. localStorage.setItem('sz1', sz1);
  215. }
  216. if (newSz2!== null) {
  217. sz2 = parseFloat(newSz2);
  218. localStorage.setItem('sz2', sz2);
  219. }
  220. if (newSz3!== null) {
  221. sz3 = parseFloat(newSz3);
  222. localStorage.setItem('sz3', sz3);
  223. }
  224. if (newSz4!== null) {
  225. sz4 = parseFloat(newSz4);
  226. localStorage.setItem('sz4', sz4);
  227. }
  228. // 重启流星雨特效
  229. clearInterval(meteorInterval);
  230. startMeteorEffect();
  231. });
  232. }
  233.  
  234. clickEffect();
  235. })();