Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 69 additions & 0 deletions src/components/behavior.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
interface Entity<B = unknown> {
behavior: BehaviorComponent<B>;
}

type UpdateFunc = (entity: Entity) => void;

/**
* Behavior component.
*/
export interface BehaviorComponent<T = unknown> {
/** Generic state. Presumably used by the update function. */
state: T;
/** Update function, called each frame. */
update: UpdateFunc;
}

/**
* Creates a simple behavior based on an update function.
* @param initialState Initial state value.
* @param updateFunc Update function.
*/
export function setBehavior<T>(initialState: T, updateFunc: UpdateFunc): BehaviorComponent<T> {
return {
state: initialState,
update: updateFunc,
};
}

/** Generator type required by setBehaviorGenerator. */
export type BehaviorGenerator = Generator<void, void, unknown>;

type GeneratorFunc = (entity: Entity) => BehaviorGenerator;

type GeneratorState = {
generatorFunc: GeneratorFunc;
generator: null | BehaviorGenerator;
}

/**
* Updates a generator-based behavior.
* @param entity Entity to update.
*/
function updateGenerator(entity: Entity<GeneratorState>) {
const state = entity.behavior.state;

if (!state.generator) {
state.generator = state.generatorFunc(entity);
}

const result = state.generator.next();

if (result.done) {
state.generator = null;
}
}

/**
* Creates a behavior based on a generator function. The generator will be advanced once per update.
* @param generatorFunc Generator function to use during update.
*/
export function setBehaviorGenerator(generatorFunc: GeneratorFunc): BehaviorComponent<GeneratorState> {
return {
state: {
generatorFunc: generatorFunc,
generator: null,
},
update: updateGenerator,
};
}
2 changes: 2 additions & 0 deletions src/states/gameplay/entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { VelocityComponent } from "./../../components/velocity";
import { SpriteComponent } from "./../../components/sprite";
import { TimerComponent } from "./../../components/timer";
import { CooldownComponent } from "../../components/cooldown";
import { BehaviorComponent } from "src/components/behavior";

/**
* Class to represent an entity in the game. No constructor as an entity can
Expand All @@ -22,4 +23,5 @@ export class Entity {
public hitBox?: HitBoxComponent;
public timer?: TimerComponent;
public cooldown?: CooldownComponent;
public behavior?: BehaviorComponent;
}
29 changes: 29 additions & 0 deletions src/states/gameplay/state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,32 @@ import { setCooldown } from "./../../components/cooldown";
import { cooldownSystem } from "./../../systems/cooldown";
import { Engine } from "../../engine/engine";
import { EventTypes } from "./../../events/eventtypes";
import { behaviorSystem } from "../../systems/behavior";
import { setBehaviorGenerator } from "../../components/behavior";

function* enemyBehavior(entity: Entity): Generator<void, never> {
let dir = 'left';

while (true) {
if (entity.pos.loc.x <= 750) {
dir = 'right';
}
if (entity.pos.loc.x >= 1000) {
dir = 'left';
}

switch (dir) {
case 'left':
entity.vel.positional.setX(-3);
break;
case 'right':
entity.vel.positional.setX(3);
break;
}

yield;
}
}

export class GamePlayState extends BaseState {
public gameScene: Scene;
Expand Down Expand Up @@ -76,6 +102,7 @@ export class GamePlayState extends BaseState {

// Register systems.
this.registerSystem(controlSystem, "control");
this.registerSystem(behaviorSystem);
this.registerSystem(velocitySystem);
this.registerSystem(collisionSystem);
this.registerSystem(animationSystem);
Expand Down Expand Up @@ -128,6 +155,8 @@ export class GamePlayState extends BaseState {
// this.removeEntity(other);
// }
}
enemy.vel = setVelocity(0);
enemy.behavior = setBehaviorGenerator(enemyBehavior);

this.registerEntity(enemy);
}
Expand Down
19 changes: 19 additions & 0 deletions src/systems/behavior.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { MeshBasicMaterial, NearestFilter, Mesh } from "three";
import { BehaviorComponent } from "./../components/behavior";
import { BaseState } from "../engine/basestate";

type Entity = {
behavior: BehaviorComponent<unknown>;
};

/**
* Animation System.
* @param ents Lists of ents to run system with. Must have anim and sprite components.
*/
export function behaviorSystem(ents: ReadonlyArray<Entity>, state: BaseState) : void {
ents.forEach(ent => {
if (ent.behavior) {
ent.behavior.update(ent);
}
});
}