3.1.5 • Published 11 months ago

game-platform v3.1.5

Weekly downloads
60
License
-
Repository
-
Last release
11 months ago

Roadmap

Provide some basic SCSS that can be imported\ Add a Game Grid to the common utilities\ Add hit detection against rotated rects/images (currently only leveled rects are supported)\ Create real objects for mouseMoveDataInterface to make the interface easier to document\

Add docs for the canvasAPI as a stand alone

#Changelog

19/12/2021

Release version 3.0.0

  • Refactor(CanvasAPI): Rename to Painter (new Painter())
  • Feature(Painter): Added event hooks into CanvasAPI allowing it to receive an initial canvas

02/08/2021

Release version 2.1.1

  • Update all dependencies to latest

31/07/2021

Release version 2.1.0

  • Refactor(build): Remove JARB and rollup dependency
  • Fix(General): Fix all implicit any issues with typescript
  • Breaking(CanvasAPI): Change function name from drawFn to render when adding a generic shape (canvasAPI.addShape).

31/07/2021

Release version 2.0.0

  • Change build to rollup (Starting migration away from jarb)

14/11/2019

Release version 0.4.0:

  • Added click detection against all layers
  • Clicking on the Canvas will now return an array of objects with ID and layerName
  • Added color param for addCircle()
  • Fixed bugs related to click-hit not working

###29/10/2019 Release version 0.3.1:

  • Moved the RAF in Engine, now RAF will be queued first before an system runs, this will enable systems to cancel the frame ###29/10/2019 Release version 0.3.0:
  • Moved all layerName arguments into the objects for all functions (for functions that accept Objects)
  • Added a drawTextBubble() text function
  • Added click detection(for click and select box) against rect shapes (it was only circles)\
  • Added tests for click detection against rect\
  • onViewMapMove/click and onMinimapMove/click are now optional callbacks\
  • Add hit detection against Images\
  • Add configuration to disable selection box (options.enableSelectBox = false)\
  • Added documentation to how writeBubble works\
  • Updated docs that hit detection only works on 'initial' layer\

###24/10/2019 Release version 0.2.1

  • Added the addArc() method which enables drawing arcs.

###22/10/2019 Release version 0.2.0

  • Added an Engine class to encapsulate rAF loop (start, stop, addSystem).

###17/10/2019 Release version 0.1.2

  • Added the ability to remove a layer (canvasAPI.removeLayer(name))

###03/10/2019 Release version 0.1.1

  • Added onMiniMapClick and onMiniMapView
    ###03/10/2019 Release version 0.1.0
  • Added support for Layers.
  • To use layers:
    • the canvas element must be positioned in a container element.
    • The container element must be positioned absolute with a set height and width
    • The canvas elements must be positioned absolute (To enable layering)

###02/10/2019 Release version 0.0.9

  • Updated JARB to 3.0.6
  • Updated Canvas to 2.6.0 and removed canvas prebuilt.
  • These changes now enable support for node 12.x


###15/02/2019###
Release version 0.0.8

  • Updated JARB to 2.0.0-beta.2

###09/01/2019 Release version 0.0.7

  • Fix ObjectPool.generate(amount) to generate UP TO $amount of free objects

###06/01/2019

  • Updated jarb to 1.0.8

###27/12/2018 Release version 0.0.6

  • Ensure React is not bundled in the dist file
  • Document all exported properties
  • Remove ALL TODOs and REFACTORS

#Features

  • Engine
  • CanvasAPI that can be initialized with 2d ctx
  • (React) Game Canvas (Both Main Map and Mini Map) with click detection on what shape was clicked
  • ECS Entity
  • Utility to loop over entities
  • Object Pool utility to pre-create and manage instances of objects

Usage - Engine

import {Engine} from 'game-platform/dist';
let engine = new Engine();

engine.addSystem((systemArguments) => {
   // run any system you want, order specified by order of insertion  
});

engine.addSystem((systemArguments) => {
   // run any system you want, order specified by order of insertion  
});


let systemArguments = {
  // object that is passed to all systems
  // alternatively it can also be a function that returns the object
  // in case of a function, it's evaluated every frame, so keep it light!
}

engine.run(systemArguments); // runs in a loop
  
engine.stop(); // stops the loop completely

Usage - Game Canvas

import {render} from 'react-dom';
import 'index.scss';

import GameCanvas from 'lib/GameCanvas/GameCanvas';


let gameCanvas = new GameCanvas({
  // The mapHeight/width determine the size of the map,
  // while viewHeight/width determine the size visible on the screen.
  // these are not CSS attributes, but rather canvas html properties
  // The library uses viewHeight for the main view, and mapWidth for the minimap
  mapHeight: 4000, // in pixels
  mapWidth : 4000, // in pixels
  viewHeight : 400, // this is the what you actually see in the canvas
  viewWidth : 400, // this is the what you actually see in the canvas
  selectedBoxColor: 'blue', // the color for the current selection box of the user
  enableSelectBox: true, // defaults to true, can be set to false to disable the click->drag select box
  onViewMapClick : (...args) => {
    let clickDataInterface = {
      // The library only detects hits against circles, rects and images, it ignores all other shapes
      // rects and images are calculated without orientation (rotation)
      // you can implement your own click detection system
      hits: [], // array of shape IDs that were clicked on
      dbClick: true, // BOOL, true or false
      isMouseDown: true, // BOOL, true or false
      // Information about the currently selected area (when you select an area with your mouse)
      // if mouse is not held down(no selection), these numbers will be set to 0
      selectedBox: {
        start: {
          x:10,
          y:0
        },
        end: {
          x:110,
          y:75
        },
        height: 75,
        width: 100
      }
    };
  },
  onViewMapMove : (mouseMoveData) => {
    let mouseMoveDataInterface = {
      dbClick: true, // BOOL, true or false
      isMouseDown: true, // BOOL, true or false
      // Information about the currently selected area (when you select an area with your mouse)
      // if mouse is not held down(no selection), these numbers will be set to 0
      selectedBox: {
        start: {
          x:10,
          y:0
        },
        end: {
          x:110,
          y:75
        },
        height: 75,
        width: 100
      }
    };
  }
});

let apis = {};
// these functions return React Element instances
// their callback provides a way to access the internal Canvas API
let mainMap = gameCanvas.generateMapCanvas((API) => {
  apis.main = API;
});

let miniMap = gameCanvas.generateMiniMapCanvas((API) => {
  apis.mini = API;
});

// Unfortunate, as we can only expose the APIs once the canvas context exists
// but we also can't have the canvas context until we render


// We render our new canvas react elements with React
render(<div>
  {mainMap}
  {miniMap}
</div>, document.getElementById('app'), () => {
  apis.main.addRect({
    id: 'SomeRect', // Must be Unique, as a Map is used internally
    x: 10,
    y: 15,
    width: 20,
    height: 35,
    strokeStyle: 'blue'
  });

  apis.main.addCircle({
    id: 'ExampleID',
    x:50,
    y: 50,
    radius: 15,
    strokeStyle: 'red'
  });

  let img = new Image;
  img.src = 'https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png';
  img.onload = () => {
    apis.main.drawImage({
      id : 'my-image',
      image:img, // the image to display
      x: 100, y: 100, // pos for x,y..
      height: 100, width: 100,
      cropStartX:0, cropStartY:0, cropSizeX:img.width, cropSizeY:img.height,
      rotation : 0.2 // in radians
    });
  };
  
  
  apis.main.drawTextBubble({
    id: 'bubbleTextExampleID',
    text: 'It is dangerous to go alone! \ntake this!',
    backgroundColor: 'green',
    borderColor:'orange',
    borderWidth: 3,
    fontColor: 'purple',
    x: 200,
    y: 200,
    height:0, // the minimum value is the text value within
    width:0, // the minimum value is the text value within
    fontSize: 16
  });

  // in a game, you usually render in a loop, the API supports it by having deterministic draws
  setInterval(() => {
    // Once we have all our shapes in place, we use the internal Painter to draw them
    // Internally this deletes the entire canvas, and re-renders all the shapes.
    apis.main.drawAllShapesInLayer();
    apis.mini.drawAllShapesInLayer();
  }, 16);
});

Usage - ECS

  import Entity from 'lib/ECS/Entity';
  it('Creates a new entity', () => {
    let e = new Entity();
    expect(e.id).not.toBeUndefined();
    expect(e.components).toEqual({});
  });

  it('Adds and removes components', () => {
    let e = new Entity();
    let comp = {name:'test', foo:'bar'};
    e.addComponent(comp);
    expect(e.components.test).toBe(comp);
    e.removeComponent(comp);
    expect(e.components.test).toBeUndefined();
  });

  it('Tests the hasComponent method', () => {
    let e = new Entity();
    let comp1 = {name:'test1', foo:'bar'};
    e.addComponent(comp1);
    let comp2 = {name:'test2', foo:'bar'};
    e.addComponent(comp2);

    expect(e.hasComponents('test1')).toBe(true);
    expect(e.hasComponents(['test1'])).toBe(true);
    expect(e.hasComponents(['test1', 'test2'])).toBe(true);
    expect(e.hasComponents(['anotherComp'])).toBe(false);
    expect(e.hasComponents('anotherComp')).toBe(false);
    expect(e.hasComponents()).toBe(true);
  });

  it('Entity can destroy itself', () => {
    let e = new Entity();
    let comp1 = {name:'test1', foo:'bar'};

    e.addComponent(comp1);
    // always returns a collection
    expect(Entity.getByComps(['test1'])[0]).toBe(e);

    e.destroy();
    expect(Entity.entities[e.id]).toBeUndefined();

    let resp = Entity.getByComps(['test1']);
    expect(resp.length).toBe(0);
  });

Usage - The EntityLoop

  import entityLoop from 'lib/ECS/util/entityLoop';
  import Entity from 'lib/ECS/Entity';

  it ('Loops on Entity arrays', () => {
    let foo = new Entity();

    foo.addComponent({
      name : 'lol'
    });

    let runs = 0;
    let ents = entityLoop(Entity.getByComps('lol'), (ent) => {
      runs++;
      expect(ent).not.toBeUndefined();
      return true;
    });

    expect(ents.length).toBe(1);
    expect(runs).toBe(1);
  });

Usage - The Object Pool

  import ObjectPool from 'lib/ObjectPool/ObjectPool';

  // Define what type of pool you'd like to make
  beforeEach(() => {
    class Foo {
      constructor() {
        this.isAlive = true;
      }
    }
    // if you try to acquire an object when the pool is empty, this will create more instances on the fly
    let incrementWhenEmpty = 100;
    pool = new ObjectPool(Foo, incrementWhenEmpty);
  });

  it('Acquires an object instance', () => {
    pool.generate(100);
    let obj = pool.acquire();
    expect(obj.isAlive).toBe(true);
    expect(pool.stats.free).toBe(99);
  });

  // the pool exposes the following stats
  pool.stats = {
      free: 0,
      used: 0,
      total: 0
    };
3.1.3

11 months ago

3.1.5

11 months ago

3.1.4

11 months ago

3.1.2

1 year ago

3.0.3

1 year ago

3.1.1

1 year ago

3.0.2

1 year ago

3.1.0

1 year ago

3.0.1

2 years ago

3.0.0

2 years ago

2.1.2

3 years ago

2.1.1

3 years ago

2.1.0

3 years ago

2.0.1

3 years ago

2.0.0

3 years ago

1.0.1

4 years ago

1.0.0

4 years ago

1.0.0-beta

4 years ago

0.4.0

4 years ago

0.3.1

4 years ago

0.3.0

4 years ago

0.2.1

5 years ago

0.2.0

5 years ago

0.1.2

5 years ago

0.1.1

5 years ago

0.1.0

5 years ago

0.0.9

5 years ago

0.0.8

5 years ago

0.0.7

5 years ago

0.0.6

5 years ago

0.0.5

5 years ago

0.0.4

5 years ago

0.0.3

5 years ago

0.0.2

5 years ago

0.0.1

5 years ago