Skip to content

Commit

Permalink
simplified entities
Browse files Browse the repository at this point in the history
  • Loading branch information
gastonmorixe committed Oct 24, 2024
1 parent fff6e9a commit 91ad0df
Show file tree
Hide file tree
Showing 5 changed files with 130 additions and 88 deletions.
21 changes: 18 additions & 3 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,29 @@
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Motion</title>
<meta name="viewport" content="width=900, initial-scale=1.0" />
<title>Entity Component System Animation Engine - Gaston Morixe</title>
</head>
<body>
<main>
<h1>Entity Component System (ECS)</h1>
<h2>Physics Animation Engine (WIP)</h2>
<p>
by <a href="http://gastonmorixe.com">Gaston Morixe</a> 2024
<a
href="https://github.com/gastonmorixe/ecs-animation-engine"
target="_blank"
>Github Repo</a
>
- MIT
</p>
</main>
<div id="box1" class="box">1</div>
<div id="box2" class="box">2</div>
<div id="box3" class="box">3</div>
<canvas id="chart"></canvas>
<div id="chart-container">
<canvas id="chart"></canvas>
</div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>
21 changes: 4 additions & 17 deletions src/dom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,27 +91,14 @@ export class DOMComponent extends Component {
}

export class DOMUpdateSystem extends System {
private domLinks: Map<number, HTMLElement> = new Map();

// Link an entity with a DOM element
linkEntityToDOM(entity: Entity, domElement: HTMLElement) {
this.domLinks.set(entity.id, domElement);
}

// Update the DOM element positions based on the entity's position component
update(entities: Entity[]) {
entities.forEach((entity) => {
// const position = entity.getComponent(PositionComponent);
// if (position && this.domLinks.has(entity.id)) {
// const domElement = this.domLinks.get(entity.id);
// if (domElement) {
// domElement.style.left = `${position.x}px`;
// domElement.style.top = `${position.y}px`;
// }
// }
const position = entity.getComponent(PositionComponent);
if (position && this.domLinks.has(entity.id)) {
const domElement = this.domLinks.get(entity.id);
const domComponent = entity.getComponent(DOMComponent);

if (position && domComponent) {
const domElement = domComponent.domElement;
if (domElement) {
domElement.style.transform = `translate(${position.x}px, ${position.y}px)`;
}
Expand Down
52 changes: 52 additions & 0 deletions src/entities.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { Entity } from "./ecs";
import {
PositionComponent,
VelocityComponent,
ForceComponent,
FrictionComponent,
MassComponent,
AccumulatedForceComponent,
} from "./components";
import { DOMComponent, MouseDragComponent } from "./dom";

// Define BoxEntity to represent a box that can be dragged
export class BoxEntity extends Entity {
constructor(
domElement: HTMLElement,
initialPositon: { x: number; y: number },
name?: string,
initialVelocity: { vx: number; vy: number } = { vx: 0, vy: 0 },
mass: number = 1,
friction: number = 0.05,
) {
super();

this.name = name;
this.addComponent(
new PositionComponent(initialPositon.x, initialPositon.y),
); // Initial position
this.addComponent(
new VelocityComponent(initialVelocity.vx, initialVelocity.vy),
); // Initial velocity
this.addComponent(new MassComponent(mass)); // Mass of the entity
this.addComponent(new ForceComponent()); // Force acting on the entity
this.addComponent(new AccumulatedForceComponent()); // Force acting on the entity
this.addComponent(new MouseDragComponent()); // Component for mouse dragging
this.addComponent(new FrictionComponent(friction)); // Friction acting on the entity
this.addComponent(new DOMComponent(domElement)); // DOM element associated with the entity
}
}

// Define an AnchorEntity to represent a fixed anchor point
export class AnchorEntity extends Entity {
constructor(initialPositon: { x: number; y: number }, name?: string) {
super();
this.name = name;
this.addComponent(
new PositionComponent(initialPositon.x, initialPositon.y),
); // Initial position
this.addComponent(new VelocityComponent(0, 0)); // Initial velocity
this.addComponent(new ForceComponent()); // Force acting on the entity
this.addComponent(new AccumulatedForceComponent()); // Force acting on the entity
}
}
86 changes: 21 additions & 65 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,97 +4,49 @@ import "./style.css";
import { AnimationEngine } from "./engine";

// ECS
import { Entity } from "./ecs";
import {
PositionComponent,
VelocityComponent,
MassComponent,
ForceComponent,
AccumulatedForceComponent,
FrictionComponent,
} from "./components";
import { MovementSystem, FrictionSystem } from "./systems";

// Specific Components and Systems
import {
MouseDragComponent,
MouseForceSystem,
DOMComponent,
DOMUpdateSystem,
DOMMouseDragHandler,
} from "./dom";
// Specialized Systems and Entities
import { MouseForceSystem, DOMUpdateSystem, DOMMouseDragHandler } from "./dom";
import { BoxEntity, AnchorEntity } from "./entities";
import { SpringEntity, SpringPhysicsSystem } from "./spring";
import { ChartSystem } from "./chart";

//
// Application Logic
// -- Entities --
//

// Create the ECS engine
const engine = new AnimationEngine();

// Create the box entity
const boxEntity = new Entity();
boxEntity.name = "box1";
boxEntity.addComponent(new PositionComponent(100, 100)); // Initial position
boxEntity.addComponent(new VelocityComponent(0, 0)); // Initial velocity
boxEntity.addComponent(new MassComponent(1)); // Mass of the entity
boxEntity.addComponent(new ForceComponent()); // Force acting on the entity
boxEntity.addComponent(new AccumulatedForceComponent()); // Force acting on the entity TODO: may not be needed
boxEntity.addComponent(new MouseDragComponent()); // Component for mouse dragging
boxEntity.addComponent(new FrictionComponent(0.05));

const boxElement = document.getElementById("box1") as HTMLElement;
boxEntity.addComponent(new DOMComponent(boxElement));
const boxEntity = new BoxEntity(boxElement, { x: 100, y: 100 }, "box1");

// Creating the spring force
const anchorEntity = new Entity();
anchorEntity.name = "anchor";
anchorEntity.addComponent(new PositionComponent(100, 100)); // Fixed point for the spring
anchorEntity.addComponent(new VelocityComponent(0, 0)); // Initial velocity of the anchor point
anchorEntity.addComponent(new ForceComponent()); // Force acting on the anchor point
anchorEntity.addComponent(new AccumulatedForceComponent()); // Force acting on the anchor point
// Creating a fixed anchor
const anchorEntity = new AnchorEntity({ x: 100, y: 100 }, "anchor");

// Create a spring entity that connects entityA and entityB
// Create a spring entity that connects box1 and anchor
const springEntity = new SpringEntity(boxEntity, anchorEntity, 0.2, 0.05, 1.0);
springEntity.name = "spring";

// Create second box entity
const boxEntity2 = new Entity();
boxEntity2.name = "box2";
boxEntity2.addComponent(new PositionComponent(250, 100)); // Initial position
boxEntity2.addComponent(new VelocityComponent(0, 0)); // Initial velocity
boxEntity2.addComponent(new MassComponent(1)); // Mass of the entity
boxEntity2.addComponent(new ForceComponent()); // Force acting on the entity
boxEntity2.addComponent(new AccumulatedForceComponent()); // Force acting on the entity TODO: may not be needed
boxEntity2.addComponent(new MouseDragComponent()); // Component for mouse dragging
boxEntity2.addComponent(new FrictionComponent(0.05));

const boxElement2 = document.getElementById("box2") as HTMLElement;
boxEntity2.addComponent(new DOMComponent(boxElement2));
const boxEntity2 = new BoxEntity(boxElement2, { x: 250, y: 100 }, "box2");

// Creating the spring force connecting box and box2
const springEntity2 = new SpringEntity(boxEntity, boxEntity2, 0.2, 0.05, 2.0);
springEntity2.name = "spring2";

// Create third box entity
const boxEntity3 = new Entity();
boxEntity3.name = "box3";
boxEntity3.addComponent(new PositionComponent(400, 100)); // Initial position
boxEntity3.addComponent(new VelocityComponent(0, 0)); // Initial velocity
boxEntity3.addComponent(new MassComponent(1)); // Mass of the entity
boxEntity3.addComponent(new ForceComponent()); // Force acting on the entity
boxEntity3.addComponent(new AccumulatedForceComponent()); // Force acting on the entity
boxEntity3.addComponent(new MouseDragComponent()); // Component for mouse dragging
boxEntity3.addComponent(new FrictionComponent(0.05));

const boxElement3 = document.getElementById("box3") as HTMLElement;
boxEntity3.addComponent(new DOMComponent(boxElement3));
const boxEntity3 = new BoxEntity(boxElement3, { x: 400, y: 100 }, "box3");

// Creating the spring force connecting box2 and box3
const springEntity3 = new SpringEntity(boxEntity2, boxEntity3, 0.1, 0.05, 1.0);
springEntity3.name = "spring3";

//
// --- Systems ---
//

// Set up the movement system (handles physics and movement)
const movementSystem = new MovementSystem();

Expand All @@ -109,9 +61,6 @@ const mouseForceSystem = new MouseForceSystem(0.2, 0.1); // Drag strength and da

// Set up the DOM update system (handles syncing the DOM with the entity position)
const domUpdateSystem = new DOMUpdateSystem();
domUpdateSystem.linkEntityToDOM(boxEntity, boxElement);
domUpdateSystem.linkEntityToDOM(boxEntity2, boxElement2);
domUpdateSystem.linkEntityToDOM(boxEntity3, boxElement3);

// Set up the DOM mouse drag handler to handle mouse events via the DOM component
const domMouseDragHandler = new DOMMouseDragHandler();
Expand All @@ -123,6 +72,13 @@ domMouseDragHandler2.initializeDragListeners(boxEntity2);
const domMouseDragHandler3 = new DOMMouseDragHandler();
domMouseDragHandler3.initializeDragListeners(boxEntity3);

//
// -- Engine --
//

// Create the ECS engine
const engine = new AnimationEngine();

// Add Entities to the engine
engine.addEntity(anchorEntity);
engine.addEntity(boxEntity);
Expand Down
38 changes: 35 additions & 3 deletions src/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
font-weight: 400;

/*color-scheme: light dark;*/
color: rgba(255, 255, 255, 0.87);
/*color: rgba(255, 255, 255, 0.87);*/
color: black;
background-color: #fff;

font-synthesis: none;
Expand All @@ -13,6 +14,23 @@
-moz-osx-font-smoothing: grayscale;
}

html,
body {
width: 100%;
position: relative;
height: 100%;
}

h1 {
margin: 0;
}
h2 {
margin: 0;
}
p {
margin: 0;
}

.box {
--bg-color: blue;
background-color: var(--bg-color);
Expand All @@ -33,6 +51,7 @@
justify-content: center;
font-size: 1.5rem;
font-weight: 600;
color: white;
&.dragging {
cursor: grabbing;
box-shadow: 0 15px 15px rgba(0, 0, 0, 0.15);
Expand All @@ -47,10 +66,23 @@
--bg-color: green;
}

#chart {
#chart-container {
pointer-events: none;
user-select: none;
position: absolute;
bottom: 20px;
width: 100%;
width: calc(100% - 20px);
left: 0;
right: 0;
height: 90%;
/*background-color: yellow;*/
display: flex;
flex-direction: column;
justify-content: flex-end;
z-index: -1;
canvas {
/*height: 100%;*/
width: 100%;
/*background-color: green;*/
}
}

0 comments on commit 91ad0df

Please sign in to comment.