解析游戏开发中的ECS设计模式:实体、组件、系统的完美协同

news2024/9/20 14:41:12

ECS(Entity-Component-System)是一种设计模式,通常用于构建和管理具有大量实体和复杂交互的系统,尤其在游戏开发中得到广泛应用。这个模式的核心思想是将系统中的组件、实体和系统进行分离,以提高代码的可维护性、可扩展性和性能。

实体(Entity):

实体是系统中的基本对象,可以是游戏中的角色、物体或其他有意义的实体。
实体本身通常只是一个标识符,没有行为或状态。

组件(Component):

组件是实体的属性或数据单元,描述了实体的特征和状态。
不同的组件可以包含不同类型的数据,例如位置、渲染信息、健康状态等。
一个实体可以关联多个组件,组件之间是相互独立的。

系统(System):

系统是处理实体和组件的逻辑单元,负责执行特定的功能或行为。
系统基于组件的存在与否,以及它们的状态来执行逻辑。
系统通常是独立于特定实体的,可以处理多个具有相似组件结构的实体。
ECS 模式的优势包括:

松散耦合(Loose Coupling): 实体、组件和系统之间的分离降低了各部分之间的依赖关系,使得系统更易于理解和维护。
可重用性(Reusability): 组件和系统的设计使得它们可以轻松地被重用在不同的实体和场景中。
性能优化(Performance Optimization): ECS 模式支持数据驱动的设计,允许系统更有效地管理和处理大量数据,提高系统性能。

在应用 ECS 模式时,开发者通常需要定义组件、创建实体,实现系统,并在主循环中更新系统。 ECS
提供了一种结构化的方式来管理和处理系统中的复杂性,特别适用于需要频繁变化和交互的应用场景。

简易ECS示例

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>简易ECS示例</title>
    <style>
      canvas {
        border: 1px solid #000;
      }
    </style>
  </head>
  <body>
    <canvas id="gameCanvas" width="400" height="400"></canvas>
    <script>
      // 实体类,用于表示游戏中的实体
      class Entity {
        constructor(id) {
          this.id = id;
          this.components = {};
        }

        // 添加组件到实体
        addComponent(component) {
          this.components[component.constructor.name] = component;
        }

        // 获取实体的指定组件
        getComponent(componentName) {
          return this.components[componentName];
        }
      }

      // 组件基类,所有组件都继承自这个基类
      class Component {
        constructor() {
          this.name = this.constructor.name;
        }
      }

      // 位置组件,表示实体的位置
      class Position extends Component {
        constructor(x, y) {
          super();
          this.x = x;
          this.y = y;
        }
      }

      // 渲染组件,表示实体的渲染样式
      class Render extends Component {
        constructor(color) {
          super();
          this.color = color;
        }
      }

      // 移动系统,处理具有位置组件的实体的移动逻辑
      class MoveSystem {
        constructor() {
          this.componentTypes = ["Position"];
        }

        // 更新实体的位置
        update(entities) {
          for (const entity of entities) {
            if (this.entityHasComponents(entity)) {
              const position = entity.getComponent("Position");
              if (position.x >= 380) position.x = 0;
              if (position.y >= 380) position.y = 0;
              position.x += 1;
              position.y += 1;
            }
          }
        }

        // 检查实体是否具有指定的组件类型
        entityHasComponents(entity) {
          return this.componentTypes.every((type) => entity.components[type]);
        }
      }

      // 渲染系统,处理具有位置和渲染组件的实体的渲染逻辑
      class RenderSystem {
        constructor() {
          this.componentTypes = ["Position", "Render"];
          this.canvas = document.getElementById("gameCanvas");
          this.context = this.canvas.getContext("2d");
        }

        // 更新实体的渲染
        update(entities) {
          // 清空画布
          this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);

          for (const entity of entities) {
            if (this.entityHasComponents(entity)) {
              // 获取位置和渲染组件
              const position = entity.getComponent("Position");
              const render = entity.getComponent("Render");

              // 设置颜色并绘制实体
              this.context.fillStyle = render.color;
              this.context.fillRect(position.x, position.y, 20, 20);
            }
          }
        }

        // 检查实体是否具有指定的组件类型
        entityHasComponents(entity) {
          return this.componentTypes.every((type) => entity.components[type]);
        }
      }

      // 创建两个实体,并为它们添加位置和渲染组件
      const entity1 = new Entity(1);
      entity1.addComponent(new Position(50, 50));
      entity1.addComponent(new Render("#ff0000")); // 使用十六进制颜色表示 "red"

      const entity2 = new Entity(2);
      entity2.addComponent(new Position(100, 100));
      entity2.addComponent(new Render("#0000ff")); // 使用十六进制颜色表示 "blue"

      // 创建移动系统和渲染系统
      const moveSystem = new MoveSystem();
      const renderSystem = new RenderSystem();

      // 游戏循环函数,负责更新移动和渲染系统
      function gameLoop() {
        moveSystem.update([entity1, entity2]);
        renderSystem.update([entity1, entity2]);
        requestAnimationFrame(gameLoop);
      }

      // 启动游戏循环
      gameLoop();
    </script>
  </body>
</html>

ecs

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

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

相关文章

FineBI实战项目一(7):每天每小时上架商品个数

1 明确数据分析目标 对所有商品的商家时间进行统计&#xff0c;统计每个小时上架商品的个数 2 创建用于保存数据分析结果的表 create table app_hour_goods(id int primary key auto_increment,daystr varchar(20),hourstr varchar(20),cnt int ); 3 编写SQL语句进行数据分析…

鉴源论坛 · 观模丨浅谈Web渗透之信息收集(下)

作者 | 林海文 上海控安可信软件创新研究院汽车网络安全组 版块 | 鉴源论坛 观模 社群 | 添加微信号“TICPShanghai”加入“上海控安51fusa安全社区” 信息收集在渗透测试过程中是最重要的一环&#xff0c;“浅谈web渗透之信息收集”将通过上下两篇&#xff0c;对信息收集、…

用PreMaint引领先进的预测性维护

在设备维护领域&#xff0c;预测性维护成为一项利用先进技术和巧妙工具的数据驱动战略。这一战略通过条件监控和数据分析&#xff0c;以主动维护的方式识别潜在的设备缺陷&#xff0c;避免问题升级。高效使用PreMaint预测性维护工具可不仅节省时间和成本&#xff0c;更显著提升…

Eureka的自我保护机制

文章目录 一&#xff1a;Eureka的自我保护机制是什么&#xff1f;二&#xff1a;为什么会出现自我保护机制&#xff1f;三&#xff1a;怎么禁止Eureka的自我保护&#xff1f;3.1&#xff1a;来看看开启自我保护模式的时候&#xff0c;Eureka服务端提示&#xff1a;3.2&#xff…

【题解】—— LeetCode一周小结

1.经营摩天轮的最大利润 题目链接&#xff1a; 1599. 经营摩天轮的最大利润 你正在经营一座摩天轮&#xff0c;该摩天轮共有 4 个座舱 &#xff0c;每个座舱 最多可以容纳 4 位游客 。你可以 逆时针 轮转座舱&#xff0c;但每次轮转都需要支付一定的运行成本 runningCost 。摩…

Python爬虫必学数据库:MongoDB

微信公众号&#xff1a;愤怒的it男&#xff0c;超多Python技术干货文章。 MongoDB由C编写而成&#xff0c;是免费开源跨平台的非关系型数据库&#xff0c;与关系型数据库不同&#xff0c;MongoDB将数据存储在类似JSON的文档中&#xff0c;这使得数据库非常灵活和可伸缩。 一、环…

springcloud bus消息总线

简介 Spring Cloud Bus 配合Spring Cloud Config 使用可以实现配置的动态刷新。 Spring Cloud Bus是用来将分布式系统的节点与轻量级消息系统链接起来的框架&#xff0c;它整合了Java的事件处理机制和消息中间件的功能。Spring Clud Bus目前支持RabbitMQ和Kafka。 Spring C…

云计算任务调度仿真01

云计算任务调度的研究大多数以来仿真研究&#xff0c;现梳理一些做过的代码研究 结果无数次的排错&#xff0c;终于finish with code 0 了 这个代码以来的是比较老的TensorFlow版本&#xff0c;我们都知道TensorFlow1.x和TensorFlow2.x之间有很大差别&#xff0c;但其实&#…

vue3中路由的使用(详细讲解)

1、路由的简介 路由(route)&#xff1a;就是根据特定的规则将数据包或请求从源地址传输到目标地址的过程。 在前端或者vue3项目中路由主要用于构建单页面应用程序&#xff08;SPA&#xff09;&#xff0c;其中所有的页面都在同一个HTML文件中加载&#xff0c;通过JavaScript动…

无人驾驶卡尔曼滤波

无人驾驶卡尔曼滤波&#xff08;行人检测&#xff09; x k a x k − 1 w k x_k ax_{k-1} w_k xk​axk−1​wk​ w k w_k wk​&#xff1a;过程噪声 状态估计 估计飞行器状态&#xff08;高度&#xff09; x k z k − v k x_k z_k - v_k xk​zk​−vk​ 卡尔曼滤波通…

OpenAI 是如何一步一步把RAG做到98%的准确性得

参考OpenAI的官方演讲&#xff0c;如何做好RAG。本文整理的内容&#xff0c;均来源于此演讲内容。 【OpenAI演讲-自制中文字幕】干货-如何提升大模型表现&#xff1f;-提示工程、RAG与Fine-Tuning技巧详解_哔哩哔哩_bilibili 45% 的准确性 普通搜索不做任何处理的效果&#x…

人工智能_机器学习091_使用三维瑞士卷数据_KMeans聚类算法进行瑞士卷数据聚类---人工智能工作笔记0131

然后我们首先来构建一下数据 准备瑞士卷数据: import numpy as np 导入数学计算包 import matplotlib.pyplot as plt 导入画图包 #自底向上聚类 from sklearn.cluster import AgglceerativeClustering 导入分层聚类模型 from sklearn.datasets import make_swiss_roll # 瑞士卷…

给自己创建的GPTs添加Action(查天气)

前言 在这篇文章中&#xff0c;我将分享如何利用ChatGPT 4.0辅助论文写作的技巧&#xff0c;并根据网上的资料和最新的研究补充更多好用的咒语技巧。 GPT4的官方售价是每月20美元&#xff0c;很多人并不是天天用GPT&#xff0c;只是偶尔用一下。 如果调用官方的GPT4接口&…

Linux 下查看内存使用情况方法总结

在做Linux系统优化的时候&#xff0c;物理内存是其中最重要的一方面。自然的&#xff0c;Linux也提供了非常多的方法来监控宝贵的内存资源的使用情况。下面的清单详细的列出了Linux系统下通过视图工具或命令行来查看内存使用情况的各种方法。 1./proc/meminfo 查看RAM使用情况…

【C语言】TCP测速程序

一、服务端 下面是一个用 C 语言编写的测试 TCP 传输速度的基本程序示例。 这只是一个简单示例&#xff0c;没有做详细的错误检查和边缘情况处理。在实际应用中&#xff0c;可能需要增加更多的功能和完善的异常处理机制。 TCP 服务器 (server.c): #include <stdio.h> #…

Centos7 手动更改系统时间

文章目录 1.更改系统时间2.写入系统时间3.查看是否写入成功 1.更改系统时间 date -s "2017-12-18 09:40:00"2.写入系统时间 hwclock -w3.查看是否写入成功 timedatectl

vue中鼠标拖动触发滚动条的移动

前言 在做后端管理系统中&#xff0c;像弹窗或大的表单时&#xff0c;经常会有滚动条的出现&#xff0c;但有些时候如流程、图片等操作时&#xff0c;仅仅使用鼠标拖动滚动条操作不太方便&#xff0c;如果使用鼠标拖拽图片或容器来触发滚动条的移动就比较方便了 功能设计 如…

用python提取word中的所有图片

使用word中提取的方式图片会丢失清晰度&#xff0c;使用python写一个脚本&#xff0c;程序运行将弹出对话框选择一个word文件&#xff0c;然后在弹出一个对话框选择一个文件夹保存word中的文件。将该word中的所有图片都保存成png格式&#xff0c;并命名成image_i的样式。 程序…

模型容器与AlexNet构建

一、模型容器——Containers nn.Sequential 是 nn.module的容器&#xff0c;用于按顺序包装一组网络层 Sequential 容器 nn.Sequential 是 nn.module的容器&#xff0c;用于按顺序包装一组网络层 • 顺序性&#xff1a;各网络层之间严格按照顺序构建 • 自带forward()&#xf…

nodejs版本管理工具nvm的安装与使用

提示&#xff1a;nodejs版本管理工具nvm的安装与使用 文章目录 前言一、安装二、淘宝镜像配置三、安装所需版本的nodejs四、切换nodejs版本五、参考文档总结 前言 需求&#xff1a;新建一个vue3项目&#xff0c;&#xff0c;提示写法错误 查原因为node版本过低 随着技术更新迭…