20251109-3

news/2025/11/9 20:31:22/文章来源:https://www.cnblogs.com/Leesz/p/19205219

经过今天晚上近两个小时的努力,终于初具雏形了!!

添加功能如下:

1.增加了计量分数,和金币的功能。

2.增加了属性加点功能。

3.增加了怪物的增长曲线。

4.增加了界面跳转和回合重置。

也能应该够格算一个纯前端的简单的割草小游戏demo了吧。

等日后再去优化拓展其他功能。

html代码如下:

  1 <!DOCTYPE html>
  2 <html lang="en">
  3 
  4 <head>
  5   <meta charset="UTF-8">
  6   <meta name="viewport" content="width=device-width, initial-scale=1.0">
  7   <title>Document</title>
  8 </head>
  9 <style>
 10   body {
 11     margin: 0;
 12     overflow: hidden;
 13   }
 14 </style>
 15 
 16 <body>
 17   <canvas id="Canvas" style="border:1px solid #000000;"></canvas>
 18 </body>
 19 <script>
 20   //全局属性初始化
 21   let running = false;
 22   let score = 0;
 23   let gold = 0;
 24   let maxMonsterCount = 1;
 25   let currentPlayerCount = 0;
 26   let currentMonsterCount = 0;
 27   let maxPlayerHp = 10;
 28   let playerAt = 1;
 29   let playerAttackwidth = 80;
 30   let playerAttackheight = 40;
 31   let maxMonsterHp = 5;
 32   let monsterAt = 1;
 33   //初始化画布
 34   const canvas = document.getElementById('Canvas');
 35   canvas.width = window.innerWidth;
 36   canvas.height = window.innerHeight;
 37   canvas.style.backgroundColor = '#000000';
 38   const ctx = canvas.getContext('2d');
 39   //定义游戏对象数组
 40   const players = [];
 41   const grounds = [];
 42   const monsters = [];
 43   //定义玩家类
 44   class Player {
 45     //基础属性
 46     maxHp = 10;
 47     hp = 10;
 48     x = Math.round(canvas.width / 2);
 49     y = Math.round(canvas.height / 2);
 50     width = 30;
 51     height = 30;
 52     color = '#FF0000';
 53     invincibleColor = 'white';
 54     speedX = 0;
 55     speedY = 0;
 56     a = 0.05;
 57     g = 0.1;
 58     maxSpeedX = 3;
 59     maxSpeedY = 3;
 60 
 61     lastAttackedTime = Date.now();
 62 
 63     status = {
 64       up: false,
 65       down: false,
 66       left: false,
 67       right: false,
 68 
 69       landing: false,
 70       toward: 'right',
 71       attacking: false,
 72       invincible: false,
 73     }
 74 
 75     damage = {
 76       at: 1,
 77       width: 80,
 78       height: 40,
 79     }
 80     //构造函数
 81     constructor() {
 82       this.maxHp = maxPlayerHp;
 83       this.hp = this.maxHp;
 84       this.damage.at = playerAt;
 85       this.damage.width = playerAttackwidth;
 86       this.damage.height = playerAttackheight;
 87     }
 88 
 89     //方法
 90 
 91     //跳跃方法
 92     jump() {
 93       this.speedY = -5;
 94       this.status.landing = false;
 95     }
 96     //玩家运动
 97     move() {
 98       this.x += this.speedX;
 99       this.y += this.speedY;
100     }
101     //碰撞监测
102     checkCrash() {
103       //陆地检测
104       grounds.forEach(Ground => {
105         //下落碰撞检测
106         if (Ground.y - (this.y + this.height) <= 0 &&
107           Ground.y - (this.y + this.height) >= -this.speedY &&
108           this.x + this.width > Ground.x &&
109           this.x < Ground.x + Ground.width
110         ) {
111           this.y = Ground.y - this.height;
112           this.status.landing = true;
113         }
114         //左侧
115         if (
116           this.x < Ground.x + Ground.width &&
117           this.x > Ground.x + Ground.width + this.speedX &&
118           this.y + this.height > Ground.y &&
119           this.y < Ground.y + Ground.height
120         ) {
121           this.x = Ground.x + Ground.width;
122           this.speedX = 0;
123           this.status.left = false;
124         }
125         //右侧
126         if (
127           this.x + this.width > Ground.x &&
128           this.x + this.width < Ground.x + this.speedX &&
129           this.y + this.height > Ground.y &&
130           this.y < Ground.y + Ground.height
131         ) {
132           this.x = Ground.x - this.width;
133           this.speedX = 0;
134           this.status.right = false;
135         }
136       });
137       //边界检测
138       if (this.x < 0) {
139         this.x = 0;
140         this.speedX = 0;
141       }
142       if (this.x + this.width > canvas.width) {
143         this.x = canvas.width - this.width;
144         this.speedX = 0;
145       }
146       if (this.y < 0) {
147         this.y = 0;
148         this.speedY = 0;
149       }
150       if (this.y + this.height > canvas.height) {
151         this.y = canvas.height - this.height;
152         this.status.landing = true;
153       }
154     }
155     //重力作用
156     applyGravity() {
157       if (this.status.landing == false) {
158         this.speedY += this.g;
159         if (this.speedY > this.maxSpeedY)
160           this.speedY = this.maxSpeedY;
161       } else {
162         this.speedY = 0;
163       }
164     }
165     //水平无操作时水平减速
166     velocityDecay() {
167       if ((this.status.left == false && this.status.right == false) || (this.status.left == true && this.status.right == true)) {
168         if (this.speedX > 0) {
169           this.speedX -= this.a;
170           if (this.speedX < 0) this.speedX = 0;
171         } else if (this.speedX < 0) {
172           this.speedX += this.a;
173           if (this.speedX > 0) this.speedX = 0;
174         }
175       }
176     }
177     //水平加速度操作速度
178     controlSpeed() {
179       if (this.status.left) {
180         this.speedX -= this.a;
181         if (this.speedX < -this.maxSpeedX) this.speedX = -this.maxSpeedX;
182       }
183       if (this.status.right) {
184         this.speedX += this.a;
185         if (this.speedX > this.maxSpeedX) this.speedX = this.maxSpeedX;
186       }
187     }
188     //绘制玩家
189     draw() {
190       if (this.status.invincible)
191         ctx.fillStyle = this.invincibleColor;
192       else
193         ctx.fillStyle = this.color;
194       ctx.fillRect(this.x, this.y, this.width, this.height);
195     }
196     //展示血量数字
197     showHp() {
198       ctx.fillStyle = 'white';
199       ctx.font = '12px Arial';
200       ctx.fillText(this.hp, this.x + this.width / 2 - 6, this.y - 2);
201     }
202     //攻击方法
203     attack(m) {
204       m.hp -= this.damage.at;
205       if (m.hp <= 0) {
206         const index = monsters.indexOf(m);
207         if (index > -1) {
208           monsters.splice(index, 1);
209           currentMonsterCount -= 1;
210           gold += 1;
211           score += m.maxHp;
212         }
213       }
214     }
215     //绘制攻击范围与攻击判定
216     drawAttackRange() {
217       //绘制范围
218       if (this.status.attacking) {
219         ctx.fillStyle = '#FFFF00';
220         if (this.status.toward == 'right') {
221           ctx.fillRect(this.x + this.width, this.y + (this.height - this.damage.height) / 2, this.damage.width, this.damage.height);
222         } else if (this.status.toward == 'left') {
223           ctx.fillRect(this.x - this.damage.width, this.y + (this.height - this.damage.height) / 2, this.damage.width, this.damage.height);
224         }
225         //攻击判定
226         monsters.forEach(m => {
227           if (this.status.toward == 'right' &&
228             m.x < this.x + this.width + this.damage.width &&
229             m.x + m.width > this.x + this.width &&
230             m.y < this.y + (this.height + this.damage.height) / 2 &&
231             m.y + m.height > this.y + (this.height - this.damage.height) / 2
232           ) {
233             this.attack(m);
234           }
235           else if (
236             this.status.toward == 'left' &&
237             m.x + m.width > this.x - this.damage.width &&
238             m.x < this.x &&
239             m.y < this.y + (this.height + this.damage.height) / 2 &&
240             m.y + m.height > this.y + (this.height - this.damage.height) / 2
241           ) {
242             this.attack(m);
243           }
244         })
245         this.status.attacking = false;
246       }
247     }
248     //受击方法
249     attacked() {
250       monsters.forEach(m => {
251         if (
252           m.x < this.x + this.width &&
253           m.x + m.width > this.x &&
254           m.y < this.y + this.height &&
255           m.y + m.height > this.y
256         ) {
257           this.reduceHp(m.at);
258           if (this.hp <= 0) {
259             currentPlayerCount -= 1;
260           }
261         }
262       });
263     }
264     //常规血量减少
265     reduceHp(at) {
266       const currentTime = Date.now();
267       if (currentTime - this.lastAttackedTime > 1000) {
268         this.hp -= at;
269         this.status.invincible = true;
270         this.lastAttackedTime = currentTime;
271         //异步延迟
272         setTimeout(() => {
273           this.status.invincible = false;
274         }, 1000);
275       }
276     }
277   }
278   //定义地面类
279   class Ground {
280     x = 0;
281     y = 0;
282     width = 0;
283     height = 0;
284     color = '#654321';
285 
286     constructor(x, y, width, height) {
287       this.x = x;
288       this.y = y;
289       this.width = width;
290       this.height = height;
291     }
292   }
293   //定义怪物类
294   class Monster {
295     maxHp = 5;
296     hp = 5;
297     at = 1;
298     x = 0;
299     y = 0;
300     width = 30;
301     height = 30;
302     invincibleColor = 'white';
303     speedX = 0;
304     speedY = 0;
305     a = 0.03;
306     g = 0.1;
307     maxSpeedX = 2;
308     maxSpeedY = 3;
309     color = '#00FF00';
310 
311     status = {
312       up: false,
313       down: false,
314       left: false,
315       right: false,
316 
317       landing: false,
318       toward: 'right',
319       attacking: false,
320       invincible: false,
321     }
322 
323     constructor(x, y, width, height) {
324       this.x = x;
325       this.y = y;
326       this.width = width;
327       this.height = height;
328       this.maxHp = maxMonsterHp;
329       this.hp = this.maxHp;
330       this.at = monsterAt;
331     }
332     //绘制怪物
333     draw() {
334       ctx.fillStyle = this.color;
335       ctx.fillRect(this.x, this.y, this.width, this.height);
336     }
337     //展示血量数字
338     showHp() {
339       ctx.fillStyle = 'white';
340       ctx.font = '12px Arial';
341       ctx.fillText(this.hp, this.x + this.width / 2 - 6, this.y - 2);
342     }
343     //怪物运动
344     move() {
345       this.x += this.speedX;
346       this.y += this.speedY;
347     }
348     //水平加速度操作速度
349     controlSpeed() {
350       if (this.status.left) {
351         this.speedX -= this.a;
352         if (this.speedX < -this.maxSpeedX) this.speedX = -this.maxSpeedX;
353       }
354       if (this.status.right) {
355         this.speedX += this.a;
356         if (this.speedX > this.maxSpeedX) this.speedX = this.maxSpeedX;
357       }
358     }
359     //判断玩家位置并移动
360     pursuePlayer(p) {
361       if (p.x < this.x) {
362         this.status.left = true;
363         this.status.right = false;
364       } else if (p.x > this.x) {
365         this.status.right = true;
366         this.status.left = false;
367       } else {
368         this.status.left = false;
369         this.status.right = false;
370       }
371     }
372     //重力作用
373     applyGravity() {
374       if (this.status.landing == false) {
375         this.speedY += this.g;
376         if (this.speedY > this.maxSpeedY)
377           this.speedY = this.maxSpeedY;
378       } else {
379         this.speedY = 0;
380       }
381     }
382     //碰撞监测
383     checkCrash() {
384       grounds.forEach(Ground => {
385         //下落碰撞检测
386         if (Ground.y - (this.y + this.height) <= 0 &&
387           Ground.y - (this.y + this.height) >= -this.speedY &&
388           this.x + this.width > Ground.x &&
389           this.x < Ground.x + Ground.width) {
390           this.y = Ground.y - this.height;
391           this.status.landing = true;
392         }
393         //左侧
394         if (
395           this.x < Ground.x + Ground.width &&
396           this.x > Ground.x + Ground.width + this.speedX &&
397           this.y + this.height > Ground.y &&
398           this.y < Ground.y + Ground.height
399         ) {
400           this.x = Ground.x + Ground.width;
401           this.speedX = 0;
402         }
403         //右侧
404         if (
405           this.x + this.width > Ground.x &&
406           this.x + this.width < Ground.x + this.speedX &&
407           this.y + this.height > Ground.y &&
408           this.y < Ground.y + Ground.height
409         ) {
410           this.x = Ground.x - this.width;
411           this.speedX = 0;
412         }
413       });
414       //边界检测
415       if (this.x < 0) {
416         this.x = 0;
417         this.speedX = 0;
418       }
419       if (this.x + this.width > canvas.width) {
420         this.x = canvas.width - this.width;
421         this.speedX = 0;
422       }
423       if (this.y < 0) {
424         this.y = 0;
425         this.speedY = 0;
426       }
427       if (this.y + this.height > canvas.height) {
428         this.y = canvas.height - this.height;
429         this.status.landing = true;
430       }
431     }
432   }
433 
434   //辅助函数
435   {
436     //开始
437     function start() {
438       running = true;
439       createPlayer();
440       createMonster();
441       animate();
442     }
443     //生成指定范围随机整数
444     function randomInt(min, max) {
445       min = Math.ceil(min);
446       max = Math.floor(max);
447       return Math.floor(Math.random() * (max - min + 1)) + min;
448     }
449     //生成玩家
450     function createPlayer() {
451       const p = new Player();
452       players.push(p);
453       currentPlayerCount += 1;
454     }
455     //生成怪物
456     function createMonster() {
457       for (let i = monsters.length; i < maxMonsterCount; i++) {
458         const m = new Monster(randomInt(0, canvas.width - 30), 0, 30, 30);
459         monsters.push(m);
460         currentMonsterCount += 1;
461       }
462     }
463     //怪物升级
464     function monsterLevelUp() {
465       monsterAt += 1;
466       maxMonsterCount += 2;
467       maxMonsterHp += 5;
468     }
469   }
470   //ui界面
471   {
472     //绘制顶栏
473     function drawSection() {
474       ctx.fillStyle = 'white';
475       ctx.font = '20px Arial Border';
476       ctx.fillText('分数: ' + score, 20, 30);
477       ctx.fillText('金币: ' + gold, 20, 60)
478     }
479     //绘制加点界面
480     function drawPointAddUi() {
481       ctx.fillStyle = 'white';
482       ctx.font = '30px Arial Border';
483       ctx.fillText('当前金币: ' + gold, 20, 60)
484       ctx.fillText('按下对应按键选择你的加点,按空格继续游戏', canvas.width / 2 - 200, canvas.height / 4 + 40 * 0);
485       ctx.fillText('每次加点消耗金币x1', canvas.width / 2 - 200, canvas.height / 4 + 40 * 1);
486       ctx.fillText('1 - 生命+5,当前生命最大值: ' + maxPlayerHp, canvas.width / 2 - 200, canvas.height / 4 + 40 * 3);
487       ctx.fillText('2 - 伤害+1,当前伤害: ' + playerAt, canvas.width / 2 - 200, canvas.height / 4 + 40 * 4);
488       ctx.fillText('3 - 攻击宽度+10,当前攻击宽度: ' + playerAttackwidth, canvas.width / 2 - 200, canvas.height / 4 + 40 * 5);
489       ctx.fillText('4 - 攻击高度+10,当前攻击高度: ' + playerAttackheight, canvas.width / 2 - 200, canvas.height / 4 + 40 * 6);
490     }
491   }
492 
493   //创建初始地面对象
494   const ground1 = new Ground(0, Math.round(canvas.height - 100), Math.round(canvas.width), 100);
495   grounds.push(ground1);
496 
497   //键盘事件监听
498 
499   //1.按下按键
500   document.addEventListener('keydown', function (event) {
501     switch (event.key) {
502       case 'ArrowUp':
503         if (players[0].status.landing == true)
504           players[0].jump();
505         break;
506       case 'ArrowDown':
507         players[0].status.down = true;
508         break;
509       case 'ArrowLeft':
510         players[0].status.left = true;
511         players[0].status.toward = 'left';
512         break;
513       case 'ArrowRight':
514         players[0].status.right = true;
515         players[0].status.toward = 'right';
516         break;
517       case 'z':
518         players[0].status.attacking = true;
519         break;
520       case 'Z':
521         players[0].status.attacking = true;
522         break;
523       case '1':
524         if (!running && gold >= 1) {
525           ctx.clearRect(0, 0, canvas.width, canvas.height)
526           maxPlayerHp += 5;
527           gold--;
528           drawPointAddUi();
529         } else {
530           alert('金币不足!')
531         } break;
532       case '2':
533         if (!running && gold >= 1) {
534           ctx.clearRect(0, 0, canvas.width, canvas.height)
535           playerAt += 1;
536           gold--;
537           drawPointAddUi();
538         } else {
539           alert('金币不足!')
540         } break;
541       case '3':
542         if (!running && gold >= 1) {
543           ctx.clearRect(0, 0, canvas.width, canvas.height)
544           playerAttackwidth += 10;
545           gold--;
546           drawPointAddUi();
547         } else {
548           alert('金币不足!')
549         } break;
550       case '4':
551         if (!running && gold >= 1) {
552           ctx.clearRect(0, 0, canvas.width, canvas.height)
553           playerAttackheight += 10;
554           gold--;
555           drawPointAddUi();
556         } else {
557           alert('金币不足!')
558         } break;
559       case ' ':
560         if (!running)
561           start();
562         break;
563     }
564   });
565   //2.松开按键
566   document.addEventListener('keyup', function (event) {
567     switch (event.key) {
568       case 'ArrowUp':
569         break;
570       case 'ArrowDown':
571         players[0].status.down = false;
572         break;
573       case 'ArrowLeft':
574         players[0].status.left = false;
575         break;
576       case 'ArrowRight':
577         players[0].status.right = false;
578         break;
579     }
580   });
581   //3.c键查看玩家状态
582   document.addEventListener('keydown', function (event) {
583     if (event.key === 'c' || event.key === 'C') {
584       console.log("玩家状态:", players[0]);
585     }
586 
587   });
588   //动画循环
589   function animate() {
590     ctx.clearRect(0, 0, canvas.width, canvas.height);
591 
592     //绘制顶栏
593     drawSection();
594 
595     //绘制陆地
596     grounds.forEach(Ground => {
597       ctx.fillStyle = Ground.color;
598       ctx.fillRect(Ground.x, Ground.y, Ground.width, Ground.height);
599     });
600 
601     //玩家
602     {
603       //玩家运动
604       players[0].move();
605       //碰撞监测
606       players[0].checkCrash();
607       //重力作用
608       players[0].applyGravity();
609       //水平无操作时水平减速
610       players[0].velocityDecay();
611       //水平加速度操作速度
612       players[0].controlSpeed();
613       //受到伤害方法
614       players[0].attacked()
615       //绘制玩家
616       players[0].draw();
617       //展示血量
618       players[0].showHp();
619       //绘制攻击范围
620       players[0].drawAttackRange();
621     }
622 
623     //怪物
624     {
625       monsters.forEach(m => {
626         //下落碰撞检测
627         m.checkCrash();
628         //重力作用
629         m.applyGravity();
630         //绘制怪物
631         m.draw();
632         //展示血量
633         m.showHp();
634         //怪物运动
635         m.pursuePlayer(players[0])
636         //水平加速度操作速度
637         m.controlSpeed();
638         //怪物移动
639         m.move();
640       });
641 
642     }
643     //清图判定
644     if (currentMonsterCount == 0) {
645       running = false;
646       ctx.clearRect(0, 0, canvas.width, canvas.height);
647 
648       monsters.length = 0;
649       currentMonsterCount = 0;
650       players.length = 0;
651       currentPlayerCount = 0;
652 
653       monsterLevelUp();
654       drawPointAddUi();
655       return;
656     }
657     //玩家死亡判定
658     if (currentPlayerCount <= 0) {
659       running = false;
660       ctx.clearRect(0, 0, canvas.width, canvas.height);
661 
662       monsters.length = 0;
663       currentMonsterCount = 0;
664       players.length = 0;
665       currentPlayerCount = 0;
666 
667       ctx.fillStyle = 'white';
668       ctx.font = '60px Arial Border';
669       ctx.fillText('You Died', canvas.width / 2 - 100, canvas.height / 2-100)
670       ctx.font = '30px Arial Border';
671       ctx.fillText('最终分数: ' + score, canvas.width / 2 - 100, canvas.height / 2)
672       return;
673     }
674     requestAnimationFrame(animate);
675   }
676   //启动!!
677   start();
678 </script>
679 
680 </html>

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/960718.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

kettle从入门到精通 第110课 ETL之kettle webspoon的两种部署方式docker+tomcat使用教程

大家好,经常有小伙伴私信我咨询webspoon的部署问题,今天周末抽点时间一起梳理学习下。 1、docker方式部署 1)docker方式部署可以参考我之前的文章【kettle从入门到精通 第四十八课 ETL之kettle webspoon】 2)有时候…

【达梦数据库】性能优化-转正官网

【达梦数据库】性能优化-转正官网一、前言 1.1 概述 性能优化是指在不影响系统运行正确性的前提下,使之运行地更快,完成特定功能所需的时间更短。达梦数据库性能优化主要包含以下内容: @list l0:level1{ mso-level-…

Python中`a = 10`的6种读法对比:哪种最贴合名字-对象模型?

以下是针对a = 10语句设计的6种常见读法,结合Python名字-对象绑定模型(呼应前文《西游记》“符咒-山”比喻),通过列表对比各读法的优劣,最终明确适配Python认知的最优选择: Python中a = 10的6种读法对比:哪种最…

netgear r6220 路由器,刷openwrt后,体系备份还原

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

文字识别准确度

文字识别准确度coding: utf-8 import torch import torch.nn as nn import torch.optim as optim from torch.utils.data import Dataset, DataLoader from torchvision import transforms from PIL import Image, Ima…

原生多模态AI架构:统一训练与跨模态推理的环境实现与性能优化

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

VBA之Word应用第四章第三节:段落集合Paragraphs对象的手段(一)

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

日记?

还是写一写的好虽然叫日记但是并不是日日记,差不多就是有话就写没话不硬挤吧。 尽量避免写垃圾话(存疑)。 不喜欢流水账,流水账太无聊了,写流水账的就应该重修小学学位攻读废话博士。 2025.11.9 前几天因为心态彻…

2025校运会小记

2025 校运会小记 前言 update 2025.11.09 本来拖到这么久还没有开始写,大概是要咕咕掉了的。但是想到这个运动会还是太有意思了,所以写吧。这篇应该没有照片,因为懒得放,因为放照片是不是得把其他人(以及我自己?…

安卓项目调用摄像头或相机。调用不了相机解决方案

这里推荐两篇文章: https://blog.csdn.net/weixin_31569663/article/details/148461910 这个是介绍了如何声明和请求相机及存储权限,然后详细说明了使用Camera API的基本流程,包括启动预览、拍照及图片保存。之后,…

2025 年 11 月上海老房翻新装修公司推荐排行榜,毛胚房改造/局部翻新/设计施工/水电改造/现代简约/奶油风格/法式风格/地中海风格/中式风格/全包装修/半包装修公司推荐

2025 年 11 月上海老房翻新装修公司推荐排行榜,毛胚房改造/局部翻新/设计施工/水电改造/现代简约/奶油风格/法式风格/地中海风格/中式风格/全包装修/半包装修公司推荐随着上海城市更新的持续推进,老房翻新与毛胚房改…

用《西游记》讲透Python name模型:撕最后一张符咒,山为何会消失?

用《西游记》讲透Python name模型:撕最后一张符咒,山为何会消失? 看过《西游记》的人都记得一个经典场景:孙悟空大闹天宫后,被如来佛祖压在五行山下,山顶还贴了一张写着“唵嘛呢叭咪吽”的符咒——这张符咒如同“…

鸿蒙应用开发实战:实现分享卡片保存为图片功能

本文将详细介绍如何在鸿蒙应用中实现将UI组件保存为图片并存储到相册的功能,通过componentSnapshot和photoAccessHelper等核心API,为用户提供便捷的分享体验。功能概述 在现代移动应用中,分享功能是提升用户活跃度和…

详细介绍:【Visual Studio】Visual Studio Community 安装已完成,但出现警告:无法安装 sqlsysclrtypes

详细介绍:【Visual Studio】Visual Studio Community 安装已完成,但出现警告:无法安装 sqlsysclrtypespre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: …

nvidia边缘计算平台 —— Jetson AGX Thor —— 英伟达NVIDIA Jetson AGX Thor 128G开发者套件 AI智能 T5000模组

nvidia边缘计算平台 —— Jetson AGX Thor —— 英伟达NVIDIA Jetson AGX Thor 128G开发者套件 AI智能 T5000模组本博客是博主个人学习时的一些记录,不保证是为原创,个别文章加入了转载的源地址,还有个别文章是汇总…

知识学报:树算法(1)

未完成不是题解不是教学!!! 11.7 CSES 1674 给定一颗树求他的子树有多少节点。不提。 CSES 1130 给定一棵树,要求选一些边,要求这些边连接的点没有重复。问最多选多少条边。 简单的树形 dp,对每个点统计以它为根…

[译] CQRS Without The Complexity

原文链接:https://docs.eventsourcingdb.io/blog/2025/11/06/cqrs-without-the-complexity/想象一下,你正站在本地图书馆的柜台前。你想借一本书——就比如《2001:太空奥德赛》。你告诉图书管理员,他们检查书是否在…

Jetson AGX Thor —— 英伟达NVIDIA Jetson AGX Thor 128G开发者套件 AI智能 T5000模组

Jetson AGX Thor —— 英伟达NVIDIA Jetson AGX Thor 128G开发者套件 AI智能 T5000模组本博客是博主个人学习时的一些记录,不保证是为原创,个别文章加入了转载的源地址,还有个别文章是汇总网上多份资料所成,在这之…

科技赋能塞上农业:宁夏从黄土地到绿硅谷的蝶变 - 详解

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

Python 循环引用怎么破?用 weakref 轻松解决 GC 回收难题

Python 循环引用怎么破?用 weakref 轻松解决 GC 回收难题 如果你开发过链表、树、图等数据结构,大概率会遇到一个棘手问题:明明用del删除了所有对象的引用,内存却依然居高不下 —— 这就是 “循环引用” 导致的 GC…