Skip to content

Commit

Permalink
feat(rendering): implement rendering system
Browse files Browse the repository at this point in the history
add rendering system implementation + ShapeComponent draw logic
  • Loading branch information
ruggero-visintin committed Dec 5, 2023
1 parent a0034c8 commit 5fb7cef
Show file tree
Hide file tree
Showing 9 changed files with 81 additions and 14 deletions.
4 changes: 4 additions & 0 deletions src/ecs/components/BaseComponent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,8 @@ export class BaseComponent implements IComponent {
public getContainer(): IEntity {
throw new Error("Method not implemented.");
}

public setContainer(): IEntity {
throw new Error("Method not implemented.");
}
}
1 change: 1 addition & 0 deletions src/ecs/components/IComponent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ import { IEntity } from "../entities";

export interface IComponent {
getContainer(): IEntity;
setContainer(container: IEntity): void;
}
19 changes: 18 additions & 1 deletion src/ecs/components/ShapeComponent.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,26 @@
import { PrimitiveType } from "../../renderer/RenderCommand";
import { Renderer } from "../../renderer";
import { DrawPrimitiveCommand, PrimitiveType } from "../../renderer/RenderCommand";
import { BaseComponent } from "./BaseComponent";
import { TransformComponent } from "./TransformComponent";

/**
* Represents a primitive Shape like rectangle, circle, etc
*/
export class ShapeComponent extends BaseComponent {
public shapeType: PrimitiveType = PrimitiveType.Rectangle;

private get transform(): TransformComponent {
return new TransformComponent();
}

public draw(renderer: Renderer): void {
const position = this.transform.position;
const size = this.transform.size;

renderer.pushRenderCommand(new DrawPrimitiveCommand(
PrimitiveType.Rectangle,
[position.x, position.y],
[size.width, size.height]
));
}
}
8 changes: 4 additions & 4 deletions src/ecs/entities/BaseEntity.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { BaseComponent } from "../components";
import { BaseComponent, IComponent } from "../components";
import { IEntity } from "./IEntity";

export class BaseEntity implements IEntity {
private components: Map<string, BaseComponent> = new Map();
private components: Map<string, IComponent> = new Map();

public addComponent<Component extends BaseComponent>(key: string, component: Component): void {
public addComponent(key: string, component: IComponent): void {
this.components.set(key, component);
}

public getComponent<Component extends BaseComponent>(key: string): Component | undefined {
public getComponent<Component extends IComponent>(key: string): Component | undefined {
return this.components.get(key) as Component;
}
}
2 changes: 1 addition & 1 deletion src/ecs/entities/IEntity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@ import { IComponent } from "../components";

export interface IEntity {
addComponent(key: string, component: IComponent): void;
getComponent(key: string): IComponent | undefined;
getComponent<T extends IComponent>(key: string): T | undefined;
}
9 changes: 7 additions & 2 deletions src/ecs/systems/RenderSystem.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
import { Renderer } from "../../renderer";
import { ShapeComponent } from "../components";
import { ISystem } from "./ISystem";

export class RenderSystem implements ISystem {
public readonly components: ShapeComponent[] = []
public readonly components: ShapeComponent[] = [];

constructor(
private readonly renderer: Renderer
) {}

public registerComponent(component: ShapeComponent): void {
this.components.push(component);
}

public update(): void {
throw new Error('NotImplemented');
this.components.forEach(component => component.draw(this.renderer));
}
}
11 changes: 7 additions & 4 deletions test/unit/ecs/components/BaseComponent.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import { BaseComponent } from "../../../../src";

describe('ecs/components/BaseComponent', () => {
it('Should construct', () => {
new BaseComponent();
describe('.getContainer()', () => {
it.todo('Should get the container entity of the component');
it.todo('Should return null if the component is not attached to an entity');
})

describe('.setConatiner', () => {
it.todo('Should set the container entity to the component');
})
})
18 changes: 18 additions & 0 deletions test/unit/ecs/components/ShapeComponent.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { CanvasDevice, DrawPrimitiveCommand, PrimitiveType, Renderer, ShapeComponent } from "../../../../src";

describe('ecs/components/ShapeComponent', () => {
describe('.draw()', () => {
const shapeComponent = new ShapeComponent();
const renderer = new Renderer(new CanvasDevice());

it('Should push the right draw command to the renderer', () => {
shapeComponent.draw(renderer);

expect(renderer.commandBuffer).toEqual([new DrawPrimitiveCommand(
PrimitiveType.Rectangle,
[0, 0],
[0, 0],
)]);
})
})
})
23 changes: 21 additions & 2 deletions test/unit/ecs/systems/RenderSystem.test.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { RenderSystem, ShapeComponent } from "../../../../src"
import { CanvasDevice, RenderSystem, Renderer, ShapeComponent } from "../../../../src";

describe('systems/RenderSystem', () => {
describe('.registerComponent()', () => {
const renderSystem = new RenderSystem();
const renderSystem = new RenderSystem(new Renderer(new CanvasDevice()));
const myTestShape = new ShapeComponent();

it('Should register the component into the RenderSystem components list', () => {
Expand All @@ -11,4 +11,23 @@ describe('systems/RenderSystem', () => {
expect(renderSystem.components).toContain(myTestShape);
})
})

describe('.update()', () => {
const renderSystem = new RenderSystem(new Renderer(new CanvasDevice()));

it('Should draw renderable object', () => {
const drawSpy = jest.spyOn(ShapeComponent.prototype, 'draw');

renderSystem.registerComponent(new ShapeComponent());
renderSystem.registerComponent(new ShapeComponent());

renderSystem.update();

expect(drawSpy).toHaveBeenCalledTimes(2);
});

it.todo('Should render objects based on their depthIndex in reverse order (0 rendered last)')

it.todo('Should render object based on their transparency (transparent last)')
})
})

0 comments on commit 5fb7cef

Please sign in to comment.