(window.webpackJsonp=window.webpackJsonp||[]).push([[65],{114:function(e,t,n){"use strict";n.r(t),n.d(t,"frontMatter",(function(){return r})),n.d(t,"metadata",(function(){return s})),n.d(t,"rightToc",(function(){return m})),n.d(t,"default",(function(){return d}));var a=n(2),i=n(6),l=(n(0),n(131)),b=n(132),c=n(133),o=n.n(c),r={title:"PIXI-ECS Docs",description:"Documentation of PIX-ECS library"},s={unversionedId:"ecsdocs",id:"ecsdocs",isDocsHomePage:!1,title:"PIXI-ECS Docs",description:"Documentation of PIX-ECS library",source:"@site/docs\\ecsdocs.md",slug:"/ecsdocs",permalink:"/docs/ecsdocs",version:"current",sidebar:"docs",previous:{title:"Course requirements",permalink:"/docs/requirements"},next:{title:"Config",permalink:"/docs/examples/pixi-intro/config"}},m=[{value:"Pixi architecture",id:"pixi-architecture",children:[]},{value:"ECS Library",id:"ecs-library",children:[{value:"Architecture",id:"architecture",children:[]},{value:"PIXI-ECS binding",id:"pixi-ecs-binding",children:[]},{value:"How to start",id:"how-to-start",children:[]},{value:"Components",id:"components",children:[]},{value:"Game Object",id:"game-object",children:[]},{value:"Scene",id:"scene",children:[]},{value:"Delayed invocation",id:"delayed-invocation",children:[]},{value:"Messaging",id:"messaging",children:[]},{value:"Built-in messages",id:"built-in-messages",children:[]}]},{value:"Built-in components and tools",id:"built-in-components-and-tools",children:[{value:"Builder",id:"builder",children:[]},{value:"Chain Component",id:"chain-component",children:[]},{value:"Functional component",id:"functional-component",children:[]},{value:"Key-Input Component",id:"key-input-component",children:[]},{value:"Pointer-Input Component",id:"pointer-input-component",children:[]},{value:"Virtual-Gamepad Component",id:"virtual-gamepad-component",children:[]},{value:"Vector",id:"vector",children:[]},{value:"Responsive mode",id:"responsive-mode",children:[]},{value:"Debug Component",id:"debug-component",children:[]}]}],p={rightToc:m};function d(e){var t=e.components,n=Object(i.a)(e,["components"]);return Object(l.b)("wrapper",Object(a.a)({},p,n,{components:t,mdxType:"MDXLayout"}),Object(l.b)("ul",null,Object(l.b)("li",{parentName:"ul"},"documentation to the ",Object(l.b)("inlineCode",{parentName:"li"},"PIXI-ECS")," library that can be found in the repository")),Object(l.b)("h2",{id:"pixi-architecture"},"Pixi architecture"),Object(l.b)("div",{className:o.a.figure},Object(l.b)("img",{src:Object(b.a)("img/docs/tutorials/02-pixi/diag_pixi_classes.svg")})),Object(l.b)("h2",{id:"ecs-library"},"ECS Library"),Object(l.b)("ul",null,Object(l.b)("li",{parentName:"ul"},"a minimalist library for NI-APH that implements ECS pattern with the most important amenities"),Object(l.b)("li",{parentName:"ul"},"located in ",Object(l.b)("inlineCode",{parentName:"li"},"examples/libs/pixi-ecs")),Object(l.b)("li",{parentName:"ul"},Object(l.b)("strong",{parentName:"li"},"features"),Object(l.b)("ul",{parentName:"li"},Object(l.b)("li",{parentName:"ul"},"object builder"),Object(l.b)("li",{parentName:"ul"},"scene manager"),Object(l.b)("li",{parentName:"ul"},"PIXI-ECS bridging"),Object(l.b)("li",{parentName:"ul"},"messaging pattern"),Object(l.b)("li",{parentName:"ul"},"reactive components"),Object(l.b)("li",{parentName:"ul"},"states, flags and tags"),Object(l.b)("li",{parentName:"ul"},"simple debugging window"),Object(l.b)("li",{parentName:"ul"},"keyboard/pointer handlers")))),Object(l.b)("h3",{id:"architecture"},"Architecture"),Object(l.b)("ul",null,Object(l.b)("li",{parentName:"ul"},Object(l.b)("strong",{parentName:"li"},"PIXI.Application"),Object(l.b)("ul",{parentName:"li"},Object(l.b)("li",{parentName:"ul"},"PIXI application"))),Object(l.b)("li",{parentName:"ul"},Object(l.b)("strong",{parentName:"li"},"PIXI.Ticker"),Object(l.b)("ul",{parentName:"li"},Object(l.b)("li",{parentName:"ul"},"PIXI clock for game loop"))),Object(l.b)("li",{parentName:"ul"},Object(l.b)("strong",{parentName:"li"},"PIXI.Container, PIXI.Sprite,..."),Object(l.b)("ul",{parentName:"li"},Object(l.b)("li",{parentName:"ul"},"PIXI game objects"))),Object(l.b)("li",{parentName:"ul"},Object(l.b)("strong",{parentName:"li"},"ECS.Engine"),Object(l.b)("ul",{parentName:"li"},Object(l.b)("li",{parentName:"ul"},"entry point to the library, accepts a configuration object and initializes PIXI game loop"))),Object(l.b)("li",{parentName:"ul"},Object(l.b)("strong",{parentName:"li"},"ECS.Scene"),Object(l.b)("ul",{parentName:"li"},Object(l.b)("li",{parentName:"ul"},"a scene manager, provides querying of components and game objects, manages global components"))),Object(l.b)("li",{parentName:"ul"},Object(l.b)("strong",{parentName:"li"},"ECS.Component"),Object(l.b)("ul",{parentName:"li"},Object(l.b)("li",{parentName:"ul"},"functional components of game objects"),Object(l.b)("li",{parentName:"ul"},"global components are attached to the ",Object(l.b)("inlineCode",{parentName:"li"},"stage")," object"))),Object(l.b)("li",{parentName:"ul"},Object(l.b)("strong",{parentName:"li"},"ECS.GameObject"),Object(l.b)("ul",{parentName:"li"},Object(l.b)("li",{parentName:"ul"},"an interface that declares extension methods for PIXI containers"),Object(l.b)("li",{parentName:"ul"},"in older versions, all components and the ",Object(l.b)("inlineCode",{parentName:"li"},"Scene")," worked with the containers through ",Object(l.b)("inlineCode",{parentName:"li"},"GameObject")," interface and accessing PIXI attributes required to use casting functions such as \u02d9asContainer()\u02d9. The current version uses inherited \u02d9ECS.Container\u02d9, so that it is possible to access both ",Object(l.b)("inlineCode",{parentName:"li"},"ECS")," and ",Object(l.b)("inlineCode",{parentName:"li"},"PIXI")," functions at the same time. ",Object(l.b)("inlineCode",{parentName:"li"},"GameObject")," interface is now only used internally for derived objects to force them to implement all ",Object(l.b)("inlineCode",{parentName:"li"},"ECS")," functions"))),Object(l.b)("li",{parentName:"ul"},Object(l.b)("strong",{parentName:"li"},"ECS.GameObjectProxy"),Object(l.b)("ul",{parentName:"li"},Object(l.b)("li",{parentName:"ul"},"a delegate that contains implementation of methods in ",Object(l.b)("inlineCode",{parentName:"li"},"ECS.GameObject")," interface. It's used as a proxy by respective containers (because JavaScript doesn't have multi-inheritance facility)"))),Object(l.b)("li",{parentName:"ul"},Object(l.b)("strong",{parentName:"li"},"ECS.Container, ECS.Sprite,..."),Object(l.b)("ul",{parentName:"li"},Object(l.b)("li",{parentName:"ul"},"PIXI containers that inherits from respective PIXI objects, implements ",Object(l.b)("inlineCode",{parentName:"li"},"ECS.GameObject")," interface and passes the implementation on to ",Object(l.b)("inlineCode",{parentName:"li"},"ECS.GameObjectProxy")," (in order to avoid duplicated code)")))),Object(l.b)("div",{className:o.a.figure},Object(l.b)("img",{src:Object(b.a)("img/docs/pixi-ecs/arch_ecs.svg")})),Object(l.b)("h3",{id:"pixi-ecs-binding"},"PIXI-ECS binding"),Object(l.b)("ul",null,Object(l.b)("li",{parentName:"ul"},"instead of creating ",Object(l.b)("inlineCode",{parentName:"li"},"PIXI.Container"),", ",Object(l.b)("inlineCode",{parentName:"li"},"PIXI.Sprite")," etc., we can create ",Object(l.b)("inlineCode",{parentName:"li"},"ECS.Container"),", ",Object(l.b)("inlineCode",{parentName:"li"},"ECS.Sprite"),",..."),Object(l.b)("li",{parentName:"ul"},"those objects inherit from their respective counterparts in PIXI. Additionally, they contain methods from ",Object(l.b)("inlineCode",{parentName:"li"},"ECS.GameObject")," interface"),Object(l.b)("li",{parentName:"ul"},"they can be treated in the same way as regular PIXI objects"),Object(l.b)("li",{parentName:"ul"},"they use ",Object(l.b)("inlineCode",{parentName:"li"},"GameObjectProxy")," as a provider of the implementation of ECS features"),Object(l.b)("li",{parentName:"ul"},"any functional behaviour can be implemented in components, having them manipulate with game objects they are attached to ")),Object(l.b)("div",{className:o.a.figure},Object(l.b)("img",{src:Object(b.a)("img/docs/pixi-ecs/arch_bridge.svg")})),Object(l.b)("h3",{id:"how-to-start"},"How to start"),Object(l.b)("ul",null,Object(l.b)("li",{parentName:"ul"},"import the ECS library"),Object(l.b)("li",{parentName:"ul"},"get your canvas"),Object(l.b)("li",{parentName:"ul"},"call the ",Object(l.b)("inlineCode",{parentName:"li"},"init")," function"),Object(l.b)("li",{parentName:"ul"},"load your resources by using ",Object(l.b)("inlineCode",{parentName:"li"},"PIXI loader")),Object(l.b)("li",{parentName:"ul"},"access the ",Object(l.b)("inlineCode",{parentName:"li"},"engine.scene"))),Object(l.b)("pre",null,Object(l.b)("code",Object(a.a)({parentName:"pre"},{className:"language-typescript"}),"\nimport * as ECS from '../libs/pixi-ecs';\n\nclass MyGame {\n engine: ECS.Engine;\n\n constructor() {\n this.engine = new ECS.Engine();\n let canvas = (document.getElementById('gameCanvas') as HTMLCanvasElement);\n\n this.engine.init(canvas, { width: 800, height: 600 });\n\n this.engine.app.loader\n .reset()\n .add('spritesheet', './assets/spritesheet.png')\n .load(onAssetsLoaded);\n }\n\n onAssetsLoaded = () => {\n this.engine.scene.clearScene();\n const graphics = new ECS.Graphics();\n this.engine.scene.stage.addChild(graphics);\n }\n}\n\nexport default new MyGame();\n\n")),Object(l.b)("ul",null,Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"engine.app")," is a link to ",Object(l.b)("inlineCode",{parentName:"li"},"PIXI.Application")),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"scene.stage")," is a link to the stage object in PIXI"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"scene.stage.addChild(...)")," allows us to add children to the stage object")),Object(l.b)("pre",null,Object(l.b)("code",Object(a.a)({parentName:"pre"},{className:"language-typescript"}),"let sprite = new ECS.Sprite('mySprite', PIXI.Texture.from('spritesheet'));\nsprite.position.set(engine.app.screen.width / 2, engine.app.screen.height / 2);\nsprite.anchor.set(0.5);\nengine.scene.stage.addChild(sprite);\n")),Object(l.b)("h4",{id:"config"},"Config"),Object(l.b)("ul",null,Object(l.b)("li",{parentName:"ul"},"to optimize query search in the scene, all components and objects are stored in hash maps, sets and array"),Object(l.b)("li",{parentName:"ul"},"in order not to allocate too much memory, searching has to be enabled explicitly",Object(l.b)("ul",{parentName:"li"},Object(l.b)("li",{parentName:"ul"},"don't worry! If you forget to enable it, it will inform you via an Error thrown \ud83e\udd23")))),Object(l.b)("pre",null,Object(l.b)("code",Object(a.a)({parentName:"pre"},{className:"language-typescript"}),"new ECS.Engine().init(canvas, {\n width: 800,\n height: 600,\n debugEnabled: true,\n flagsSearchEnabled: true,\n statesSearchEnabled: true,\n}, true);\n")),Object(l.b)("ul",null,Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"resizeToScreen")," - if true, the game will be resized to fit the screen"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"transparent")," - if true, the canvas will be trasparent"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"backgroundColor")," - canvas background color"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"antialias")," - enables antialiasing"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"width")," - canvas virtual width"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"height")," - canvas virtual height"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"resolution")," - scale of displayed objects (1 by default)"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"gameLoopType")," - type of the game loop (FIXED, VARIABLE)"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"gameLoopThreshold")," - upper threshold of game loop in ms (300 by default)"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"gameLoopFixedTick")," - period for fixed game loop (16ms by default)"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"speed")," - speed of the game (1 by default)"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"flagsSearchEnabled")," - enables searching by flags"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"statesSearchEnabled")," - enables searching by states"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"tagsSearchEnabled")," - enables searching by tags"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"namesSearchEnabled")," - enables searching by names"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"notifyAttributeChanges")," - enables notifying when an attribute changes"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"notifyStateChanges")," - enables notifying when a state changes"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"notifyFlagChanges")," - enables notifying when a flag changes"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"notifyTagChanges")," - enables notifying when a tag changes"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"debugEnabled")," - injects a debugging HTML element")),Object(l.b)("h3",{id:"components"},"Components"),Object(l.b)("ul",null,Object(l.b)("li",{parentName:"ul"},"every functional behavior is implemented in components"),Object(l.b)("li",{parentName:"ul"},"every component is attached to one game object"),Object(l.b)("li",{parentName:"ul"},"global components are attached directly to the stage")),Object(l.b)("div",{className:o.a.figure},Object(l.b)("img",{src:Object(b.a)("img/docs/pixi-ecs/class_component.svg")})),Object(l.b)("ul",null,Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"id")," - unique identifier"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"name")," - component name"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"props")," - custom property object (void by default)"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"owner")," - game object this component is attached to"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"scene")," - link to the scene"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"fixedFrequency")," - frequency of the fixed udpate loop (if unset, fixedUpdate() will NOT be invoked)"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"cmpState")," - component state (NEW, INITIALIZED, RUNNING, DETACHED, FINISHED)"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"onInit()")," - called when the component is added to an object"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"onAttach()")," - called when the component is attached to the scene"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"onMessage()")," - called whenever a message the component has subscribed to arrives"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"onFixedUpdate()")," - called at a fixed interval"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"onUpdate()")," - called every frame"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"onDetach()")," - called before the component is detached from the scene"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"onRemove()")," - called before the component is removed from the scene"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"onFinish()")," - called whenever someone calls 'finish()', followed by removing from the scene"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"subscribe()")," - subscribes for a message of a given key"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"unsubscribe()")," - unsubscribes a message of a given key"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"sendMessage()")," - sends a message"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"finish()")," - cancels the execution of the component and removes it from the scene instantly")),Object(l.b)("h4",{id:"a-simple-component"},"A simple component"),Object(l.b)("ul",null,Object(l.b)("li",{parentName:"ul"},"create a new component"),Object(l.b)("li",{parentName:"ul"},"initialize it in ",Object(l.b)("inlineCode",{parentName:"li"},"onInit()")),Object(l.b)("li",{parentName:"ul"},"handle incoming messages in ",Object(l.b)("inlineCode",{parentName:"li"},"onMessage()")),Object(l.b)("li",{parentName:"ul"},"handle update loop in ",Object(l.b)("inlineCode",{parentName:"li"},"onUpdate(delta, absolute)"))),Object(l.b)("pre",null,Object(l.b)("code",Object(a.a)({parentName:"pre"},{className:"language-typescript"}),"class Movement extends ECS.Component {\n\n onInit() {\n this.subscribe('STOP_EVERYTHING');\n }\n\n onMessage(msg: ECS.Message) {\n if(msg.action === 'STOP_EVERYTHING') {\n this.finish();\n }\n }\n\n onUpdate(delta: number, absolute: number) {\n this.owner.pos.set(this.owner.pos.x + 20, this.owner.pos.y);\n }\n}\n")),Object(l.b)("h4",{id:"lifecycle"},"Lifecycle"),Object(l.b)("ul",null,Object(l.b)("li",{parentName:"ul"},Object(l.b)("strong",{parentName:"li"},"components are not added to objects instantly"),", but at the beginning of the update loop of their respective objects",Object(l.b)("ul",{parentName:"li"},Object(l.b)("li",{parentName:"ul"},"immediate execution can be forced by calling ",Object(l.b)("inlineCode",{parentName:"li"},"addComponentAndRun")," instead of ",Object(l.b)("inlineCode",{parentName:"li"},"addComponent")))),Object(l.b)("li",{parentName:"ul"},"components ",Object(l.b)("strong",{parentName:"li"},"can be reused")," - removed from an object and added to another one"),Object(l.b)("li",{parentName:"ul"},"a component can be only attached to one game object at a time"),Object(l.b)("li",{parentName:"ul"},"components can receive messages if they are running"),Object(l.b)("li",{parentName:"ul"},"components can't receive message they had sent by themselves"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"finish()")," will stop the components from execution and removes it from the scene"),Object(l.b)("li",{parentName:"ul"},"if a game object is to be removed, all of its components will be finalized and removed as well"),Object(l.b)("li",{parentName:"ul"},"if the parent game object gets detached from the scene (e.g. for later reuse), all of its components will be also detached and re-attached afterwards",Object(l.b)("ul",{parentName:"li"},Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"onAttach()")," is called when a component is attached to the scene. It can happen in two cases: ",Object(l.b)("ul",{parentName:"li"},Object(l.b)("li",{parentName:"ul"},"a) component is added to an object that is already on the scene"),Object(l.b)("li",{parentName:"ul"},"b) a game object is attached to a scene (so will be its components)"))),Object(l.b)("li",{parentName:"ul"},"if the component is detached, it won't update nor receive any messages"))),Object(l.b)("li",{parentName:"ul"},Object(l.b)("strong",{parentName:"li"},"recommended"),": if you don't need to react on detaching, use only ",Object(l.b)("inlineCode",{parentName:"li"},"onInit()")," for initialization and ",Object(l.b)("inlineCode",{parentName:"li"},"onRemove()")," for clean-up")),Object(l.b)("div",{className:o.a.figure},Object(l.b)("img",{src:Object(b.a)("img/docs/pixi-ecs/lifecycle_components.svg")})),Object(l.b)("h3",{id:"game-object"},"Game Object"),Object(l.b)("ul",null,Object(l.b)("li",{parentName:"ul"},"game object is a class inherited from respective PIXI containers (Container, Sprite, Text, Mesh,...)")),Object(l.b)("div",{className:o.a.figure},Object(l.b)("img",{src:Object(b.a)("img/docs/pixi-ecs/class_gameobject.svg")})),Object(l.b)("ul",null,Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"id")," - unique identifier"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"name")," - name (empty string by default)"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"stateId")," - numeric state"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"pixiObj")," - link to a raw object"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"parentGameObject")," - link to the parent"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"scene")," - link to the scene"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"_proxy_")," - link to the proxy that contains implementation of ",Object(l.b)("inlineCode",{parentName:"li"},"GameObject")," interface"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"asContainer()")," - casts itself to ",Object(l.b)("inlineCode",{parentName:"li"},"ECS.Container")),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"asParticleContainer()")," - casts itself to ",Object(l.b)("inlineCode",{parentName:"li"},"ECS.ParticleContainer")),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"asXYZ()")," - casts itself to any class from the list of PIXI containers (throws an error if the casting is not possible)"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"addComponent()")," - adds a new component"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"findComponentByName()")," - finds a component by its name"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"removeComponent()")," - removes a component"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"assignAttribute()")," - adds a new attribute to the hashmap"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"getAttribute()")," - gets an attribute by its key"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"removeAttribute()")," - removes an existing attribute"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"addTag()")," - adds a tag to the set of tags"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"removeTag()")," - removes a tag"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"hasTag()")," - returns true if given tag is in the set"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"setFlag()")," - sets a bit-flag"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"resetFlag()")," - resets a bit-flag"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"hasFlag()")," - returns true if given bit-flag is set"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"invertFlag()")," - inverts given bit-flag"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"detach()")," - detaches object from the scene but doesn't destroy it from PIXI"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"destroy()")," - destroy the object from the scene and from inner PIXI collections, and removes all of its components"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"destroyChildren()")," - destroys all children")),Object(l.b)("pre",null,Object(l.b)("code",Object(a.a)({parentName:"pre"},{className:"language-typescript"}),"let newObject = new ECS.Sprite('warrior', warriorTexture);\n\n// we can store any number of attributes of any type\nnewObject.assignAttribute('speed', 20);\n\n// we can store as many tags as we want\nnewObject.addTag('projectile');\n\n// we can store flags within a range of 1-128\nnewObject.setFlag(FLAG_COLLIDABLE);\n\n// a numeric state for a simple \nnewObject.stateId = STATE_MOVING;\n")),Object(l.b)("h4",{id:"lifecycle-1"},"Lifecycle"),Object(l.b)("ul",null,Object(l.b)("li",{parentName:"ul"},"objects are added to the game scene ",Object(l.b)("strong",{parentName:"li"},"instantly")),Object(l.b)("li",{parentName:"ul"},"when an object is attached to the scene, the scene will invoke the update loop upon it (it's being called recursively)"),Object(l.b)("li",{parentName:"ul"},"if the object is detached, it will be removed from the game scene but it will not be destroyed",Object(l.b)("ul",{parentName:"li"},Object(l.b)("li",{parentName:"ul"},"detached objects can be re-added to the scene"))),Object(l.b)("li",{parentName:"ul"},"if the object is destroyed, it can no longer be used")),Object(l.b)("div",{className:o.a.figure},Object(l.b)("img",{src:Object(b.a)("img/docs/pixi-ecs/lifecycle_objects.svg")})),Object(l.b)("h3",{id:"scene"},"Scene"),Object(l.b)("ul",null,Object(l.b)("li",{parentName:"ul"},"serves as a message bus and scene manager")),Object(l.b)("div",{className:o.a.figure},Object(l.b)("img",{src:Object(b.a)("img/docs/pixi-ecs/class_scene.svg")})),Object(l.b)("ul",null,Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"app")," - link to the ",Object(l.b)("inlineCode",{parentName:"li"},"PIXI.Application")),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"name")," - name of the scene"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"stage")," - root game object, derived from ",Object(l.b)("inlineCode",{parentName:"li"},"PIXI.Container")),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"currentDelta")," - current delta time"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"currentAbsolute")," - current game time"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"callWithDelay(number, function)")," - invokes a function with a certain delay"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"addGlobalComponent(cmp)")," - adds a global component (attached to the stage)"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"findGlobalComponentByName(name)")," - finds a global component by name"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"removeGlobalComponent(component)")," - removes a global component"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"assignGlobalAttribute(name, attr)")," - assigns a global attribute to the stage"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"getGlobalAttribute(name)")," - gets a global atribute by name"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"removeGlobalAttribute(string)")," - removes a global attribute"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"findObjectById(id)")," - finds objects by id"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"findObjectsByQuery(query)")," - finds objects that meet conditions in the query"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"findObjectsByName(name)")," - finds objects by name"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"findObjectByName(name)")," - gets the first object of given name"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"findObjectsByTag(tag)")," - finds objects that have given tag"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"findObjectByTag(tag)")," - gets the first object that has given tag"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"findObjectsByFlag(flag)")," - finds objects that have given flag set"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"findObjectByFlag(flag)")," - gets the first object that has a given flag set"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"findObjectsByState(state)")," - finds objects by numeric state"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"findObjectByState(state)")," - gets the first object that has a numeric state set"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"sendMessage(message)")," - sends a generic message",Object(l.b)("ul",{parentName:"li"},Object(l.b)("li",{parentName:"ul"},"it's better to send message from within components (the message will carry their id)"))),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"clearScene(config)")," - erases the whole scene")),Object(l.b)("h4",{id:"scene-querying"},"Scene querying"),Object(l.b)("pre",null,Object(l.b)("code",Object(a.a)({parentName:"pre"},{className:"language-typescript"}),"let droids = scene.findObjectsByTag('droid');\nlet charged = scene.findObjectsByFlag(FLAG_CHARGED);\nlet idle = scene.findObjectsByState(STATE_IDLE);\n\nlet chargedIdleDroids = scene.findObjectsByQuery({\n ownerTag: 'droid',\n ownerFlag: FLAG_CHARGED,\n ownerState: STATE_IDLE\n});\n")),Object(l.b)("h3",{id:"delayed-invocation"},"Delayed invocation"),Object(l.b)("ul",null,Object(l.b)("li",{parentName:"ul"},"don't use ",Object(l.b)("inlineCode",{parentName:"li"},"setInterval()")," nor ",Object(l.b)("inlineCode",{parentName:"li"},"setTimeout()"),", as those two methods are invoked from the browser's event loop"),Object(l.b)("li",{parentName:"ul"},"if you want something to happen at a delay, you can use ",Object(l.b)("inlineCode",{parentName:"li"},"scene.callWithDelay()")," instead, which is invoked at the end of the update loop"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("strong",{parentName:"li"},"example: clear the whole scene after 3 seconds"))),Object(l.b)("pre",null,Object(l.b)("code",Object(a.a)({parentName:"pre"},{className:"language-typescript"}),"// invoked from within a component\nthis.scene.callWithDelay(1000, () => this.scene.clearScene());\n")),Object(l.b)("h3",{id:"messaging"},"Messaging"),Object(l.b)("ul",null,Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"Message")," is an crate for inter-component communication"),Object(l.b)("li",{parentName:"ul"},"every component contains method ",Object(l.b)("inlineCode",{parentName:"li"},"sendMessage(action, data)")),Object(l.b)("li",{parentName:"ul"},"we can also use ",Object(l.b)("inlineCode",{parentName:"li"},"scene.sendMessage(Message)")," to send a message from outside a component"),Object(l.b)("li",{parentName:"ul"},"in order to receive messages of a given type, the component first needs to register itself via ",Object(l.b)("inlineCode",{parentName:"li"},"subscribe(action)")),Object(l.b)("li",{parentName:"ul"},"all messages are handled in ",Object(l.b)("inlineCode",{parentName:"li"},"OnMessage()")," of their respective handlers",Object(l.b)("ul",{parentName:"li"},Object(l.b)("li",{parentName:"ul"},"if the ",Object(l.b)("inlineCode",{parentName:"li"},"OnMessage()")," handler returns a value, it will be collected in the ",Object(l.b)("inlineCode",{parentName:"li"},"responses")," structure"))),Object(l.b)("li",{parentName:"ul"},"if any component sets ",Object(l.b)("inlineCode",{parentName:"li"},"expired = true"),", the message will not be passed any furter")),Object(l.b)("div",{className:o.a.figure},Object(l.b)("img",{src:Object(b.a)("img/docs/pixi-ecs/class_message.svg")})),Object(l.b)("h4",{id:"example-finish-a-component-by-a-message"},"Example: Finish a component by a message"),Object(l.b)("pre",null,Object(l.b)("code",Object(a.a)({parentName:"pre"},{className:"language-typescript"}),"\nclass Sender extends ECS.Component {\n\n onInit() {\n this.fixedFrequency = 1;\n }\n\n onFixedUpdate() {\n this.sendMessage('RECEIVER_FINISH');\n }\n}\n\nclass Receiver extends ECS.Component {\n\n onInit() {\n this.subscribe('RECEIVER_FINISH');\n }\n\n onMessage(msg: ECS.Message) {\n if(msg.action === 'RECEIVER_FINISH') {\n this.finish(); // will be removed from the scene instantly\n }\n }\n}\n\n")),Object(l.b)("h3",{id:"built-in-messages"},"Built-in messages"),Object(l.b)("ul",null,Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"ANY")," - gets all messages (good for debugging)"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"OBJECT_ADDED")," - object was added to the scene"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"OBJECT_REMOVED")," - object was removed"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"COMPONENT_ADDED")," - component was added to an object"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"COMPONENT_DETACHED")," - component was detached from the scene (along with its owner)"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"COMPONENT_REMOVED")," - component was removed"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"ATTRIBUTE_ADDED")," - attribute was added (sent only when ",Object(l.b)("inlineCode",{parentName:"li"},"notifyAttributeChanges = true"),")"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"ATTRIBUTE_CHANGED")," - attribute has changed (sent only when ",Object(l.b)("inlineCode",{parentName:"li"},"notifyAttributeChanges = true"),")"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"ATTRIBUTE_REMOVED")," - attribute was removed (sent only when ",Object(l.b)("inlineCode",{parentName:"li"},"notifyAttributeChanges = true"),")"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"STATE_CHANGED")," - state of an object has changed (sent only when ",Object(l.b)("inlineCode",{parentName:"li"},"notifyStateChanges = true"),")"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"FLAG_CHANGED")," - flag of an object has changed (sent only when ",Object(l.b)("inlineCode",{parentName:"li"},"notifyFlagChanges = true"),")"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"TAG_ADDED")," - tag was added to an object (sent only when ",Object(l.b)("inlineCode",{parentName:"li"},"notifyTagChanges = true"),")"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"TAG_REMOVED")," - tag was removed from an object (sent only when ",Object(l.b)("inlineCode",{parentName:"li"},"notifyTagChanges = true"),")"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"SCENE_CLEAR")," - the whole scene was erased ")),Object(l.b)("h4",{id:"example-collect-new-objects-by-messaging-pattern"},"Example: Collect new objects by messaging pattern"),Object(l.b)("pre",null,Object(l.b)("code",Object(a.a)({parentName:"pre"},{className:"language-typescript"}),"\nclass TreeCollector extends ECS.Component {\n\n trees: ECS.Container[] = [];\n\n onInit() {\n this.subscribe('OBJECT_ADDED');\n }\n\n onMessage(msg: ECS.Message) {\n if (msg.action === 'OBJECT_ADDED' && msg.gameObject.hasTag('TREE')) {\n trees.push(msg.gameObject);\n }\n }\n}\n\n")),Object(l.b)("h2",{id:"built-in-components-and-tools"},"Built-in components and tools"),Object(l.b)("h3",{id:"builder"},"Builder"),Object(l.b)("ul",null,Object(l.b)("li",{parentName:"ul"},"a versatile builder for all types of game objects")),Object(l.b)("div",{className:o.a.figure},Object(l.b)("img",{src:Object(b.a)("img/docs/pixi-ecs/class_builder.svg")})),Object(l.b)("ul",null,Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"anchor()")," - set an anchor"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"virtualAnchor()")," - sets an anchor only virtually to calculate positions"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"relativePos()")," - relative position on the screen within ",Object(l.b)("inlineCode",{parentName:"li"},"[0, 1]")," range"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"localPos()")," - local position"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"globalPos()")," - global position"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"scale()")," - local scale"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"withAttribute()")," - adds an attribute"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"withComponent()")," - adds a component"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"withFlag()")," - adds a flag"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"withState()")," - adds a state"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"withTag()")," - adds a tag"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"withParent()")," - sets a parent"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"withChild()")," - sets a child Builder"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"withName()")," - sets a name"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"asContainer()")," - sets the target object as a container "),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"asGraphics()")," - sets the target object as graphics"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"asXYZ()")," - sets the target object as XYZ (anything from PIXI object collection)"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"buildInto()")," - puts the data into an existing object"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"build()")," - builds a new object"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"clear()")," - clears data")),Object(l.b)("pre",null,Object(l.b)("code",Object(a.a)({parentName:"pre"},{className:"language-typescript"}),"new ECS.Builder(scene)\n .relativePos(0.5, 0.92)\n .anchor(0.5, 1)\n .withAttribute(Attributes.RANGE, 25)\n .withFlag(FLAG_COLLIDABLE)\n .withFlag(FLAG_RANGE)\n .withState(STATE_IDLE)\n .withComponent(new TowerComponent())\n .withComponent(new AimControlComponent())\n .withComponent(new ProjectileSpawner())\n .withName('tower')\n .asSprite(PIXI.Texture.from(Assets.TEX_TOWER))\n .withParent(rootObject)\n.build();\n")),Object(l.b)("h3",{id:"chain-component"},"Chain Component"),Object(l.b)("ul",null,Object(l.b)("li",{parentName:"ul"},"very powerful implementation of chain-of-commands"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("strong",{parentName:"li"},"every action is bound to the game update loop")," - the component udpates it inner state and invokes commands only when it's its turn")),Object(l.b)("div",{className:o.a.figure},Object(l.b)("img",{src:Object(b.a)("img/docs/pixi-ecs/class_chain_component.svg")})),Object(l.b)("pre",null,Object(l.b)("code",Object(a.a)({parentName:"pre"},{className:"language-typescript"}),"// displays a sequence of fancy rotating texts whilst in the bonus mode\nthis.owner.addComponent(new ChainComponent()\n .beginWhile(() => this.gameModel.mode === BONUS_LEVEL)\n .beginRepeat(4)\n .waitFor(() => new RotationAnimation(0,360))\n .waitFor(() => new TranslateAnimation(0,0,2,2))\n .call(() => textComponent.displayMessage('BONUS 100 POINTS!!!'))\n .call(() => soundComponent.playSound('bonus'))\n .endRepeat()\n .endWhile()\n .execute(() => viewComponent.removeAllTexts()));\n \n// changes background music every 20 seconds\nthis.owner.addComponent(new ChainComponent()\n .waitForMessage('GAME_STARTED')\n .beginWhile(() => this.scene.stage.hasFlag(GAME_RUNNING))\n .waitTime(20000)\n .execute(() => this.changeBackgroundMusic())\n .endWhile()\n")),Object(l.b)("h3",{id:"functional-component"},"Functional component"),Object(l.b)("ul",null,Object(l.b)("li",{parentName:"ul"},"a generic component that serves as a wrapper for simple functions")),Object(l.b)("div",{className:o.a.figure},Object(l.b)("img",{src:Object(b.a)("img/docs/pixi-ecs/class_func_component.svg")})),Object(l.b)("pre",null,Object(l.b)("code",Object(a.a)({parentName:"pre"},{className:"language-typescript"}),"new ECS.FuncComponent('view')\n .setFixedFrequency(0.1) // 1 update per 10 seconds\n .doOnMessage('UNIT_EXPLODED', (cmp, msg) => cmp.playSound(Sounds.EXPLOSION))\n .doOnMessage('UNIT_SPAWNED', (cmp, msg) => cmp.displayWarning(Warnings.UNIT_RESPAWNED))\n .doOnFixedUpdate((cmp, delta, absolute) => cmp.displayCurrentState())\n")),Object(l.b)("h3",{id:"key-input-component"},"Key-Input Component"),Object(l.b)("ul",null,Object(l.b)("li",{parentName:"ul"},"a simple keyboard handled that only stores pressed keys"),Object(l.b)("li",{parentName:"ul"},"doesn't send any messages, it has to be polled manually")),Object(l.b)("pre",null,Object(l.b)("code",Object(a.a)({parentName:"pre"},{className:"language-typescript"}),"// Factory.ts\ninitGame(scene: ECS.Scene) {\n ...\n // here we need to add the KeyInputComponent globally\n scene.addGlobalComponent(new KeyInputComponent());\n ...\n}\n\n// CannonInputController.ts\nexport class CannonInputController extends CannonController {\n\nonUpdate(delta: number, absolute: number) {\n // assuming that we added this component to the stage\n let cmp = this.scene\n .findGlobalComponentByName(ECS.KeyInputComponent.name);\n \n if (cmp.isKeyPressed(ECS.Keys.KEY_LEFT)) {\n this.turnLeft();\n }\n \n if (cmp.isKeyPressed(ECS.Keys.KEY_RIGHT)) {\n this.turnRight();\n }\n }\n}\n")),Object(l.b)("h3",{id:"pointer-input-component"},"Pointer-Input Component"),Object(l.b)("ul",null,Object(l.b)("li",{parentName:"ul"},"a global pointer handler"),Object(l.b)("li",{parentName:"ul"},"PIXI has a built-in support for mouse events; this component handles mouse/pointer events for the canvas as a whole"),Object(l.b)("li",{parentName:"ul"},"unlike ",Object(l.b)("inlineCode",{parentName:"li"},"Key-Input Component"),", this one is using messaging pattern to notify the observers"),Object(l.b)("li",{parentName:"ul"},"the component handles both a mouse and a pointer"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("strong",{parentName:"li"},"config"),Object(l.b)("ul",{parentName:"li"},Object(l.b)("li",{parentName:"ul"},"you need to explicitly configure which events should be captured"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"handleClick")," will capture down/release actions")))),Object(l.b)("pre",null,Object(l.b)("code",Object(a.a)({parentName:"pre"},{className:"language-typescript"}),"// add component\nobj.addComponent(new ECS.PointerInputComponent( {\n handleClick: false,\n handlePointerDown: true,\n handlePointerOver: true,\n handlePointerRelease: true, \n}));\n\n")),Object(l.b)("ul",null,Object(l.b)("li",{parentName:"ul"},"then, you can subscribe for following messages (you can find the enum in ",Object(l.b)("inlineCode",{parentName:"li"},"ECS.PointerMessages"),"):",Object(l.b)("ul",{parentName:"li"},Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"pointer-tap")),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"pointer-down")),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"pointer-over")),Object(l.b)("li",{parentName:"ul"},Object(l.b)("inlineCode",{parentName:"li"},"pointer-release"))))),Object(l.b)("h3",{id:"virtual-gamepad-component"},"Virtual-Gamepad Component"),Object(l.b)("ul",null,Object(l.b)("li",{parentName:"ul"},"a simple gamepad that extends ",Object(l.b)("inlineCode",{parentName:"li"},"KeyInputComponent")," and translates clicks to keys"),Object(l.b)("li",{parentName:"ul"},"if you replace your ",Object(l.b)("inlineCode",{parentName:"li"},"KeyInputComponent")," with ",Object(l.b)("inlineCode",{parentName:"li"},"VirtualGamepadComponent"),", your game shouldn't notice the difference"),Object(l.b)("li",{parentName:"ul"},Object(l.b)("strong",{parentName:"li"},"config"),Object(l.b)("ul",{parentName:"li"},Object(l.b)("li",{parentName:"ul"},"you need to provide a mapper to the keys"),Object(l.b)("li",{parentName:"ul"},"if you omit certain keys, respective buttons will not render")))),Object(l.b)("pre",null,Object(l.b)("code",Object(a.a)({parentName:"pre"},{className:"language-typescript"})," this.engine.scene.addGlobalComponent(new ECS.VirtualGamepadComponent({\n KEY_UP: ECS.Keys.KEY_UP,\n KEY_DOWN: ECS.Keys.KEY_DOWN,\n KEY_LEFT: ECS.Keys.KEY_LEFT,\n KEY_RIGHT: ECS.Keys.KEY_RIGHT,\n KEY_A: ECS.Keys.KEY_SPACE,\n KEY_B: ECS.Keys.KEY_ENTER,\n KEY_X: ECS.Keys.KEY_ALT,\n KEY_Y: ECS.Keys.KEY_SHIFT\n }));\n")),Object(l.b)("ul",null,Object(l.b)("li",{parentName:"ul"},"this being configured, the scene will contain a gamepad rendered on the top")),Object(l.b)("div",{className:o.a.figure},Object(l.b)("img",{src:Object(b.a)("img/docs/pixi-ecs/virtual_gamepad.jpg")})),Object(l.b)("h3",{id:"vector"},"Vector"),Object(l.b)("ul",null,Object(l.b)("li",{parentName:"ul"},"helper class for vectors")),Object(l.b)("div",{className:o.a.figure},Object(l.b)("img",{src:Object(b.a)("img/docs/pixi-ecs/class_vector.svg")})),Object(l.b)("h3",{id:"responsive-mode"},"Responsive mode"),Object(l.b)("ul",null,Object(l.b)("li",{parentName:"ul"},"if you want your game render in full-screen mode, scaling with the browser window, you have 2 options:",Object(l.b)("ul",{parentName:"li"},Object(l.b)("li",{parentName:"ul"},"1) set ",Object(l.b)("inlineCode",{parentName:"li"},"resizeToScreen")," to ",Object(l.b)("inlineCode",{parentName:"li"},"true")," while initializing the engine"),Object(l.b)("li",{parentName:"ul"},"2) add ",Object(l.b)("inlineCode",{parentName:"li"},"?responsive")," query string")))),Object(l.b)("h3",{id:"debug-component"},"Debug Component"),Object(l.b)("ul",null,Object(l.b)("li",{parentName:"ul"},"debug component will attach a debugging panel next to the canvas"),Object(l.b)("li",{parentName:"ul"},"three ways:",Object(l.b)("ul",{parentName:"li"},Object(l.b)("li",{parentName:"ul"},"1) add ",Object(l.b)("inlineCode",{parentName:"li"},"DebugComponent")," to the stage"),Object(l.b)("li",{parentName:"ul"},"2) add ",Object(l.b)("inlineCode",{parentName:"li"},"?debug")," query string"),Object(l.b)("li",{parentName:"ul"},"3) set ",Object(l.b)("inlineCode",{parentName:"li"},"debugEnabled")," to ",Object(l.b)("inlineCode",{parentName:"li"},"true")," while initializing the engine")))),Object(l.b)("div",{className:o.a.figure},Object(l.b)("img",{src:Object(b.a)("img/docs/pixi-ecs/debug_window.jpg")})))}d.isMDXComponent=!0}}]);