【HTML5游戏开发教程】零基础入门合成大西瓜游戏实战 | JS物理引擎+Canvas动画+完整源码详解

《从咖啡杯到财务自由:一个程序员的合成之旅——当代码遇上物理引擎的匠心之作》

🌟 这是小游戏开发系列的第四篇送福利文章,感谢一路以来支持和关注这个项目的每一位朋友!

💡 文章力求严谨,但难免有疏漏之处,欢迎各位朋友指出,让我们一起在交流中进步。

💌 如果您有任何想法、建议或疑问,都欢迎在评论区留言或通过私信与我交流。您的每一个反馈都是项目进步的动力!

这款游戏不仅融合了流行的合成玩法,更加入了大量程序员文化元素,让我们在休闲娱乐的同时,感受到浓浓的技术氛围。

合成大西瓜Pro版 - 纯程序猿元素风
合成大西瓜Pro版

文章目录

  • 《从咖啡杯到财务自由:一个程序员的合成之旅——当代码遇上物理引擎的匠心之作》
    • 游戏介绍:从咖啡杯到财务自由
    • 演示视频:
    • 部分截图:
    • 技术栈:轻量而强大
    • 模块详解:游戏架构拆解
      • 1. 核心游戏模块 (Game.js)
      • 2. 物品渲染模块 (ItemRenderer.js)
      • 3. 音频管理模块 (AudioManager.js)
      • 4. IDE风格控制台 (ConsoleManager.js)
      • 5. 彩蛋系统:游戏点睛之笔
      • 主要彩蛋类型:
    • 开发难点与解决方案
      • 1. 物理碰撞的稳定性
      • 2. 游戏性能优化
      • 项目代码:
    • 写在最后

游戏介绍:从咖啡杯到财务自由

“程序员版合成大西瓜"是一款基于物理引擎的休闲合成游戏,专为程序员群体量身定制。游戏的主要目标是通过合成相同物品,一步步从最基础的程序员日常用品(咖啡杯)开始,最终合成象征成功的"财务自由”。

游戏流程十分直观:

  1. 玩家点击屏幕顶部,投放物品(初始为咖啡杯)
  2. 物品会根据物理规则自由下落并互相碰撞
  3. 当两个相同物品碰撞并满足特定条件时,会合成为更高级的物品
  4. 随着得分增加,玩家的"程序员等级"会提升,解锁更多游戏内容
  5. 当物品堆积过高达到警戒线时,游戏结束

我们设计了一条充满程序员文化的合成路径:

咖啡杯(☕) → 键盘(⌨️) → 笔记本(💻) → 显示器(🖥️) → 主机(🖥️) → 服务器(🖧) → 财务自由(💰)

每一级合成都会带来翻倍的分数回报:从咖啡杯的2分,到财务自由的128分。当玩家成功合成三个"财务自由"时,将触发游戏通关彩蛋,获得专属的程序员成就证书!

演示视频:

合成大西瓜Pro版-程序员风

部分截图:

本游戏有非常非常多的彩蛋,每种彩蛋触发时机不同,需要玩家自行探索~~~

首页:
在这里插入图片描述

财富自由彩蛋:
在这里插入图片描述

终极彩蛋:

在这里插入图片描述

技术栈:轻量而强大

为了确保游戏运行流畅且易于扩展,我们精心选择了以下技术栈:

  • 前端基础:HTML5、CSS3、JavaScript (ES6+)
  • 构建工具:Vite(提供极速的开发体验)
  • 物理引擎:Matter.js(处理游戏物体的物理行为和碰撞)
  • 包管理:npm

值得一提的是,我们没有使用任何重量级前端框架(如React、Vue),而是选择了纯原生JavaScript实现。这不仅减轻了项目体积,提升了加载速度,还降低了学习门槛,让更多对游戏开发感兴趣的朋友能够轻松理解代码结构。

模块详解:游戏架构拆解

1. 核心游戏模块 (Game.js)

这是整个游戏的中枢神经系统,负责协调各个模块的工作,管理游戏状态和物理世界。

核心功能

  • 物理世界的创建与管理
  • 游戏主循环的实现
  • 物品合成逻辑的控制
  • 分数计算与等级提升
  • 游戏状态(开始、暂停、结束)管理

引擎初始化代码

constructor() {// Matter.js 模块初始化this.engine = Matter.Engine.create({enableSleeping: true,constraintIterations: 3,positionIterations: 8,velocityIterations: 6,timing: {timeScale: 1.1,timestamp: 0}})// 创建运行器,固定帧率this.runner = Matter.Runner.create({isFixed: true,delta: 1000 / 60  // 固定60帧})// 设置渲染器this.render = Matter.Render.create({element: document.getElementById('app'),engine: this.engine,options: {width: GAME_CONFIG.width,height: GAME_CONFIG.height,wireframes: false,background: 'transparent',pixelRatio: window.devicePixelRatio || 1,fps: 60}})// 设置重力this.engine.gravity.y = PHYSICS_CONFIG.gravity
}

这段代码展示了如何初始化物理引擎。我们精心调整了物理参数,以确保游戏体验的流畅性。特别是positionIterationsvelocityIterations参数的提高,使物理模拟更加精确,减少了物体穿透的可能性。

开发难点
物品合成判定是最大的挑战之一。为了实现自然流畅的合成体验,我们采用了复合判定条件:结合物品间的距离、接触时间以及相对速度三个关键因素。这种方法解决了合成触发不稳定的问题,提升了游戏的可玩性。

// 碰撞检测与合并逻辑
Matter.Events.on(this.engine, 'collisionStart', (event) => {if (this.isPaused || this.gameOver) returnevent.pairs.forEach((pair) => {const { bodyA, bodyB } = pair// 检查两个物体是否相同类型且不在活动合并列表中if (bodyA.itemType && bodyB.itemType && bodyA.itemType.name === bodyB.itemType.name) {const pairId = [bodyA.id, bodyB.id].sort().join('-')// 避免重复添加if (!activeMergingPairs.has(pairId) && !collisionPairs.has(pairId)) {// 记录碰撞信息collisionPairs.set(pairId, {bodyA, bodyB,time: Date.now(),contactPoint: {x: (bodyA.position.x + bodyB.position.x) / 2,y: (bodyA.position.y + bodyB.position.y) / 2},initialVelocityA: { ...bodyA.velocity },initialVelocityB: { ...bodyB.velocity },contactFrames: 0})}}})
})

合并条件判定代码:

// 合并条件判定
const distCondition = dist < GAME_CONFIG.mergeThreshold * 1.5 * totalRadius;
const timeCondition = now - time > GAME_CONFIG.mergeWindow * 0.7;
const velocityCondition = totalVelocity < 0.8 && contactFrames > 15;if (distCondition && (timeCondition || velocityCondition)) {this.handleMerge(bodyA, bodyB);collisionPairs.delete(pairId);activeMergingPairs.delete(pairId);
}

这是游戏核心机制的一部分,通过综合考虑多种条件,使合成过程更加智能和自然。当两个物体足够接近且满足时间或速度条件时,会触发合并处理。

2. 物品渲染模块 (ItemRenderer.js)

负责游戏中各种物品的视觉呈现,确保每个物品都有鲜明的辨识度和程序员文化气息。

核心功能

  • 使用Canvas API绘制各类程序员物品
  • 实现物品合成的视觉特效
  • 处理不同大小物品的适配渲染

程序化绘制代码示例

// 渲染咖啡杯
static renderCoffee(ctx, x, y, size) {const scale = size / 100;// 绘制杯子主体ctx.beginPath();ctx.fillStyle = '#75432A';ctx.moveTo(x - 30 * scale, y - 15 * scale);ctx.bezierCurveTo(x - 32 * scale, y + 25 * scale,x - 28 * scale, y + 35 * scale,x - 20 * scale, y + 35 * scale);ctx.lineTo(x + 20 * scale, y + 35 * scale);ctx.bezierCurveTo(x + 28 * scale, y + 35 * scale,x + 32 * scale, y + 25 * scale,x + 30 * scale, y - 15 * scale);ctx.closePath();ctx.fill();// 绘制咖啡液体ctx.beginPath();ctx.fillStyle = '#4A2C1A';ctx.ellipse(x, y - 15 * scale, 30 * scale, 10 * scale, 0, 0, Math.PI * 2);ctx.fill();// 绘制杯把ctx.beginPath();ctx.strokeStyle = '#75432A';ctx.lineWidth = 5 * scale;ctx.arc(x + 35 * scale, y + 10 * scale, 10 * scale, Math.PI * 1.2, Math.PI * 1.8);ctx.stroke();
}

这段代码展示了如何使用Canvas API绘制咖啡杯物品。我们使用贝塞尔曲线和基本形状组合创建了具有立体感的图形,而不是使用图片资源。

合并动画效果代码

static renderMergeAnimation(ctx, x, y, size, progress) {// 创建闪光效果const radius = size * (1 + progress * 0.5);const opacity = 1 - progress;// 绘制外部光环ctx.beginPath();ctx.arc(x, y, radius, 0, Math.PI * 2);ctx.fillStyle = `rgba(255, 255, 255, ${opacity * 0.7})`;ctx.fill();// 绘制内部光芒const gradient = ctx.createRadialGradient(x, y, 0, x, y, radius);gradient.addColorStop(0, `rgba(255, 215, 0, ${opacity})`);gradient.addColorStop(0.7, `rgba(255, 140, 0, ${opacity * 0.5})`);gradient.addColorStop(1, `rgba(255, 69, 0, 0)`);ctx.beginPath();ctx.arc(x, y, radius * 0.8, 0, Math.PI * 2);ctx.fillStyle = gradient;ctx.fill();// 添加粒子效果const particles = 8;for (let i = 0; i < particles; i++) {const angle = (i / particles) * Math.PI * 2;const dist = radius * 0.6 * progress;const px = x + Math.cos(angle) * dist;const py = y + Math.sin(angle) * dist;const particleSize = (1 - progress) * size * 0.2;ctx.beginPath();ctx.arc(px, py, particleSize, 0, Math.PI * 2);ctx.fillStyle = `rgba(255, 215, 0, ${opacity * 0.8})`;ctx.fill();}
}

这段代码实现了物品合成时的视觉特效。通过创建光环、渐变和粒子效果,使合成过程更加生动直观。效果随progress参数(0到1)动态变化,形成平滑的动画效果。

开发难点
我们选择了程序化生成图形,而非使用图片资源。这种方式虽然增加了编码复杂度,但显著减少了资源加载时间,提升了游戏启动速度,同时也为未来可能的物品自定义提供了基础。

3. 音频管理模块 (AudioManager.js)

负责游戏中所有音效和背景音乐的控制,为游戏增添听觉体验。

核心功能

  • 音频资源的预加载
  • 游戏事件触发的音效播放
  • 背景音乐的循环播放与控制

音频加载与错误处理代码

export class AudioManager {constructor() {this.sounds = {};this.bgm = null;this.isMuted = false;this.loadFailed = false;}loadAudio() {try {// 加载背景音乐this.bgm = new Audio('/src/assets/audio/bgm.mp3');this.bgm.loop = true;this.bgm.volume = 0.5;// 预加载音效const soundFiles = {drop: '/src/assets/audio/drop.mp3',merge: '/src/assets/audio/merge.mp3',levelup: '/src/assets/audio/levelup.mp3'};// 使用Promise.all并行加载所有音效const loadPromises = Object.entries(soundFiles).map(([key, path]) => {return new Promise((resolve, reject) => {const audio = new Audio(path);audio.addEventListener('canplaythrough', () => {this.sounds[key] = audio;resolve();}, { once: true });// 添加错误处理audio.addEventListener('error', (e) => {console.warn(`音频 ${key} 加载失败:`, e);// 即使加载失败也允许继续this.loadFailed = true;resolve();}, { once: true });// 开始加载audio.load();});});// 等待所有音效加载完成return Promise.all(loadPromises).then(() => console.log('所有音频加载完成')).catch(err => {console.error('音频加载过程出错:', err);this.loadFailed = true;});} catch (error) {console.error('音频初始化失败:', error);this.loadFailed = true;return Promise.resolve(); // 返回已解决的Promise以免中断游戏}}// 播放音效的安全方法playSound(name) {if (this.isMuted || this.loadFailed) return;try {const sound = this.sounds[name];if (!sound) return;// 克隆节点以允许重叠播放const soundClone = sound.cloneNode();soundClone.volume = name === 'levelup' ? 0.8 : 0.6;// 播放后自动清理soundClone.addEventListener('ended', () => {soundClone.remove();}, { once: true });soundClone.play().catch(e => {console.warn(`播放音效 ${name} 失败:`, e);});} catch (error) {console.warn('播放音效错误:', error);}}
}

这段代码展示了如何实现健壮的音频加载和播放系统。我们使用Promise并行加载所有音效,并添加了全面的错误处理机制,确保即使音频加载失败也不会影响游戏主体功能。

开发难点
浏览器音频API的兼容性问题是一大挑战。我们实现了完善的错误捕获机制,确保即使音频加载失败,也不会影响游戏主体功能的运行。另一个挑战是解决自动播放限制,我们通过用户交互触发首次播放来解决这个问题。

// 在main.js中处理自动播放限制
function startMusicOnInteraction() {if (!musicStarted) {try {game.audioManager.playBGM()musicStarted = true} catch (error) {console.warn('播放背景音乐失败:', error)}// 移除所有事件监听器document.removeEventListener('click', startMusicOnInteraction)document.removeEventListener('keydown', startMusicOnInteraction)document.removeEventListener('touchstart', startMusicOnInteraction)}
}// 添加用户交互事件监听器
document.addEventListener('click', startMusicOnInteraction)
document.addEventListener('keydown', startMusicOnInteraction)
document.addEventListener('touchstart', startMusicOnInteraction)

4. IDE风格控制台 (ConsoleManager.js)

这是游戏中最具特色的元素之一,模拟IDE控制台,实时显示游戏事件和调试信息。

核心功能

  • 不同类型消息的格式化显示
  • 控制台滚动和历史记录管理
  • 程序员幽默元素的随机插入

控制台实现代码

export class ConsoleManager {constructor() {this.consoleElement = document.querySelector('.console-output');this.messageHistory = [];this.maxMessages = 100;// 初始化控制台this.clear();this.log('程序员合成大西瓜 v1.0.0 初始化中...', 'info');this.log('物理引擎加载完成', 'success');this.log('准备就绪,开始游戏吧!', 'success');}// 添加日志消息log(message, type = 'log') {// 创建新的日志元素const logElement = document.createElement('div');logElement.className = `log ${type}`;// 根据类型添加前缀let prefix = '';switch(type) {case 'error': prefix = '[ERROR] '; break;case 'warning': prefix = '[WARN] '; break;case 'info': prefix = '[INFO] '; break;case 'success': prefix = '[SUCCESS] '; break;default: prefix = '[LOG] ';}// 添加当前时间const time = new Date().toLocaleTimeString();logElement.textContent = `${prefix}${time} - ${message}`;// 添加到控制台并保存到历史记录this.consoleElement.appendChild(logElement);this.messageHistory.push({type,message,time});// 限制历史记录长度if (this.messageHistory.length > this.maxMessages) {this.messageHistory.shift();// 也从DOM中移除最早的消息if (this.consoleElement.children.length > this.maxMessages) {this.consoleElement.removeChild(this.consoleElement.children[0]);}}// 自动滚动到最新消息this.consoleElement.scrollTop = this.consoleElement.scrollHeight;// 添加入场动画logElement.style.opacity = '0';setTimeout(() => {logElement.style.opacity = '1';}, 10);// 随机添加程序员幽默元素this.maybeAddProgrammerHumor();return logElement;}// 随机添加程序员幽默maybeAddProgrammerHumor() {// 每20条消息有约10%概率出现幽默元素if (this.messageHistory.length % 20 === 0 && Math.random() < 0.1) {const jokes = ['又在努力调试了一整天,才发现是少了一个分号...','尝试了99种方法都不行?那就尝试第100种吧!','git commit -m "我也不知道为什么这能运行,但它就是运行了"','当代码运行时,别动它;当代码不运行时,也别动它。','Error 404: 咖啡不足','世界上最遥远的距离不是生与死,而是你我之间的1px偏差'];const randomJoke = jokes[Math.floor(Math.random() * jokes.length)];this.log(randomJoke, 'info');}}// 清空控制台clear() {this.consoleElement.innerHTML = '';this.log('控制台已清空', 'info');}
}

这段代码展示了如何实现一个交互式的模拟IDE控制台。它不仅能显示不同类型的消息,还会自动管理消息历史记录、控制滚动,甚至随机穿插程序员幽默元素,增强游戏的文化氛围。

开发难点
平衡信息量和游戏体验是最大的挑战。我们精心设计了信息过滤机制,确保玩家既能获得必要的游戏反馈,又不会被过多的技术细节所干扰。

5. 彩蛋系统:游戏点睛之笔

作为一款面向程序员的游戏,彩蛋系统是我们投入心血最多的部分。我们设计了多种彩蛋,在不同条件下触发,为玩家带来意外的惊喜。

游戏通关彩蛋代码

// 触发游戏通关彩蛋
triggerGameBeatEasterEgg() {console.log("恭喜通关!你已经合成了三个财务自由!");// 暂停游戏this.isPaused = true;// 播放胜利音效序列this.audioManager.playVictoryFanfare();// 计算游戏统计数据const stats = this.calculateGameStats();// 创建通关UIconst eggContainer = document.createElement('div');eggContainer.className = 'game-beat-egg';eggContainer.innerHTML = `<div class="endgame-content"><div class="endgame-title-container"><div class="endgame-banner"></div><h1 class="endgame-title">恭喜通关!</h1></div><div class="endgame-certificate"><div class="certificate-header">程序员成就证书</div><div class="certificate-body"><div class="achievement">✓ 成功实现财务自由</div><div class="achievement">✓ 编程技能达到专家级别</div><div class="achievement">✓ 解锁自由职业者生涯</div><div class="stats-grid"><div class="stat-item"><div class="stat-label">游戏时长</div><div class="stat-value">${stats.playTime} 分钟</div></div><div class="stat-item"><div class="stat-label">总得分</div><div class="stat-value">${this.score}</div></div><div class="stat-item"><div class="stat-label">合成次数</div><div class="stat-value">${stats.totalMerges}</div></div><div class="stat-item"><div class="stat-label">程序员等级</div><div class="stat-value">Lv.${stats.highestLevel}</div></div><div class="stat-item"><div class="stat-label">消耗咖啡</div><div class="stat-value">${stats.coffeeConsumed} 杯</div></div><div class="stat-item"><div class="stat-label">编写代码</div><div class="stat-value">${stats.linesOfCode} 行</div></div></div></div><div class="certificate-footer"><div class="certificate-date">${new Date().toLocaleDateString()}</div><div class="certificate-seal"></div></div></div><div class="endgame-message"><p>成功通关!你已经成为了拥有财务自由的程序员精英!</p><p class="joke">通往成功的唯一捷径,就是把if/else改成switch,这会加速程序运行(笑)</p></div><button class="continue-button">继续游戏</button></div>`;// 添加特效元素for (let i = 0; i < 20; i++) {const particle = document.createElement('div');particle.className = 'endgame-particle';particle.style.left = `${Math.random() * 100}%`;particle.style.top = `${Math.random() * 100}%`;particle.style.animationDelay = `${Math.random() * 5}s`;eggContainer.appendChild(particle);}// 添加流星for (let i = 0; i < 3; i++) {const star = document.createElement('div');star.className = 'shooting-star';star.style.top = `${10 + Math.random() * 30}%`;star.style.left = `${Math.random() * 20}%`;star.style.animationDelay = `${i * 3}s`;eggContainer.appendChild(star);}// 添加到文档document.body.appendChild(eggContainer);// 添加按钮事件const continueButton = eggContainer.querySelector('.continue-button');continueButton.addEventListener('click', () => {eggContainer.classList.add('fade-out');setTimeout(() => {eggContainer.remove();this.isPaused = false;}, 1000);});// 保存通关记录this.saveGameCompletionStats();
}// 计算游戏统计数据
calculateGameStats() {return {playTime: Math.floor((Date.now() - this.gameStartTime) / 60000), // 游戏时长(分钟)totalMerges: this._mergeCount || 0,  // 总合成次数highestLevel: this.currentLevel,  // 最高等级financialFreedoms: this.financialFreedomCount, // 财务自由数量difficultyLevel: this.difficultyLevel + 1, // 难度级别// 随机生成一些有趣的统计数据coffeeConsumed: Math.floor(Math.random() * 15) + 5, // 5-20杯咖啡linesOfCode: (Math.floor(Math.random() * 2000) + 1000) * this.score, // 基于分数的代码行数bugsFixed: Math.floor(Math.random() * 99) + 1, // 1-100个bugsleepLost: Math.floor(Math.random() * 12) + 4 // 4-16小时};
}

这段代码实现了游戏的通关彩蛋,当玩家成功合成三个"财务自由"物品时触发。彩蛋不仅显示游戏成绩,还生成了一张精美的"程序员成就证书",并添加了流星和粒子特效,为玩家带来视觉盛宴。

主要彩蛋类型:

  1. 财务自由彩蛋:首次合成"财务自由"物品时触发,模拟终端界面展示玩家的虚拟财富状况。

  2. 游戏通关彩蛋:成功合成三个"财务自由"物品时触发,展示精美的程序员成就证书,记录游戏统计数据和幽默的成就描述。

  3. 等级彩蛋:在达到特定程序员等级时触发,解锁特殊能力或游戏机制。

特殊彩蛋触发代码

// 特殊彩蛋方法
triggerSpecialEasterEgg(type, message) {this.consoleManager.log(message, 'warning')if (type === 'mid_game') {// 在游戏中间触发的彩蛋const warningElement = document.createElement('div')warningElement.className = 'special-easter-egg mid-game'warningElement.innerHTML = `<div class="terminal-window"><div class="terminal-header"><span class="terminal-title">Terminal</span><span class="terminal-controls">×</span></div><div class="terminal-content"><div class="command-line">$ rm -rf node_modules</div><div class="command-output">Deleting... This might take a while</div><div class="command-prompt">_</div></div></div>`document.body.appendChild(warningElement)// 3秒后删除彩蛋元素setTimeout(() => {warningElement.classList.add('fade-out')setTimeout(() => warningElement.remove(), 1000)}, 3000)}else if (type === 'high_level') {// 高等级特殊彩蛋const confetti = document.createElement('div')confetti.className = 'confetti-container'// 创建50个随机彩色纸屑for (let i = 0; i < 50; i++) {const color = ['#ff0000', '#00ff00', '#0000ff', '#ffff00', '#ff00ff'][Math.floor(Math.random() * 5)]const piece = document.createElement('div')piece.className = 'confetti-piece'piece.style.backgroundColor = colorpiece.style.left = Math.random() * 100 + '%'piece.style.animationDelay = Math.random() * 3 + 's'piece.style.animationDuration = Math.random() * 2 + 2 + 's'confetti.appendChild(piece)}document.body.appendChild(confetti)// 5秒后删除纸屑setTimeout(() => {confetti.remove()}, 5000)}
}

这段代码展示了如何实现特殊彩蛋,当玩家达到特定等级时触发。这些彩蛋包括模拟终端窗口执行命令和彩色纸屑庆祝效果,为游戏增添了更多惊喜和乐趣。

开发难点与解决方案

1. 物理碰撞的稳定性

问题:使用Matter.js实现物理碰撞时,有时会出现物体穿透或合成判定不准确的问题。

解决方案

  • 优化碰撞参数,增加迭代次数提高精度
  • 设计复合判定条件,综合考虑距离、时间和速度
  • 添加额外的安全检查,防止边缘情况导致的错误

代码实现

// 物理引擎参数优化
this.engine = Matter.Engine.create({enableSleeping: true,constraintIterations: 3,  // 增加约束迭代次数positionIterations: 8,    // 增加位置迭代次数velocityIterations: 6     // 增加速度迭代次数
})

2. 游戏性能优化

问题:当屏幕上物体数量增多时,物理计算会导致性能下降。

解决方案

  • 实现物体睡眠机制,减少静止物体的计算量
  • 优化渲染循环,分离物理更新和视觉渲染
  • 使用固定时间步长更新物理世界,保证稳定性

代码实现

gameLoop() {if (this.gameOver) returnconst loop = (currentTime) => {if (!this.isPaused) {try {// 计算时间步长const deltaTime = currentTime - this.lastTimethis.lastTime = currentTimethis.accumulator += deltaTime// 固定时间步长更新物理while (this.accumulator >= this.fixedDeltaTime) {Matter.Engine.update(this.engine, this.fixedDeltaTime)this.accumulator -= this.fixedDeltaTime}this.checkLevelUp()this.checkDifficulty()this.checkWarningLine()this.updateGameState()this.checkCanDrop()} catch (error) {console.error('游戏循环错误:', error)// 尝试恢复游戏状态this.canDropItem = truethis.lastDroppedItem = null}}requestAnimationFrame(loop.bind(this))}requestAnimationFrame(loop.bind(this))
}

这段代码实现了一个高效的游戏循环,使用固定时间步长更新物理世界,确保物理模拟的精确性和一致性,同时避免了过度渲染导致的性能问题。

项目代码:

https://download.csdn.net/download/Pte_moon/90523799

写在最后

🎉 到这里,“程序员版合成大西瓜"游戏的开发分享就到这里啦!希望这些内容能帮助到你的日常开发工作,也欢迎你下载游戏体验,看看能否成功合成三个"财务自由”,解锁终极彩蛋!

如果觉得有帮助的话,别忘了点个赞 👍 收藏 ⭐ 关注 🔖 哦!

💡 开发路上,我们都是学习者。如果你有任何问题或更好的想法,欢迎在评论区留言交流!

🤝 一起进步,共同成长~


🎯 我是果冻~,一个热爱技术、乐于分享的开发者
📚 更多精彩内容,请关注我的博客
🌟 我们下期再见!

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

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

相关文章

举例说明自然语言处理(NLP)技术

当我们使用智能助手或社交媒体平台时&#xff0c;就会接触到自然语言处理&#xff08;NLP&#xff09;技术的应用。以下是一些常见的例子&#xff1a; 语音识别&#xff1a;当我们与智能助手如Siri、Alexa或Google Assistant交互时&#xff0c;我们说出语音命令&#xff0c;系统…

ResNet与注意力机制:深度学习中的强强联合

引言 在深度学习领域&#xff0c;卷积神经网络&#xff08;CNN&#xff09;一直是图像处理任务的主流架构。然而&#xff0c;随着网络深度的增加&#xff0c;梯度消失和梯度爆炸问题逐渐显现&#xff0c;限制了网络的性能。为了解决这一问题&#xff0c;ResNet&#xff08;残差…

【设计模式】组合模式

第11章 组合模式 11.1 一个基本的目录内容遍历范例 组合模式用于处理树形结构数据&#xff0c;如操作系统目录。以下是目录遍历的非组合模式实现&#xff1a; 文件类定义 class File { public:File(string name) : m_sname(name) {}void ShowName(string lvlstr) {cout <…

DSP28335 eCAN(增强型控制器局域网)

一、概述 1.1 特征 can协议2.0 ,高达1Mbps32个邮箱 1)—可配置接收或发送—可配置标准或扩展标识符—接收标识符屏蔽功能—支持数据和远程帧—支持0到8字节的数据帧—在接收和发送的消息上使用32位时间戳(发送接收计时器)—接收新消息保护—允许动态可编程的发送消息优先…

现代控制原理

一、在状态空间中&#xff0c;建立控制系统的数学模型 如&#xff1a;有单输入&#xff08;U)--单输出&#xff08;Y)控制系统&#xff0c;其状态方程和输出方程如下图&#xff1a; 二、画状态结构图 将上述状态方程转化为状态结构图有&#xff1a; 三、高阶控制系统的状态方…

【Git】基础使用

Git基础使用 基础配置工作区-暂存区-版本库添加文件修改文件版本回退撤销修改删除文件分支管理强制删除分支 基础配置 初始化仓库&#xff1a; git init # 此时就会生成一个 .git 的文件夹&#xff0c;切勿修改或删除文件夹里的内容配置仓库——名字&#xff1a; git config…

系统与网络安全------网络应用基础(2)

资料整理于网络资料、书本资料、AI&#xff0c;仅供个人学习参考。 交换机 认识交换机 交换机&#xff0c;Switch 用户将多台计算机/交换机连接在一起&#xff0c;组建网络 交换机负责为其中任意两台计算机提供独享线路进行通信 非网管型交换机 即插即用交换机 即插即用&…

【xiaozhi赎回之路-2:语音可以自己配置就是用GPT本地API】

固件作用 打通了网络和硬件的沟通 修改固件实现【改变连接到小智服务器的】 回答逻辑LLM自定义 自定义了Coze&#xff08;比较高级&#xff0c;自定义程度比较高&#xff0c;包括知识库&#xff0c;虚拟脚色-恋人-雅思老师-娃娃玩具{可能需要使用显卡对开源模型进行微调-产…

蓝桥杯——嵌入式学习日记

因为lED和LCD共用PC8~PC15引脚&#xff0c;要通过锁存&#xff08;LE&#xff09;和&#xff08;GPIOC->ODR&#xff09;来避免LED和LCD引脚冲突 修改点: main.c中&#xff0c;GPIO初始化引脚后&#xff0c;LE&#xff08;PD2引脚低电平锁存&#xff0c;退出透明模式&…

Liunx系统Microsoft SQL Server数据库还原

1.确认Linux系统已安装SQLServer服务并启动 2.在Windows中使用SSMS连接原数据库与Linux远程数据库服务 3.备份 成功备份如下 4.上传bak文件到远程Linux服务器 登陆Linux服务并创建数据库文件夹 退出Linux服务

【学习资源】多元时序分析问题和时序图模型

工业数据分析领域中&#xff0c;多元时序数据分析是一个广泛的问题。今天和大家简单介绍多元时序预测、聚类、分类、时序图模型和相应的深度学习库。 图片来源&#xff1a;https://www.researchgate.net/publication/349207209_Multivariate_Time-Series_Anomaly_Detection_via…

QT二 QT使用generate form 生成常用UI,各种UI控件

一 。没有使用general form 和 使用 general form 后&#xff0c;file层面和代码层面的不同比较 file层面的不同 代码层面的不同&#xff0c; 在 使用了general form之后&#xff0c;在主界面的构造方法中&#xff0c;使用ui->setupUi(this),就完成了所有UI的处理。 而之…

Haption力反馈遥操作机器人:6自由度高精度技术,定义远程操作新标准

Haption在力反馈遥操作机器人技术领域展现了强大的创新能力。其核心技术——力反馈技术&#xff0c;通过提供高度逼真的触觉反馈&#xff0c;显著提升了远程操作的精确性与用户体验。这种技术在工业、医疗等高要求场景中表现出色&#xff0c;同时也为科研和教育领域提供了有力支…

魔塔社区的torch_empty错误问题的解决办法

前言 我在运行魔塔社区&#xff08;modelscope&#xff09;的ZhipuAI/chatglm3-6b模型&#xff08;智谱&#xff09;的实例程序的时候&#xff0c;碰到了一个奇怪的错误&#xff08;torch.empty&#xff09;&#xff0c;我尝试解决了一下。 &#xff08;当前采用的Python版本…

全面了解 Cookies、Session 和 Token

&#x1f9d1; 博主简介&#xff1a;CSDN博客专家&#xff0c;历代文学网&#xff08;PC端可以访问&#xff1a;https://literature.sinhy.com/#/literature?__c1000&#xff0c;移动端可微信小程序搜索“历代文学”&#xff09;总架构师&#xff0c;15年工作经验&#xff0c;…

51c自动驾驶~合集26

我自己的原文哦~ https://blog.51cto.com/whaosoft/11968755 #大模型/Sora/世界模型之间是什么关系 1 什么是大模型 人工智能大模型&#xff08;Artificial Intelligence Large Model&#xff0c;简称AI大模型&#xff09;是指具有庞大的参数规模和复杂程度的机器学习模…

分布式环境下的重复请求防护:非Redis锁替代方案全解析

目录 引言 方案一&#xff1a;前端防护策略 方案二&#xff1a;后端协同控制 方案三&#xff1a;流量控制与过滤 滑动窗口限流 布隆过滤器 方案四&#xff1a;基于框架的实践方案 多层防护策略与最佳实践 总结 引言 在Web应用开发中&#xff0c;防止用户重复点…

4.1 C#获取目录的3个方法的区别

C#中常用有如下3个获取目录的方式如下 1.Directory.GetCurrentDirectory():获取当前工作目录&#xff0c;工作目录可能被用户或其他代码修改。尽量少用。&#xff08;似乎只要在运行中使用另存为或者打开某个文件夹&#xff0c;当前工作目录就修改&#xff09; 2.Application…

【漏洞复现】Next.js中间件权限绕过漏洞 CVE-2025-29927

什么是Next.js&#xff1f; Next.js 是由 Vercel 开发的基于 React 的现代 Web 应用框架&#xff0c;具备前后端一体的开发能力&#xff0c;广泛用于开发 Server-side Rendering (SSR) 和静态站点生成&#xff08;SSG&#xff09;项目。Next.js 支持传统的 Node.js 模式和基于边…

MCU-芯片时钟与总线和定时器关系,举例QSPI

时钟源&#xff1a; 时钟源为系统时钟提供原始频率信号&#xff0c;系统时钟则通过&#xff08;分频、倍频、选择器&#xff09;成为整个芯片的“主时钟”&#xff0c;驱动 CPU 内核、总线&#xff08;AHB、APB&#xff09;及外设的运行。 内部时钟源&#xff1a; HSI&#x…