Welcome to the previous canvas game series: 《VUE implements a Flappy Bird~~~》 Guess the Word Game 《VUE+Canvas realizes desktop pinball brick-breaking game》 《VUE+Canvas implements a typing game of Thunder Fighter》 As the title suggests, everyone has played this game and it can be seen everywhere. Use the left and right direction keys to control the movement of the God of Wealth and catch the gold ingots falling from the sky. When the time is up, the game ends. Let’s take a look at the effect first: Compared to the previous Thunder Fighter that fired bullets flying everywhere, the movement trajectory of the elements this time is very simple, with vertical jewels and horizontally moving God of Wealth. Similar to the previous code, here are the key steps: 1. The God of Wealth moves horizontally with keyboard control This is very simple, similar to the control of the slider in "VUE+Canvas to realize the desktop pinball brick elimination game": drawCaishen() { let _this = this; _this.ctx.save(); _this.ctx.drawImage( _this.caishenImg, _this.caishen.x, _this.caishen.y, 120, 120 ); _this.ctx.restore(); }, moveCaishen() { this.caishen.x += this.caishen.dx; if (this.caishen.x > this.clientWidth - 120) { this.caishen.x = this.clientWidth - 120; } else if (this.caishen.x < 0) { this.caishen.x = 0; } } 2. Jewels that fall from the sky This is also very simple, but it should be noted that the initial x value of the jewels cannot be randomly taken from 0 to clientWidth, because it is easy to cause the jewels to pile up together, affecting the playability of the game, so the jewels are best scattered on different tracks. Here we divide the canvas width into 5 tracks. When the jewels are initially drawn, we scatter them on the track, and the y value is randomly set at a certain height to create a staggered appearance. Then the newly generated jewels are generated according to the track distribution to avoid the jewels being crowded together. generateTreasure() { let _this = this; if (_this.treasureArr.length < MaxNum) { let random = Math.floor(Math.random() * TreasureNames.length); let channel = _this.getRandomArbitrary(1, 5); _this.treasureArr.push({ x: _this.channelWidth * (1 / 2 + (channel - 1)) - 30, y: 0, name: TreasureNames[random], speed: _this.getRandomArbitrary(2, 4) }); } }, filterTreasure(item) { let _this = this; if ( item.x <= _this.caishen.x + 110 && item.x >= _this.caishen.x && item.y > _this.caishen.y ) { // Determine the touching range with the God of Wealth_this.score += _this.treasureObj[item.name].score; return false; } if (item.y >= _this.clientHeight) { return false; } return true; }, drawTreasure() { let _this = this; _this.treasureArr = _this.treasureArr.filter(_this.filterTreasure); _this.treasureArr.forEach(item => { _this.ctx.drawImage( _this.treasureObj[item.name].src, item.x, item.y, 60, 60 ); item.y += item.speed; }); }, getRandomArbitrary(min, max) { return Math.random() * (max - min) + min; } Here we use the filter function to filter out the jewels that should disappear. If we use the for+splice+i-- method, it will cause jitter. Then give each jewel a random movement speed, and when the jewel enters the picture range of the God of Wealth, the corresponding score is accumulated. 3. Countdown ring Set the countdown to 30s. Then in the requestAnimationFrame callback, calculate whether the difference in milliseconds between the current time and the last timestamp is greater than 1000 to calculate the seconds. Then take another timestamp to accumulate progress to achieve smooth movement of the ring. drawCountDown() { // Draw the progress ring let _this = this; _this.progress += Date.now() - _this.timeTag2; _this.timeTag2 = Date.now(); _this.ctx.beginPath(); _this.ctx.moveTo(50, 50); _this.ctx.arc( 50, 50, 40, Math.PI * 1.5, Math.PI * (1.5 + 2 * (_this.progress / (countDownInit * 1000))), false ); _this.ctx.closePath(); _this.ctx.fillStyle = "yellow"; _this.ctx.fill(); // Draw a filled circle_this.ctx.beginPath(); _this.ctx.arc(50, 50, 30, 0, Math.PI * 2); _this.ctx.closePath(); _this.ctx.fillStyle = "#fff"; _this.ctx.fill(); //Fill text_this.ctx.font = "bold 16px Microsoft YaHei"; _this.ctx.fillStyle = "#333"; _this.ctx.textAlign = "center"; _this.ctx.textBaseline = "middle"; _this.ctx.moveTo(50, 50); _this.ctx.fillText(_this.countDown + "s", 50, 50); } (function animloop() { _this.ctx.clearRect(0, 0, _this.clientWidth, _this.clientHeight); _this.loop(); animationId = window.requestAnimationFrame(animloop); if (_this.countDown === 0) { _this.gameOver = true; window.cancelAnimationFrame(animationId); } if (Date.now() - _this.timeTag >= 1000) { _this.countDown--; _this.timeTag = Date.now(); } })(); At this point, a very simple game of the God of Wealth catching gold ingots has been completed. Of course, in order to increase the difficulty, you can set up a segment of dropping bombs continuously. The principle is the same as the movement of jewels. The following is the full code for your reference: <template> <div class="caishen"> <canvas id="caishen" width="1200" height="750"></canvas> <div class="container" v-if="gameOver"> <div class="dialog"> <p class="once-again">Congratulations! </p> <p class="once-again">Treasures in this round: {{ score }} points</p> </div> </div> </div> </template> <script> const TreasureNames = [ "yuanbao", "tongqian", "jintiao", "shuijin_red", "shuijin_blue", "fudai" ]; let animationId = null; let countDownInit = 0; const MaxNum = 5; export default { name: "CaiShen", data() { return { score: 0, ctx: null, caishenImg: null, clientWidth: 0, clientHeight: 0, channelWidth: 0, caishen: x: 0, y: 0, speed: 8, dx: 0 }, progress: 0, countDown: 30, timeTag: Date.now(), timeTag2: Date.now(), treasureArr: [], gameOver: false, treasureObj: { yuanbao: score: 5, src: null }, Tongqian: score: 2, src: null }, jintiao: score: 10, src: null }, shuijin_red: score: 20, src: null }, shuijin_blue: { score: 15, src: null }, fudai: score: 8, src: null } } }; }, mounted() { let _this = this; let container = document.getElementById("caishen"); _this.ctx = container.getContext("2d"); _this.clientWidth = container.width; _this.clientHeight = container.height; _this.channelWidth = Math.floor(_this.clientWidth / 5); _this.caishenImg = new Image(); _this.caishenImg.src = require("@/assets/img/caishen/财神爷.png"); _this.initTreasures(); countDownInit = _this.countDown; _this.caishen.x = _this.clientWidth / 2 - 60; _this.caishen.y = _this.clientHeight - 120; document.onkeydown = function(e) { let key = window.event.keyCode; if (key === 37) { //Left button_this.caishen.dx = -_this.caishen.speed; } else if (key === 39) { //Right button_this.caishen.dx = _this.caishen.speed; } }; document.onkeyup = function(e) { _this.caishen.dx = 0; }; _this.caishenImg.onload = function() { (function animloop() { _this.ctx.clearRect(0, 0, _this.clientWidth, _this.clientHeight); _this.loop(); animationId = window.requestAnimationFrame(animloop); if (_this.countDown === 0) { _this.gameOver = true; window.cancelAnimationFrame(animationId); } if (Date.now() - _this.timeTag >= 1000) { _this.countDown--; _this.timeTag = Date.now(); } })(); }; }, methods: { initTreasures() { let _this = this; Object.keys(_this.treasureObj).forEach(key => { _this.treasureObj[key].src = new Image(); _this.treasureObj[ key ].src.src = require(`@/assets/img/caishen/${key}.png`); }); for (let i = 0; i < MaxNum; i++) { let random = Math.floor(Math.random() * TreasureNames.length); _this.treasureArr.push({ x: _this.channelWidth * (1 / 2 + i) - 30, y: _this.getRandomArbitrary(0, 20), name: TreasureNames[random], speed: _this.getRandomArbitrary(2, 4) }); } }, loop() { let _this = this; _this.drawCountDown(); _this.drawCaishen(); _this.moveCaishen(); _this.generateTreasure(); _this.drawTreasure(); _this.drawScore(); }, drawCaishen() { let _this = this; _this.ctx.save(); _this.ctx.drawImage( _this.caishenImg, _this.caishen.x, _this.caishen.y, 120, 120 ); _this.ctx.restore(); }, moveCaishen() { this.caishen.x += this.caishen.dx; if (this.caishen.x > this.clientWidth - 120) { this.caishen.x = this.clientWidth - 120; } else if (this.caishen.x < 0) { this.caishen.x = 0; } }, drawScore() { let _this = this; _this.ctx.beginPath(); _this.ctx.fillStyle = "#fff"; _this.ctx.textAlign = "center"; _this.ctx.textBaseline = "middle"; _this.ctx.fillText(_this.score + "分", 30, _this.clientHeight - 10); _this.ctx.closePath(); }, drawCountDown() { // Draw the progress ring let _this = this; _this.progress += Date.now() - _this.timeTag2; _this.timeTag2 = Date.now(); _this.ctx.beginPath(); _this.ctx.moveTo(50, 50); _this.ctx.arc( 50, 50, 40, Math.PI * 1.5, Math.PI * (1.5 + 2 * (_this.progress / (countDownInit * 1000))), false ); _this.ctx.closePath(); _this.ctx.fillStyle = "yellow"; _this.ctx.fill(); // Draw a filled circle_this.ctx.beginPath(); _this.ctx.arc(50, 50, 30, 0, Math.PI * 2); _this.ctx.closePath(); _this.ctx.fillStyle = "#fff"; _this.ctx.fill(); //Fill text_this.ctx.font = "bold 16px Microsoft YaHei"; _this.ctx.fillStyle = "#333"; _this.ctx.textAlign = "center"; _this.ctx.textBaseline = "middle"; _this.ctx.moveTo(50, 50); _this.ctx.fillText(_this.countDown + "s", 50, 50); }, filterTreasure(item) { let _this = this; if ( item.x <= _this.caishen.x + 110 && item.x >= _this.caishen.x && item.y > _this.caishen.y ) { // Determine the touching range with the God of Wealth_this.score += _this.treasureObj[item.name].score; return false; } if (item.y >= _this.clientHeight) { return false; } return true; }, drawTreasure() { let _this = this; _this.treasureArr = _this.treasureArr.filter(_this.filterTreasure); _this.treasureArr.forEach(item => { _this.ctx.drawImage( _this.treasureObj[item.name].src, item.x, item.y, 60, 60 ); item.y += item.speed; }); }, getRandomArbitrary(min, max) { return Math.random() * (max - min) + min; }, generateTreasure() { let _this = this; if (_this.treasureArr.length < MaxNum) { let random = Math.floor(Math.random() * TreasureNames.length); let channel = _this.getRandomArbitrary(1, 5); _this.treasureArr.push({ x: _this.channelWidth * (1 / 2 + (channel - 1)) - 30, y: 0, name: TreasureNames[random], speed: _this.getRandomArbitrary(2, 4) }); } } } }; </script> <!-- Add "scoped" attribute to limit CSS to this component only --> <style scoped lang="scss"> #caishen background-color: #b00600; background-image: url("~assets/img/caishen/brick-wall.png"); } .container { position: absolute; top: 0; right: 0; bottom: 0; left: 0; background-color: rgba(0, 0, 0, 0.3); text-align: center; font-size: 0; white-space: nowrap; overflow:auto; } .container:after { content: ""; display: inline-block; height: 100%; vertical-align: middle; } .dialog { width: 400px; height: 300px; background: rgba(255, 255, 255, 0.5); box-shadow: 3px 3px 6px 3px rgba(0, 0, 0, 0.3); display: inline-block; vertical-align: middle; text-align: left; font-size: 28px; color: #fff; font-weight: 600; border-radius: 10px; white-space: normal; text-align: center; .once-again-btn { background: #1f9a9a; border: none; color: #fff; } } </style> This is the end of this article about VUE+Canvas realizing the God of Wealth receiving ingots game. For more relevant Vue receiving ingots game content, please search 123WORDPRESS.COM's previous articles or continue to browse the following related articles. I hope everyone will support 123WORDPRESS.COM in the future! You may also be interested in:
|
<<: Code analysis of user variables in mysql query statements
>>: Linux CentOS6.9 installation graphic tutorial under VMware
1. Environmental Description (1) CentOS-7-x86_64,...
Ubuntu 18.04, other versions of Ubuntu question: ...
<br />Choose the most practical one to talk ...
Table of contents 1. Install Node Exporter 2. Ins...
In Linux system, both chmod and chown commands ca...
Scenario: An inspection document has n inspection...
1. Add in package.json "main": "el...
1. Check the kali linux system version Command: c...
During the development and debugging process, it ...
WeChat applet: Simple calculator, for your refere...
CSS naming rules header: header Content: content/c...
Table of contents Written in front Environment de...
<br />Question: How to write in HTML to jump...
01. Command Overview dirname - strip non-director...
Without further ado, let me give you the code. Th...