Skip to content

Commit

Permalink
Merge pull request #4 from florisdh/dev
Browse files Browse the repository at this point in the history
Version 1.3.0
  • Loading branch information
florisdh authored Sep 12, 2019
2 parents 994ceb3 + a9e3a1a commit 81286aa
Show file tree
Hide file tree
Showing 7 changed files with 164 additions and 31 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,14 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [1.3.0] - 2019-09-12
### Added
- Stopping scenes
- Removing scenes
- Getting active scene name
- Retrieving a list of scene names
- Some code docs

## [1.2.0] - 2019-09-03
### Added
- Seperate build output for ESM to support usage as module
Expand Down
21 changes: 9 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,15 @@ You can use this library through import/require or by loading it straight into y
### Setup
```ts
import {SceneManager} from 'pixi-scenes';
const sceneManager = new SceneManager(myPixiApplication);
const scenes = new SceneManager(myPixiApplication);
```

### Using scenes
```ts
sceneManager.add('splash', new SplashScene());
sceneManager.add('menu', new MenuScene());
sceneManager.add('gameover', new GameoverScene());
sceneManager.start('splash');
scenes.add('splash', new SplashScene());
scenes.add('menu', new MenuScene());
scenes.add('gameover', new GameoverScene());
scenes.start('splash');
```

### Example scene
Expand All @@ -50,7 +50,7 @@ export default class SplashScene extends Scene {
public start(): void {
this.header.angle = 0;
setTimeout(() => {
this.scenes.start('mainMenu');
this.scenes.start('menu');
}, 5000);
}

Expand All @@ -60,16 +60,13 @@ export default class SplashScene extends Scene {
}
```


## About
Please let me know if you're using it or have some feedback. :)
Splitting your codebase into multiple states/scenes in a common practice in the app/game world and can now easilly be done using this plugin for *PIXI.js*.

## TODO
- Removing scenes
- Getting active scene name
- Retrieving list of scenes
- Destroy function
- Subscenes structure
- Event system on manager
- Document code
- Resize integration
- Improve readme
- Add documentation pages
Expand Down
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "pixi-scenes",
"version": "1.2.0",
"version": "1.3.0",
"description": "Managing multiple scenes within your pixi application.",
"main": "build/pixi-scenes.min.js",
"module": "build/esm/index.js",
Expand Down
31 changes: 31 additions & 0 deletions src/scene.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,21 @@ import * as PIXI from 'pixi.js';
import SceneManager from "./sceneManager";
import IScene from "./iScene";

/**
* Base scene class which should be extended and used to your own likings.
*/
export default class Scene extends PIXI.Container implements IScene {

/**
* Reference to the pixi application this scene has been added to.
* This will automatically be set by the SceneManager after it has been added.
*/
public app: PIXI.Application|null;

/**
* Reference to the SceneManager this Scene has been added to.
* This will automatically be set by the SceneManager after it has been added.
*/
public scenes: SceneManager|null;

constructor() {
Expand All @@ -13,8 +25,27 @@ export default class Scene extends PIXI.Container implements IScene {
this.scenes = null;
}

/**
* Called directly after this Scene is added to a SceneManager.
* You should create all of your elements for this scene here.
*/
public init(): void {}

/**
* Called after this Scene is started from the SceneManager.
* This means that this Scene is now the active scene in the SceneManager and will be rendered.
*/
public start(): void {}

/**
* Called after this Scene is stopped from the SceneManager.
* The Scene is not the active scene anymore, nor will it be rendered.
*/
public stop(): void {}

/**
* Called with every PIXI update tick while this Scene is the active scene in the SceneManager.
* @param {number} delta Elapsed time since the last update in milliseconds.
*/
public update(delta: number): void {}
}
90 changes: 79 additions & 11 deletions src/sceneManager.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
import * as PIXI from 'pixi.js';
import IScene from "./iScene";

/**
* Manages numerous Scenes and makes sure they function as they should.
* @param {PIXI.Application} app The pixi application the scenes will be bound to.
*/
export default class SceneManager {

private app: PIXI.Application;
private scenes: {[name: string]: IScene};
private current: string|null;
Expand All @@ -10,7 +15,6 @@ export default class SceneManager {
this.app = app;
this.scenes = {};
this.current = null;
// Listen for animate update
app.ticker.add(this.update.bind(this));
}

Expand All @@ -21,8 +25,15 @@ export default class SceneManager {
}
}

/**
* Adds the scene instance to function under this manager.
* * If the name is already taken, it won't be added.
* @param {string} name The name you give to this scene instance.
* @param {Scene} scene Instance of the scene you want to add.
*/
public add(name: string, scene: IScene): void {
if (this.contains(name)) {
// TODO: Remove from previous manager if set
if (!name || this.contains(name)) {
return;
}
this.scenes[name] = scene;
Expand All @@ -31,31 +42,88 @@ export default class SceneManager {
scene.init();
}

/**
* Removed a scene from this manager.
* * If this scene is currently active, it will be stopped first.
* @param {string} name Name given to this scene instance.
*/
public remove(name: string): boolean {
if (!name || !this.contains(name)) {
return false;
}
if (this.current === name) {
this.stop();
}
const scene = this.scenes[name];
scene.app = null;
scene.scenes = null;
delete this.scenes[name];
return true;
}

/**
* Checks there is a scene with this name in this manager.
* @param {string} name
* @returns {boolean}
*/
public contains(name: string): boolean {
return !!this.scenes[name];
return name in this.scenes;
}

/**
* Starts a scene and set's it to be the active scene of this manager.
* * Stops the previous active scene first if defined.
* @param {string} name
*/
public start(name: string): void {
if (!this.contains(name) || name === this.current) {
return;
}

// Stop current
let active: IScene|null = this.active;
if (active) {
active.stop();
this.app.stage.removeChild(active);
}

this.stop();

// Start new
this.current = name;
if (active = this.active) {
const active = this.active;
if (active) {
this.app.stage.addChild(active);
active.start();
}
}

/**
* Stops the scene and unsets it as the active scene in this manager.
*/
public stop(): void {
let active: IScene|null = this.active;
if (active) {
this.current = null;
active.stop();
this.app.stage.removeChild(active);
}
}

/**
* Getting the active scene in this manager.
* @returns {Scene|null}
*/
public get active(): IScene|null {
return this.current ? this.scenes[this.current] : null;
}

/**
* Getting the name of the active scene in this manager.
* @returns {Scene|null}
*/
public get activeName(): string|null {
return this.current;
}

/**
* Getting the names of all the scenes in this manager.
* @returns {string[]}
*/
public get sceneNames(): string[] {
return Object.keys(this.scenes);
}
}
41 changes: 35 additions & 6 deletions test/sceneManager.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,20 +26,49 @@ describe('SceneManager', () => {
expect(manager['app']).toBe(app);
});

const scene: Scene = new Scene();
const scene: Scene = new Scene(),
sceneName: string = 'test';

it('should not contain scene before adding', () => {
expect(manager.contains(sceneName)).toBe(false);
});

it('contains scene after adding', () => {
manager.add('test', scene);
expect(manager.contains('test')).toBe(true);
manager.add(sceneName, scene);
expect(manager.contains(sceneName)).toBe(true);
});

it('keep track of active scene', () => {
manager.start('test');
it('allows starting scenes', () => {
manager.start(sceneName);
expect(manager.active).toBe(scene);
expect(manager.activeName).toBe(sceneName);
});

it('does not overwrite scenes', () => {
manager.add('test', new Scene());
manager.add(sceneName, new Scene());
expect(manager.active).toBe(scene);
});

it('allows stopping scenes', () => {
manager.stop();
expect(manager.active).toBeNull();
});

it('list of scenes is correct', () => {
expect(manager.sceneNames).toEqual([sceneName]);
});

it('allows removing scenes', () => {
manager.remove(sceneName);
expect(manager.active).toBeNull();
expect(scene.app).toBeNull();
expect(scene.scenes).toBeNull();
});

it('removing active scene should clear active', () => {
manager.add(sceneName, scene);
manager.start(sceneName);
manager.remove(sceneName);
expect(manager.active).toBeNull();
});
});

0 comments on commit 81286aa

Please sign in to comment.