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
This article records the installation and configu...
Table of contents 1. Introduction: 2. The first i...
Table of contents Linux netstat command 1. Detail...
When making a new version of the configuration in...
Today I will introduce two HTML tags that I don’t...
This question originated from a message on Nugget...
1. nohup Run the program in a way that ignores th...
Say it in advance We all know that Docker can ach...
A simple Linux guessing game source code Game rul...
There are also two servers: Preparation: Set the ...
I started configuring various environments this a...
In some scenarios, we need to modify our varchar ...
Table of contents 1. React.Children.map 2. React....
Table of contents Create a new user Authorize new...
Table of contents Take todolist as an example The...