index.vue 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837
  1. <template>
  2. <div id="main_box" ref="main_box">
  3. <canvas id="myCanvas1" class="can" ref="can1"></canvas>
  4. <canvas id="myCanvas2" class="can" ref="can2"></canvas>
  5. <a href="javascript:void(0)" @click="loginGame" id="login_btn" ref="login_btn">开始游戏</a>
  6. <div id="score" ref="score_div">{{ scoreText }}</div>
  7. <div id="game_title" ref="game_title">方&nbsp;块&nbsp;跳&nbsp;跃</div>
  8. <div id="state" ref="state_div">{{ stateText }}</div>
  9. <span id="square_main" ref="square_main"></span>
  10. <div id="colorChangeTime_div" ref="colorChangeTime_div">{{ colorChangeTimeText }}</div>
  11. </div>
  12. </template>
  13. <script setup lang="ts">
  14. import { ref, onMounted, onBeforeUnmount } from 'vue';
  15. const changeTimeArrays: any = ["10", "9", "8", "7", "6", "5", "4", "3", "2", "1", "color change!"];
  16. const squareColor: any = ["#FF6688", "#00FF00", "#3399FF", "#FFDAB9", "blueviolet"];
  17. const can1: any = ref(null);
  18. const can2: any = ref(null);
  19. const ctx1: any = ref(null);
  20. const ctx2: any = ref(null);
  21. const canWidth: any = ref(820);
  22. const canHeight: any = ref(640);
  23. const maxWidth: any = ref(820);
  24. const maxHeight: any = ref(640);
  25. const beginGame: any = ref(false);
  26. const gameOver: any = ref(true);
  27. const score: any = ref(0);
  28. const scoreText: any = ref('得分:0');
  29. const stateText: any = ref('');
  30. const colorChangeTimeText: any = ref();
  31. let backrgound: any = ref(null);
  32. let squares: any = ref(null);
  33. let mySquare: any = ref(null);
  34. let beginAnim: any = ref(null);
  35. let lastTime: any = ref(null);
  36. let changeColorTime: any = ref(null);
  37. let loop: any = ref(null);
  38. const changeColorindex: any = ref(0);
  39. const totalSpeed: any = ref(3);
  40. const isStep: any = ref(false);
  41. const colorChangeTimeW: any = ref(0);
  42. const AnimPX: any = ref([]);
  43. const AnimPY: any = ref([]);
  44. const jump_count: any = ref(0);
  45. let square_main: any = ref(null);
  46. let game_title: any = ref(null);
  47. let main_box: any = ref(null);
  48. let login_btn: any = ref(null);
  49. let colorChangeTime_div: any = ref(null);
  50. let state_div: any = ref(null);
  51. let score_div: any = ref(null);
  52. function init() {
  53. score.value = 0;
  54. beginGame.value = false;
  55. gameOver.value = false;
  56. isStep.value = false;
  57. lastTime.value = Date.now();
  58. ctx1.value = can1.value.getContext("2d");
  59. ctx2.value = can2.value.getContext("2d");
  60. if (maxWidth.value != canWidth.value) {
  61. canWidth.value = maxWidth.value;
  62. }
  63. if (maxHeight.value != canHeight.value) {
  64. canHeight.value = maxHeight.value;
  65. }
  66. main_box.value.style.width = canWidth.value + "px";
  67. main_box.value.style.height = canHeight.value + "px";
  68. can1.value.width = canWidth.value;
  69. can2.value.width = canWidth.value;
  70. can1.value.height = canHeight.value;
  71. can2.value.height = canHeight.value;
  72. // 模拟 slideDown 效果
  73. game_title.value.style.display = "block";
  74. game_title.value.style.height = "0";
  75. game_title.value.style.overflow = "hidden";
  76. setTimeout(() => {
  77. game_title.value.style.height = "auto";
  78. }, 0);
  79. // 模拟 delay 和 slideToggle 效果
  80. setTimeout(() => {
  81. login_btn.value.style.display = "block";
  82. login_btn.value.style.height = "0";
  83. login_btn.value.style.overflow = "hidden";
  84. setTimeout(() => {
  85. login_btn.value.style.height = "auto";
  86. }, 10);
  87. }, 500);
  88. colorChangeTimeW.value = (canHeight.value > canWidth.value ? canWidth.value : canHeight.value) * 0.5;
  89. colorChangeTime_div.value.style.width = colorChangeTimeW * 1.6 + "px";
  90. colorChangeTime_div.value.style.height = colorChangeTimeW * 0.5 + "px";
  91. colorChangeTime_div.value.style.marginLeft = -colorChangeTimeW * 0.8 + "px";
  92. colorChangeTime_div.value.style.lineHeight = colorChangeTimeW * 0.5 + "px";
  93. colorChangeTime_div.value.style.fontSize = colorChangeTimeW * 0.3 + "px";
  94. backrgound.value = new backgroundObj();
  95. backrgound.value.init();
  96. squares.value = new squareObj();
  97. squares.value.init();
  98. mySquare.value = new mySquareObj();
  99. mySquare.value.init();
  100. beginAnim.value = new beginAnimObj();
  101. beginAnim.value.init();
  102. }
  103. function restartInit() {
  104. AnimPX.value = new Array();
  105. AnimPY.value = new Array();
  106. changeColorindex.value = 0;
  107. jump_count.value = 0;
  108. // 隐藏元素
  109. colorChangeTime_div.value.style.display = "none";
  110. score_div.value.style.display = "none";
  111. // 初始化动画
  112. beginAnim.value.init();
  113. // 设置游戏状态
  114. beginGame.value = false;
  115. gameOver.value = true;
  116. lastTime.value = Date.now();
  117. // 设置游戏标题
  118. game_title.value.innerHTML = "方&nbsp;块&nbsp;跳&nbsp;跃";
  119. // 显示游戏标题(模拟slideDown效果)
  120. game_title.value.style.display = "block";
  121. game_title.value.style.height = "0";
  122. game_title.value.style.overflow = "hidden";
  123. setTimeout(() => {
  124. game_title.value.style.height = "auto";
  125. }, 0);
  126. // 延迟显示登录按钮(模拟delay和slideToggle效果)
  127. setTimeout(() => {
  128. login_btn.value.style.display = "block";
  129. login_btn.value.style.height = "0";
  130. login_btn.value.style.overflow = "hidden";
  131. setTimeout(() => {
  132. login_btn.value.style.height = "auto";
  133. }, 10);
  134. }, 500);
  135. // 设置登录按钮文本
  136. login_btn.value.innerHTML = "再来一次";
  137. // 显示状态(模拟slideDown效果)
  138. state_div.value.style.display = "block";
  139. state_div.value.style.height = "0";
  140. state_div.value.style.overflow = "hidden";
  141. setTimeout(() => {
  142. state_div.value.style.height = "auto";
  143. }, 500);
  144. // 设置状态文本
  145. state_div.value.innerHTML = "游戏结束,得分:" + Math.floor(score.value);
  146. }
  147. function game() {
  148. init();
  149. loop.value = setInterval(gameloop, 20);
  150. }
  151. function restart() {
  152. // 调用初始化方法
  153. backrgound.value.init();
  154. squares.value.init();
  155. mySquare.value.init();
  156. // 更新时间戳
  157. lastTime.value = Date.now();
  158. // 隐藏元素
  159. state_div.value.style.display = "none";
  160. game_title.value.style.display = "none";
  161. login_btn.value.style.display = "none";
  162. // 显示分数
  163. score_div.value.style.display = "block";
  164. // 重置分数和速度
  165. score.value = 0;
  166. totalSpeed.value = 3;
  167. }
  168. function gameloop() {
  169. backrgound.value.draw();
  170. ctx2.value.clearRect(0, 0, canWidth.value, canHeight.value);
  171. ctx2.value.save();
  172. if (beginAnim.value.isLive && Date.now() - lastTime.value > 1000) {
  173. beginAnim.value.draw();
  174. }
  175. if (beginGame.value && !gameOver.value) {
  176. scoreText.value = `得分:${Math.floor(score.value)}`;
  177. addSpeed();
  178. squares.value.draw();
  179. mySquare.value.draw();
  180. squaresToMy();
  181. // 添加点击事件监听器
  182. main_box.value.addEventListener("click", function () {
  183. mySquare.value.jump();
  184. });
  185. } else if (gameOver.value && !beginGame.value) {
  186. // 这里可以添加游戏结束时的逻辑
  187. }
  188. ctx2.value.restore();
  189. }
  190. function loginGame() {
  191. changeColorTime.value = Date.now();
  192. // 显示颜色变化时间div
  193. colorChangeTime_div.value.style.display = "block";
  194. // 随机设置颜色
  195. const randomColor =
  196. squareColor[Math.floor(Math.random() * squareColor.length)];
  197. colorChangeTime_div.value.style.color = randomColor;
  198. // 设置颜色变化时间div的内容
  199. colorChangeTime_div.value.innerHTML = "" + changeTimeArrays[changeColorindex.value];
  200. if (!gameOver.value && !beginGame.value) {
  201. // 显示分数,隐藏游戏标题和方块
  202. score_div.value.style.display = "block";
  203. game_title.value.style.display = "none";
  204. square_main.value.style.display = "none";
  205. // 设置游戏状态
  206. beginGame.value = true;
  207. // 隐藏登录按钮
  208. login_btn.value.style.display = "none";
  209. } else if (gameOver.value && !beginGame.value) {
  210. // 重新开始游戏
  211. restart();
  212. // 更新游戏状态
  213. gameOver.value = false;
  214. beginGame.value = true;
  215. }
  216. // 设置动画状态
  217. beginAnim.value.isLive = false;
  218. // 隐藏方块
  219. square_main.value.style.display = "none";
  220. }
  221. function addSpeed() {
  222. totalSpeed.value += 0.04 * 0.05;
  223. score.value += 0.04;
  224. }
  225. function squaresToMy() {
  226. for (var i = 0; i < squares.value.num; i++) {
  227. if (squares.value.isLive[i]) {
  228. if (squares.value.color[i] != mySquare.value.color) {
  229. if (mySquare.value.isLive) {
  230. if (
  231. ((mySquare.value.x + mySquare.value.l - 1 > squares.value.x[i] &&
  232. mySquare.value.x + mySquare.value.l - 1 < squares.value.x[i] + squares.value.w[i] &&
  233. mySquare.value.x + mySquare.value.l - 30 > squares.value.x[i] &&
  234. mySquare.value.x + mySquare.value.l - 30 <
  235. squares.value.x[i] + squares.value.w[i]) ||
  236. (mySquare.value.x > squares.value.x[i] &&
  237. mySquare.value.x + 10 < squares.value.x[i] + squares.value.w[i] &&
  238. mySquare.value.x + 10 > squares.value.x[i] &&
  239. mySquare.value.x + 10 < squares.value.x[i] + squares.value.w[i])) &&
  240. mySquare.value.y + mySquare.value.l > squares.value.y[i] &&
  241. mySquare.value.y + mySquare.value.l < squares.value.y[i] + squares.value.h[i]
  242. ) {
  243. mySquare.value.y = squares.value.y[i] - mySquare.value.l;
  244. mySquare.value.toVSpeed = -totalSpeed.value * 0.2;
  245. mySquare.value.toDownSpeed = 0;
  246. jump_count.value = 0;
  247. }
  248. if (
  249. mySquare.value.x + mySquare.value.l > squares.value.x[i] &&
  250. mySquare.value.x + mySquare.value.l < squares.value.x[i] + squares.value.w[i] &&
  251. mySquare.value.y + mySquare.value.l > squares.value.y[i] &&
  252. mySquare.value.y + mySquare.value.l < squares.value.y[i] + squares.value.h[i]
  253. ) {
  254. mySquare.value.x = squares.value.x[i] - mySquare.value.l;
  255. }
  256. }
  257. }
  258. }
  259. }
  260. }
  261. //背景
  262. class backgroundObj {
  263. constructor() {
  264. this.x = [];
  265. this.y = [];
  266. this.w = [];
  267. this.h = [];
  268. this.isLive = [];
  269. this.num = 3;
  270. }
  271. init() {
  272. for (let i = 0; i < this.num; i++) {
  273. this.x[i] =
  274. i === 0
  275. ? canWidth.value * 0.1 * Math.random()
  276. : this.x[i - 1] +
  277. this.w[i - 1] +
  278. canWidth.value * 0.2 * i * Math.random();
  279. this.w[i] = canWidth.value * 0.08 + canHeight.value * Math.random() * 0.3;
  280. this.h[i] = canHeight.value * 0.08 + canWidth.value * Math.random() * 0.3;
  281. this.y[i] = canHeight.value * 0.2 * Math.random();
  282. this.isLive[i] = true;
  283. }
  284. }
  285. cloudBorn() {
  286. for (let i = 0; i < this.num; i++) {
  287. if (!this.isLive[i]) {
  288. this.w[i] = canWidth.value * 0.08 + canWidth.value * Math.random() * 0.3;
  289. this.h[i] = canHeight.value * 0.08 + canHeight.value * Math.random() * 0.3;
  290. this.y[i] = canHeight.value * 0.2 * Math.random();
  291. this.x[i] = i === 0 ? canWidth.value : canWidth.value + i * this.w[i - 1];
  292. this.isLive[i] = true;
  293. }
  294. }
  295. }
  296. draw() {
  297. ctx1.value.clearRect(0, 0, canWidth.value, canHeight.value);
  298. ctx1.value.save();
  299. for (let i = 0; i < this.num; i++) {
  300. if (!this.isLive[i]) continue;
  301. this.x[i] -= 0.1 * totalSpeed.value;
  302. const maxSize = Math.max(this.h[i], this.w[i]) * 0.15;
  303. const smallSize = Math.max(this.h[i], this.w[i]) * 0.1;
  304. // 绘制云朵的各个部分
  305. const cloudParts = [
  306. { x: 0.4, y: 0.1, size: maxSize },
  307. { x: 0.1, y: 0.2, size: maxSize },
  308. { x: 0.6, y: 0.25, size: maxSize },
  309. { x: 0.5, y: 0.3, size: maxSize },
  310. { x: 0.65, y: 0.22, size: maxSize },
  311. { x: 0.2, y: 0.35, size: maxSize },
  312. { x: 0.35, y: 0.35, size: smallSize },
  313. { x: 0.3, y: 0.1, size: maxSize },
  314. ];
  315. ctx1.value.fillStyle = "#ffffff";
  316. cloudParts.forEach((part) => {
  317. ctx1.value.beginPath();
  318. ctx1.value.arc(
  319. this.x[i] + this.w[i] * part.x,
  320. this.y[i] + this.h[i] * part.y,
  321. part.size,
  322. 0,
  323. Math.PI * 2
  324. );
  325. ctx1.value.fill();
  326. ctx1.value.closePath();
  327. });
  328. if (this.x[i] + this.w[i] < 0) {
  329. this.isLive[i] = false;
  330. }
  331. }
  332. ctx1.value.restore();
  333. this.cloudBorn();
  334. }
  335. }
  336. //底下方块
  337. class squareObj {
  338. constructor() {
  339. this.num = 12;
  340. this.x = [];
  341. this.y = [];
  342. this.w = [];
  343. this.h = [];
  344. this.color = [];
  345. this.isLive = [];
  346. }
  347. init() {
  348. let repeatColorCount = 0;
  349. for (let i = 0; i < this.num; i++) {
  350. // Random color selection with constraints
  351. this.color[i] = this.getRandomColor(i, repeatColorCount);
  352. // Position and size initialization
  353. if (i === 0) {
  354. this.x[i] = 0;
  355. } else {
  356. this.x[i] = this.x[i - 1] + this.w[i - 1] + 1;
  357. }
  358. this.h[i] = canHeight.value * 0.3 + canHeight.value * 0.25 * Math.random();
  359. this.w[i] = canWidth.value * 0.15 + canWidth.value * 0.06 * Math.random();
  360. this.y[i] = canHeight.value - this.h[i];
  361. this.isLive[i] = true;
  362. // Update repeat color count
  363. repeatColorCount =
  364. this.color[i] === this.color[i - 1] ? repeatColorCount + 1 : 0;
  365. // Handle consecutive colors
  366. if (repeatColorCount > 1) {
  367. this.adjustColor(i);
  368. }
  369. }
  370. }
  371. getRandomColor(i: any, repeatColorCount: any) {
  372. const randomIndex = Math.floor(Math.random() * squareColor.length);
  373. let color = squareColor[randomIndex];
  374. // For the first element, check against last element
  375. if (i === 0 && color === this.color[this.num - 1]) {
  376. const lastColorIndex = squareColor.indexOf(
  377. this.color[this.num - 1]
  378. );
  379. color =
  380. squareColor[
  381. (lastColorIndex - 1 + squareColor.length) % squareColor.length
  382. ];
  383. }
  384. // For other elements, check against previous element
  385. else if (
  386. i > 0 &&
  387. color === this.color[i - 1] &&
  388. repeatColorCount > 1
  389. ) {
  390. const currentColorIndex = squareColor.indexOf(color);
  391. color = squareColor[(currentColorIndex + 1) % squareColor.length];
  392. }
  393. return color;
  394. }
  395. adjustColor(i: any) {
  396. if (i === 0) {
  397. const lastColorIndex = squareColor.indexOf(
  398. this.color[this.num - 1]
  399. );
  400. this.color[i] =
  401. squareColor[
  402. (lastColorIndex - 1 + squareColor.length) % squareColor.length
  403. ];
  404. } else {
  405. const currentColorIndex = squareColor.indexOf(this.color[i]);
  406. this.color[i] =
  407. squareColor[(currentColorIndex + 1) % squareColor.length];
  408. }
  409. }
  410. squareBorn() {
  411. const maxX = Math.max(
  412. ...this.x.map((val, idx) => val + (this.w[idx] || 0))
  413. );
  414. const maxI = this.x.indexOf(
  415. maxX - (this.w[this.x.indexOf(maxX)] || 0)
  416. );
  417. for (let i = 0; i < this.num; i++) {
  418. if (!this.isLive[i]) {
  419. this.x[i] = maxX + 1;
  420. this.h[i] = canHeight.value * 0.25 + canHeight.value * 0.35 * Math.random();
  421. this.w[i] = canWidth.value * 0.14 + canWidth.value * 0.1 * Math.random();
  422. this.y[i] = canHeight.value - this.h[i];
  423. let repeatColorCount = 0;
  424. if (i === 0 && this.isLive[this.num - 1]) {
  425. this.color[i] = this.getRandomColorForBorn(
  426. this.num - 1,
  427. repeatColorCount
  428. );
  429. } else if (i > 0 && this.isLive[i - 1]) {
  430. this.color[i] = this.getRandomColorForBorn(
  431. i - 1,
  432. repeatColorCount
  433. );
  434. }
  435. this.isLive[i] = true;
  436. return;
  437. }
  438. }
  439. }
  440. getRandomColorForBorn(prevIndex: any, repeatColorCount: any) {
  441. const randomIndex = Math.floor(Math.random() * 3);
  442. let color = squareColor[randomIndex];
  443. if (color === this.color[prevIndex] && repeatColorCount > 1) {
  444. const currentColorIndex = squareColor.indexOf(color);
  445. color = squareColor[(currentColorIndex + 1) % squareColor.length];
  446. }
  447. return color;
  448. }
  449. draw() {
  450. for (let i = 0; i < this.num; i++) {
  451. if (this.isLive[i]) {
  452. ctx2.value.fillStyle = this.color[i];
  453. ctx2.value.beginPath();
  454. ctx2.value.fillRect(this.x[i], this.y[i], this.w[i], this.h[i]);
  455. ctx2.value.fill();
  456. ctx2.value.closePath();
  457. this.x[i] -= totalSpeed.value;
  458. }
  459. if (this.x[i] + this.w[i] < 0) {
  460. this.isLive[i] = false;
  461. }
  462. }
  463. this.squareBorn();
  464. }
  465. }
  466. //我的方块
  467. class mySquareObj {
  468. constructor() {
  469. this.x;
  470. this.y;
  471. this.isLive; // 生命状态
  472. this.l = 40; // 正方形边长
  473. this.color;
  474. this.toDownSpeed = 0; // 垂直方向速度
  475. this.toVSpeed = 0; // 水平方向速度
  476. }
  477. init() {
  478. this.isLive = true;
  479. this.x = 0;
  480. this.y = 0;
  481. this.l = 40;
  482. this.toDownSpeed = 0;
  483. this.toVSpeed = 0;
  484. this.color = squareColor[0];
  485. }
  486. jump() {
  487. if (this.isLive) {
  488. this.toDownSpeed = -15;
  489. this.toVSpeed = 2;
  490. jump_count.value++;
  491. if (this.x + this.l > canWidth.value) {
  492. this.x = canWidth.value - this.l;
  493. }
  494. }
  495. }
  496. toDown() {
  497. if (this.isLive) {
  498. this.toDownSpeed += 9.8 * 1 * 0.06;
  499. this.y += this.toDownSpeed;
  500. this.x += this.toVSpeed;
  501. if (this.y + this.l > canHeight.value) {
  502. this.isLive = false;
  503. }
  504. }
  505. }
  506. draw() {
  507. if (this.isLive) {
  508. const now = Date.now();
  509. if (now - changeColorTime.value > 1000) {
  510. changeColorindex.value = ++changeColorindex.value % changeTimeArrays.length;
  511. const strColor =
  512. "" +
  513. squareColor[Math.floor(Math.random() * squareColor.length)];
  514. // 设置颜色和内容
  515. colorChangeTime_div.value.style.color = strColor;
  516. colorChangeTime_div.value.textContent =
  517. "" + changeTimeArrays[changeColorindex.value];
  518. if (changeColorindex.value === 10) {
  519. colorChangeTime_div.value.style.fontSize =
  520. colorChangeTimeW * 0.15 + "px";
  521. this.color = strColor;
  522. } else {
  523. colorChangeTime_div.value.style.fontSize =
  524. colorChangeTimeW * 0.3 + "px";
  525. }
  526. changeColorTime.value = now;
  527. }
  528. ctx2.value.fillStyle = this.color + "";
  529. ctx2.value.rect(this.x, this.y, this.l, this.l);
  530. ctx2.value.fill();
  531. ctx2.value.lineWidth = 3;
  532. ctx2.value.radiusX = 3;
  533. ctx2.value.strokeStyle = "#ffffff";
  534. ctx2.value.stroke();
  535. if (this.x < -100) {
  536. this.isLive = false;
  537. }
  538. } else {
  539. restartInit();
  540. }
  541. this.toDown();
  542. }
  543. }
  544. //动画
  545. class beginAnimObj {
  546. constructor() {
  547. this.x;
  548. this.y;
  549. this.isLive;
  550. this.l = 40; // 正方形边长
  551. this.color;
  552. this.toDownSpeed = 0; // 垂直方向速度
  553. this.toVSpeed = canWidth.value * 0.021; // 水平方向速度
  554. }
  555. init() {
  556. this.isLive = true;
  557. this.x = 0;
  558. this.y = 0;
  559. this.toDownSpeed = 0;
  560. this.toVSpeed = canWidth.value * 0.021;
  561. this.color = squareColor[0];
  562. }
  563. jump() {
  564. if (this.isLive) {
  565. this.toDownSpeed = -this.toDownSpeed;
  566. this.toVSpeed = canWidth.value * 0.021 * 0.5;
  567. jump_count.value++;
  568. if (this.x + this.l > canWidth.value) {
  569. this.x = canWidth.value - this.l;
  570. }
  571. this.x += this.toVSpeed;
  572. if (this.toVSpeed + 2 < 3) {
  573. this.toVSpeed += 1;
  574. }
  575. }
  576. }
  577. toDown() {
  578. if (this.isLive) {
  579. this.toDownSpeed += 9.8 * 1 * 0.06;
  580. this.y += this.toDownSpeed;
  581. this.x += this.toVSpeed;
  582. if (this.y > canHeight.value) {
  583. this.isLive = false;
  584. }
  585. }
  586. }
  587. draw() {
  588. if (this.isLive) {
  589. square_main.value.style.display = "block";
  590. square_main.value.style.left = this.x + "px";
  591. square_main.value.style.top = this.y + "px";
  592. if (
  593. this.y + this.l > canHeight.value * 0.35 &&
  594. this.x + this.l * 0.5 < canWidth.value * 0.5 + 120 &&
  595. this.x + this.l * 0.5 > canWidth.value * 0.5 - 120
  596. ) {
  597. this.jump();
  598. game_title.value.innerHTML =
  599. "方&nbsp;块&nbsp;<i style='font-size: 46px;color:#FF6688;'>跳&nbsp;</i>跃";
  600. }
  601. ctx2.value.restore();
  602. this.toDown();
  603. } else {
  604. square_main.value.style.display = "none";
  605. }
  606. }
  607. }
  608. onMounted(() => {
  609. game();
  610. });
  611. onBeforeUnmount(() => {
  612. clearInterval(loop.value);
  613. });
  614. </script>
  615. <style scoped>
  616. * {
  617. padding: 0px;
  618. margin: 0px;
  619. }
  620. a {
  621. text-decoration: none;
  622. list-style: none;
  623. color: rgb(0, 0, 0);
  624. }
  625. #main_box {
  626. margin: 0px auto;
  627. width: 420px;
  628. height: 580px;
  629. background: skyblue;
  630. position: relative;
  631. overflow: hidden;
  632. }
  633. .can {
  634. position: absolute;
  635. top: 0px;
  636. left: 0px;
  637. }
  638. #score {
  639. width: auto;
  640. height: 40px;
  641. font-size: 22px;
  642. color: #7fffd4;
  643. position: absolute;
  644. top: 10px;
  645. left: 10px;
  646. display: none;
  647. }
  648. #game_title {
  649. display: none;
  650. position: absolute;
  651. width: 240px;
  652. height: 80px;
  653. line-height: 80px;
  654. text-align: center;
  655. top: 35%;
  656. left: 50%;
  657. margin-left: -120px;
  658. font-size: 42px;
  659. font-family: "century gothic";
  660. font-weight: bolder;
  661. text-shadow: 4px 3px 2px black;
  662. color: #fff;
  663. }
  664. #login_btn {
  665. display: none;
  666. position: absolute;
  667. bottom: 100px;
  668. left: 50%;
  669. width: 100px;
  670. height: 40px;
  671. margin-left: -50px;
  672. line-height: 40px;
  673. text-align: center;
  674. border-radius: 12px;
  675. border: 2px solid #ffffff;
  676. font-size: 18px;
  677. color: #000000;
  678. font-weight: normal;
  679. background: peachpuff;
  680. }
  681. #login_btn:hover {
  682. color: #fff;
  683. }
  684. #login_btn:active {
  685. background: #ffffff;
  686. color: #000000;
  687. }
  688. #square_main {
  689. width: 40px;
  690. height: 40px;
  691. position: absolute;
  692. top: 0px;
  693. left: 0px;
  694. border: 2px solid #ffffff;
  695. display: none;
  696. background: #ff6688;
  697. }
  698. #state {
  699. width: 280px;
  700. height: 60px;
  701. font-size: 18px;
  702. font-weight: bolder;
  703. text-shadow: #fdf5e6;
  704. color: blueviolet;
  705. font-family: "arial narrow";
  706. position: absolute;
  707. top: 45%;
  708. left: 50%;
  709. line-height: 60px;
  710. text-align: center;
  711. margin-left: -140px;
  712. display: none;
  713. }
  714. #colorChangeTime_div {
  715. width: 200px;
  716. height: 50px;
  717. line-height: 50px;
  718. position: absolute;
  719. text-align: center;
  720. top: 3%;
  721. left: 50%;
  722. display: none;
  723. color: #ffffff;
  724. font-size: 40px;
  725. }
  726. </style>