В этой серии уроков я постараюсь познакомить вас с основными концепциями ECS, создав игру с помощью ECS Game Framework.
Что такое ECS?
ECS или Entity-Component-System — это архитектура разработки игр, которая используется для разработки высокоэффективных игр. Она состоит из 3 элементов —
1. Сущность
относится к игровому объекту/сущности, состоящей из различных компонентов. Системы «запрашивают» эти сущности для выполнения различных функций. Они хранят «данные», которые используются системами для определения текущего состояния сущности и выполнения соответствующих операций.
2. Компонент
Компонент — это не что иное, как данные или свойство. Сущность может иметь несколько компонентов, таких как здоровье, положение, форма и т.д.
3. Система
Система — это место, где все начинает двигаться. Вы можете думать о них как о функциях, которые вызываются при каждом тике/обновлении. Они выполняют специализированные функции, такие как рендеринг сущностей, физика, столкновения и т.д. Они «запрашивают» интересующие их компоненты (те, которые имеют определенный набор компонентов, необходимых системе) и обновляют игру.
Запрос
Другим важным компонентом ECS является запрос. Его можно представить как набор/массив имен компонентов. Системы используют эти запросы, чтобы получить список сущностей, которые имеют эти компоненты. Это похоже на то, как вы запрашиваете элементы DOM с помощью CSS-запросов.
Начало
Мы будем использовать Square — ECS Framework, написанный на Javascript.
Структура проекта
/game
- queries.js
- components.js
- systems.js
- main.js
queries.js
Он будет содержать запросы, которые будут использовать наши системы.
export const Renderable = ['@position', '@size', '@shape'];
components.js
export class PositionComponent {
constructor(x = 0, y = 0) {
this.x = x;
this.y = y;
}
}
export class SizeComponent {
constructor(width = 0, height = 0) {
this.width = width;
this.height = height;
}
}
export class ShapeComponent {
static RECTANGLE = 'rectangle';
}
systems.js
import { ShapeComponent } from './components.js';
export function RenderingSystem(app) {
const canvas = document.createElement('canvas');
const context = canvas.getContext('2d');
app.on('init', () => document.body.appendChild(canvas));
app.on('update', () => {
context.clearRect(0, 0, canvas.width, canvas.height);
app.emit('render', canvas, context);
});
}
export function ShapeRenderer(app) {
app.on('render', (_canvas, ctx) => {
const entities = app.query('@shape');
entities.forEach(entity => {
if(entity.shape === ShapeComponent.RECTANGLE) {
ctx.fillRect(
entity.position.x,
entity.position.y,
entity.size.width,
entity.size.height
);
}
});
});
}
main.js
// importing the library
import { Application } from 'https://unpkg.com/square-ecs@latest';
// importing various parts of our game
import { RenderingSystem, ShapeRenderer } from './systems.js';
import { PositionComponent, SizeComponent, ShapeComponent } from './components.js';
// creating an instance of the game
const app = new Application({
// shared data that our game will use,
// it can contain any kind of data
data: {},
// systems of our game
systems: [
RenderingSystem,
ShapeRenderer
]
});
app.on('init', () => {
const entity = app.entityPool.getEntity(); // borrow an entity from the entity pool
// attach various components
entity
.attach('shape', ShapeComponent.RECTANGLE)
.attach('position', new PositionComponent(100, 100))
.attach('size', new SizeComponent(50, 50));
// add it to the world
app.add(entity);
});
// start the game
app.start();
Вывод
Да! Мы успешно отрисовали квадрат.
В следующей статье все начнет двигаться.
Джай Шри Рам!