import { makeText } from "./text" export type Creator = (objIn: A) => B export type Builder = Creator, A> export type Extender = Creator, B> export function makeCombined(fn1: Builder): Builder export function makeCombined(fn1: Builder, fn2: Extender): Builder export function makeCombined(fn1: Builder, fn2: Extender, fn3: Extender): Builder export function makeCombined(fn1: Builder, fn2: Extender, fn3: Extender, fn4: Extender): Builder export function makeCombined(fn1: Builder, fn2: Extender, fn3: Extender, fn4: Extender, fn5: Extender): Builder export function makeCombined(fn1: Builder, fn2: Extender, fn3: Extender, fn4: Extender, fn5: Extender, fn6: Extender): Builder export function makeCombined(fn1: Builder, fn2?: Extender, fn3?: Extender, fn4?: Extender, fn5?: Extender, fn6?: Extender): Builder | Builder | Builder | Builder | Builder | Builder { if(fn2 && fn3 && fn4 && fn5 && fn6) return makeCombined(makeCombined(fn1, fn2, fn3, fn4, fn5), fn6) if(fn2 && fn3 && fn4 && fn5) return makeCombined(makeCombined(fn1, fn2, fn3, fn4), fn5) if(fn2 && fn3 && fn4) return makeCombined(makeCombined(fn1, fn2, fn3), fn4) if(fn2 && fn3) return makeCombined(makeCombined(fn1, fn2), fn3) if(fn2) return (objIn: Partial) => fn2(>fn1(objIn)) return fn1 } export interface HasIdentity { id: number } export interface HasPosition { position: Vector2 } export interface HasColor { color: Color } export interface HasBoundingBox { boundingBox: Rectangle } export interface Behaviour { load?: (entity: T) => void, unload?: (entity: T) => void, update?: (entity: T) => void, draw?: (entity: T) => void } export function addBehaviour(obj: T, behaviour: Behaviour){ obj.behaviours.push(behaviour) } export function removeBehaviour(obj: T, behaviour: Behaviour){ const idx = obj.behaviours.findIndex(x => x === behaviour) if(idx !== -1) obj.behaviours.splice(idx, 1) } export interface HasBehaviour { behaviours: Behaviour[] } export type Entity = HasIdentity & HasBehaviour export type EntityOf = Entity & T export const setPropFn = (obj: T, key: keyof T, valueFn: () => any) => { if(obj[key] === undefined) obj[key] = valueFn() } export const setProp = (obj: T, key: keyof T, value: any) => { if(obj[key] === undefined) obj[key] = value } let ID = 0 export const makeIdentity = (obj: Partial) => { setPropFn(obj, 'id', () => ID++) return obj } export const makeBehaviour = (obj: Partial) => { setPropFn(obj, 'behaviours', () => []) return obj } export const makeEntity: Builder = makeCombined(makeIdentity, makeBehaviour) export const makePosition = (obj: Partial,x = 0, y = 0) => { setPropFn(obj, 'position', () => new Vector2(x,y)) return obj } export const makeColorRgb = (obj: Partial, r = 255, g = 255, b = 255, a = 255) => { setPropFn(obj, 'color', () => new Color(r, g, b, a)) return obj } export const makeColor = (obj: Partial, c = WHITE) => { setPropFn(obj, 'color', () => new Color(c.r, c.g, c.b, c.a)) return obj } export const makeBoundingBox = (obj: Partial, x = 0, y = 0, width = 0, height = 0) => { setPropFn(obj, 'boundingBox', () => new Rectangle(x,y,width,height)) return obj } export const debugRectDrawFn = (obj: HasBoundingBox, color = GREEN) => drawRectangleLines(obj.boundingBox.x, obj.boundingBox.y, obj.boundingBox.width, obj.boundingBox.height, color) export const debugRectDrawBehaviour = { draw: debugRectDrawFn } export interface Clickable extends HasBoundingBox, HasBehaviour { isClicked: boolean hasMouseOver: boolean, hasMouseEntered: boolean, hasMouseLeft: boolean debugClickable: boolean } export const clickableBehaviour: Behaviour = { update: (obj: Clickable) => { const over = checkCollisionPointRec(getMousePosition(), obj.boundingBox) obj.hasMouseEntered = !obj.hasMouseOver && over obj.hasMouseLeft = obj.hasMouseOver && !over obj.hasMouseOver = over obj.isClicked = obj.hasMouseOver && isMouseButtonPressed(MOUSE_BUTTON_LEFT) if(obj.hasMouseEntered) setMouseCursor(MOUSE_CURSOR_POINTING_HAND) if(obj.hasMouseLeft) setMouseCursor(MOUSE_CURSOR_DEFAULT) }, draw: (obj: Clickable) => { if(obj.debugClickable){ debugRectDrawFn(obj, obj.hasMouseOver ? RED : GREEN) drawCircle(getMouseX(), getMouseY(), 10, YELLOW) } }, unload: obj => setMouseCursor(MOUSE_CURSOR_DEFAULT) } export const makeClickable: Builder = makeCombined(makeBehaviour, makeBoundingBox, (obj: HasBehaviour & HasBoundingBox & Partial) => { setProp(obj, 'hasMouseOver', false) setProp(obj, 'isClicked', false) setProp(obj, 'hasMouseEntered', false) setProp(obj, 'hasMouseLeft', false) setProp(obj, 'debugClickable', false) addBehaviour(obj, clickableBehaviour) return obj })