欢迎加入开源鸿蒙PC社区:
https://harmonypc.csdn.net/

atomgit开源仓库地址:
https://atomgit.com/feng8403000/game_Collisioneffect

示例效果

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在游戏开发和物理模拟中,碰撞检测是一个核心技术。准确的碰撞检测和物理响应能够为游戏和模拟应用提供更加真实的交互体验。为了帮助开发者理解和测试碰撞检测算法,我们开发了一个基于HTML5 Canvas的物体碰撞效果测试应用。

本文将详细介绍如何使用Electron和HTML5 Canvas开发一款物体碰撞效果测试应用,包括物理引擎的实现、碰撞检测算法、用户界面设计以及性能优化等方面。

技术栈选择

前端技术

  • HTML5 Canvas:用于绘制物体和实现动画效果
  • JavaScript:实现物理引擎和碰撞检测算法
  • CSS:设计美观的用户界面

后端技术

  • Electron:构建跨平台桌面应用,提供原生桌面体验

技术优势

  • 跨平台:Electron可以在Windows、macOS和Linux上运行
  • 性能优异:Canvas绘制提供高效的图形渲染
  • 开发效率高:使用熟悉的Web技术栈,开发周期短
  • 用户体验好:桌面应用提供更沉浸式的测试体验

应用功能介绍

核心功能

  1. 多种物体类型:支持圆形、矩形、多边形三种物体类型
  2. 可调节参数
    • 物体数量(1-50)
    • 物体大小(10-100)
    • 移动速度(1-10)
    • 弹性系数(0-1)
  3. 实时碰撞检测:检测物体之间的碰撞并产生物理响应
  4. 边界碰撞处理:处理物体与画布边界的碰撞
  5. 碰撞统计:实时显示碰撞次数
  6. 性能监控:显示帧率信息
  7. 测试控制:开始、停止、重置测试

界面设计

  • 简洁美观:采用现代化的UI设计,界面清爽整洁
  • 响应式布局:适配不同窗口大小
  • 直观的控制面板:方便用户调整参数
  • 实时信息面板:显示碰撞统计和性能数据

核心代码分析

1. 物体类实现

class GameObject {
    constructor(type, size, speed, x, y) {
        this.type = type;
        this.size = size;
        this.speed = speed;
        this.x = x;
        this.y = y;
        this.vx = (Math.random() - 0.5) * speed * 2;
        this.vy = (Math.random() - 0.5) * speed * 2;
        this.color = `hsl(${Math.random() * 360}, 70%, 50%)`;
        this.rotation = Math.random() * Math.PI * 2;
        this.angularVelocity = (Math.random() - 0.5) * 0.05;
        
        if (type === 'polygon') {
            this.sides = 3 + Math.floor(Math.random() * 5); // 3-7边形
            this.vertices = [];
            for (let i = 0; i < this.sides; i++) {
                const angle = (i / this.sides) * Math.PI * 2;
                const radius = size * 0.8;
                this.vertices.push({
                    x: Math.cos(angle) * radius,
                    y: Math.sin(angle) * radius
                });
            }
        }
    }
    
    update() {
        // 更新位置
        this.x += this.vx;
        this.y += this.vy;
        
        // 更新旋转
        if (this.type === 'polygon') {
            this.rotation += this.angularVelocity;
        }
        
        // 边界碰撞检测
        if (this.x - this.size < 0) {
            this.x = this.size;
            this.vx = Math.abs(this.vx) * parseFloat(bounceInput.value);
        }
        if (this.x + this.size > canvasWidth) {
            this.x = canvasWidth - this.size;
            this.vx = -Math.abs(this.vx) * parseFloat(bounceInput.value);
        }
        if (this.y - this.size < 0) {
            this.y = this.size;
            this.vy = Math.abs(this.vy) * parseFloat(bounceInput.value);
        }
        if (this.y + this.size > canvasHeight) {
            this.y = canvasHeight - this.size;
            this.vy = -Math.abs(this.vy) * parseFloat(bounceInput.value);
        }
    }
    
    draw() {
        ctx.save();
        ctx.translate(this.x, this.y);
        
        if (this.type === 'polygon') {
            ctx.rotate(this.rotation);
        }
        
        ctx.fillStyle = this.color;
        ctx.strokeStyle = '#333';
        ctx.lineWidth = 2;
        
        if (this.type === 'circle') {
            ctx.beginPath();
            ctx.arc(0, 0, this.size, 0, Math.PI * 2);
            ctx.fill();
            ctx.stroke();
        } else if (this.type === 'rectangle') {
            ctx.fillRect(-this.size, -this.size, this.size * 2, this.size * 2);
            ctx.strokeRect(-this.size, -this.size, this.size * 2, this.size * 2);
        } else if (this.type === 'polygon') {
            ctx.beginPath();
            ctx.moveTo(this.vertices[0].x, this.vertices[0].y);
            for (let i = 1; i < this.vertices.length; i++) {
                ctx.lineTo(this.vertices[i].x, this.vertices[i].y);
            }
            ctx.closePath();
            ctx.fill();
            ctx.stroke();
        }
        
        ctx.restore();
    }
}

代码解析

  • 物体类支持三种类型:圆形、矩形和多边形
  • 每个物体具有位置、速度、大小、颜色等属性
  • 多边形物体具有随机的边数(3-7边)和顶点坐标
  • update方法更新物体位置和处理边界碰撞
  • draw方法根据物体类型绘制不同的形状

2. 碰撞检测算法

function checkCollision(obj1, obj2) {
    if (obj1.type === 'circle' && obj2.type === 'circle') {
        // 圆形与圆形碰撞
        const dx = obj1.x - obj2.x;
        const dy = obj1.y - obj2.y;
        const distance = Math.sqrt(dx * dx + dy * dy);
        return distance < (obj1.size + obj2.size);
    } else if ((obj1.type === 'rectangle' && obj2.type === 'rectangle')) {
        // 矩形与矩形碰撞
        return Math.abs(obj1.x - obj2.x) < (obj1.size + obj2.size) &&
               Math.abs(obj1.y - obj2.y) < (obj1.size + obj2.size);
    } else {
        // 其他碰撞类型(简化处理)
        const dx = obj1.x - obj2.x;
        const dy = obj1.y - obj2.y;
        const distance = Math.sqrt(dx * dx + dy * dy);
        return distance < (obj1.size + obj2.size);
    }
}

代码解析

  • 针对不同类型的物体组合使用不同的碰撞检测算法
  • 圆形与圆形碰撞:计算两圆心距离与半径之和比较
  • 矩形与矩形碰撞:使用轴对齐边界盒(AABB)碰撞检测
  • 其他组合:使用简化的距离检测方法

3. 碰撞响应处理

function resolveCollision(obj1, obj2) {
    // 计算碰撞法线
    const dx = obj2.x - obj1.x;
    const dy = obj2.y - obj1.y;
    const distance = Math.sqrt(dx * dx + dy * dy);
    
    if (distance === 0) return; // 避免除以零
    
    // 归一化法线
    const nx = dx / distance;
    const ny = dy / distance;
    
    // 计算相对速度
    const dvx = obj2.vx - obj1.vx;
    const dvy = obj2.vy - obj1.vy;
    
    // 计算相对速度在碰撞法线上的分量
    const dotProduct = dvx * nx + dvy * ny;
    
    // 如果物体正在分离,不处理碰撞
    if (dotProduct > 0) return;
    
    // 计算弹性系数
    const bounce = parseFloat(bounceInput.value);
    
    // 计算冲量
    const impulse = -(1 + bounce) * dotProduct / 2;
    
    // 应用冲量
    obj1.vx -= impulse * nx;
    obj1.vy -= impulse * ny;
    obj2.vx += impulse * nx;
    obj2.vy += impulse * ny;
    
    // 分离物体,避免重叠
    const overlap = (obj1.size + obj2.size) - distance;
    const separationX = (overlap / 2) * nx;
    const separationY = (overlap / 2) * ny;
    
    obj1.x -= separationX;
    obj1.y -= separationY;
    obj2.x += separationX;
    obj2.y += separationY;
    
    // 增加碰撞计数
    collisionCount++;
    collisionCountElement.textContent = collisionCount;
}

代码解析

  • 计算碰撞法线:从obj1指向obj2的单位向量
  • 计算相对速度:两物体速度之差
  • 计算碰撞冲量:根据弹性系数和相对速度计算
  • 应用冲量:更新两物体的速度
  • 分离物体:避免物体重叠
  • 增加碰撞计数:用于统计碰撞次数

4. 动画循环

function animate(timestamp) {
    // 计算帧率
    if (!lastTime) lastTime = timestamp;
    const deltaTime = timestamp - lastTime;
    lastTime = timestamp;
    
    frameCount++;
    if (timestamp - lastFpsUpdate >= 1000) {
        fps = Math.round((frameCount * 1000) / (timestamp - lastFpsUpdate));
        fpsElement.textContent = fps;
        frameCount = 0;
        lastFpsUpdate = timestamp;
    }
    
    // 清空画布
    ctx.clearRect(0, 0, canvasWidth, canvasHeight);
    
    // 更新和绘制物体
    objects.forEach(obj => {
        obj.update();
        obj.draw();
    });
    
    // 检测碰撞
    for (let i = 0; i < objects.length; i++) {
        for (let j = i + 1; j < objects.length; j++) {
            if (checkCollision(objects[i], objects[j])) {
                resolveCollision(objects[i], objects[j]);
            }
        }
    }
    
    // 继续动画
    animationId = requestAnimationFrame(animate);
}

代码解析

  • 使用requestAnimationFrame实现平滑动画
  • 计算帧率并实时更新
  • 清空画布并重新绘制所有物体
  • 检测所有物体对之间的碰撞
  • 处理碰撞响应

开发过程中的挑战与解决方案

1. 碰撞检测性能优化

挑战:当物体数量较多时,碰撞检测可能会影响性能

解决方案

  • 使用双层循环,避免重复检测(只检测i<j的物体对)
  • 对于不同类型的物体使用不同的检测算法
  • 简化非圆形和矩形的碰撞检测

2. 物理引擎实现

挑战:实现真实的物理碰撞响应

解决方案

  • 使用冲量法计算碰撞后的速度变化
  • 考虑弹性系数对碰撞的影响
  • 处理物体重叠问题,确保物体不会穿透

3. 多边形碰撞检测

挑战:多边形的碰撞检测和旋转处理比较复杂

解决方案

  • 为多边形生成随机顶点
  • 在绘制时应用旋转变换
  • 使用简化的碰撞检测方法处理多边形与其他形状的碰撞

4. 用户界面设计

挑战:创建直观易用的控制面板

解决方案

  • 使用响应式布局,适配不同窗口大小
  • 提供清晰的参数调整控件
  • 实时显示碰撞统计和性能数据

项目结构

electron-openharmony-vue3/
├── ohos_hap/
│   └── web_engine/
│       └── src/main/
│           └── resources/
│               └── resfile/
│                   └── resources/
│                       └── app/
│                           ├── index.html      # 物体碰撞效果测试页面
│                           ├── main.js         # Electron主进程
│                           └── preload.js      # 预加载脚本
└── docs/
    └── COLLISION_TEST_BLOG.md  # 项目博客

未来改进方向

  1. 更精确的碰撞检测:实现基于SAT(分离轴定理)的精确碰撞检测
  2. 更多物体类型:添加三角形、椭圆等更多形状
  3. 物理参数调整:添加质量、摩擦力等物理参数
  4. 场景预设:提供不同的碰撞场景预设
  5. 碰撞可视化:添加碰撞力和法线的可视化效果
  6. 导出功能:支持导出碰撞数据和动画
  7. 性能分析:添加更详细的性能分析工具
  8. 多画布支持:支持多个画布同时测试不同场景

总结

通过本项目,我们成功开发了一款功能完整、界面美观的物体碰撞效果测试应用。应用采用Electron和HTML5 Canvas技术栈,实现了以下核心功能:

  • 支持多种物体类型(圆形、矩形、多边形)
  • 可调整物体数量、大小、速度和弹性系数
  • 实时碰撞检测和物理响应
  • 边界碰撞处理
  • 碰撞次数统计和帧率显示
  • 开始/停止/重置测试控制

项目中使用的技术和算法包括:

  • Canvas绘制技术
  • 面向对象编程
  • 碰撞检测算法
  • 物理引擎实现
  • 动画循环优化
  • 性能监控

这款物体碰撞效果测试应用不仅可以帮助开发者理解碰撞检测的原理,还可以用于测试不同物理参数下的碰撞效果,为游戏开发和物理模拟提供参考。

如何运行

  1. 克隆项目到本地
  2. 进入项目目录
  3. 运行Electron应用
  4. 在应用界面中:
    • 选择物体类型(圆形、矩形、多边形)
    • 设置物体数量、大小、移动速度和弹性系数
    • 点击"开始测试"按钮开始碰撞效果测试
    • 观察物体之间的碰撞效果
    • 点击"停止测试"按钮暂停测试
    • 点击"重置"按钮清空当前测试
    • 查看碰撞次数、当前物体数量和帧率信息

技术栈总结

技术 用途 版本
Electron 桌面应用框架 最新版
HTML5 Canvas 绘制物体和动画 HTML5
JavaScript 物理引擎和碰撞检测 ES6+
CSS 界面设计 CSS3

通过本项目的开发,我们展示了如何使用现代Web技术构建一个功能完整的物理碰撞测试应用,希望对开发者有所启发和帮助。

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐